Linux设备驱动入门-USB设备驱动
Linux设备驱动入门----USB设备驱动
/**************************************** * USB主机与设备驱动 * 主机侧:由底到高:USB主机控制器硬件--> * USB主机控制器驱动--> USB核心层 --> USB * 设备驱动层 * 设备侧:UDC驱动程序、Gadget API和Gadget * 驱动程序 * 逻辑组织:设备(1) <--> 配置(n) * 配置(1) <--> 接口(n) * 端点(0/n) <--> 接口(1) <--> 设置(n) * USB主机控制驱动:控制插入其中的USB设备 * USB设备驱动:控制USB设备如何与主机通信 * 标准描述符: * 设备描述符 usb_device_descriptor * 配置描述符 usb_config_descriptor * 接口描述符 usb_interface_descriptor * 端点描述符 usb_endpoint_descriptor * 字符串描述符 usb_string_descriptor * 几个重要的数据结构:hc_driver usb_hcd * ohci_hcd usb_driver urb(请求块) * urb的典型生命周期: * (1) 被一个USB设备驱动创建 * (2) 初始化,被安排给一个特定USB设备的特定端点 * (3) 被USB设备驱动提交给USB核心 * (4) 提交与USB核心指定的USB主机控制器驱动 * (5) 被USB主机控制器处理,进行一次到USB设备的传送 * (6) 当urb完成,USB主机控制器驱动通知USB设备驱动 * * probe() 和 disconnect() 这两个函数比较重要 * ********************************************/ /* * USB 设备驱动实例:USB串口驱动(部分) * */ /* Driver structure we register with the USB core */ static struct usb_driver usb_serial_driver = { .name = "usbserial", .probe = usb_serial_probe, .disconnect = usb_serial_disconnect, .suspend = usb_serial_suspend, .resume = usb_serial_resume, .no_dynamic_id = 1, } /* USB串口设备驱动的模块加载函数 */ static int __init usb_serial_init(void) { int i; int result; /* 分配tty_driver */ usb_serial_tty_driver = alloc_tty_driver(SERIAL_TTY_MINORS); if(usb_serial_tty_driver) { return -ENOMEM; } /* 初始化全局变量 */ for(i = 0; i < SERIAL_TTY_MINORS; ++i) serial_table[i] = NULL; /* 注册总线 */ result = bus_register(&usb_serial_bus_type); if(result) { printk(KERN_ERR "usb-serial: %s - registering bus driver failed\n", __func__); goto exit_bus; } /* 初始化tty_driver */ usb_serial_tty_driver->owner = THIS_MODULE; usb_serial_tty_driver->driver_name = "usbserial"; usb_serial_tty_driver->name = "ttyUSB"; usb_serial_tty_driver->major = SERIAL_TTY_MAJOR; usb_serial_tty_driver->minor_start = 0; usb_serial_tty_driver->type = TTY_DRIVER_TYPE_SERIAL; usb_serial_tty_driver->subtype = SERIAL_TYPE_NORMAL; usb_serial_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; usb_serial_tty_driver->init_termios = tty_std_termios; usb_serial_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; usb_serial_tty_driver->init_termios.c_ispeed = 9600; usb_serial_tty_driver->init_termios.c_ospeed = 9600; tty_set_operations(usb_serial_tty_driver, &serial_ops); /* 注册tty_driver */ result = tty_register_driver(usb_serial_tty_driver); if (result) { printk(KERN_ERR "usb-serial: %s - tty_register_driver failed\n", __func__); goto exit_reg_driver; } /* 注册USB驱动 */ result = usb_register(&usb_serial_driver); if (result < 0) { printk(KERN_ERR "usb-serial: %s - usb_register failed\n", __func__); goto exit_tty; } /* register the generic driver, if we should */ result = usb_serial_generic_register(debug); if (result < 0) { printk(KERN_ERR "usb-serial: %s - registering generic " "driver failed\n", __func__); goto exit_generic; } printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n"); return result; exit_generic: usb_deregister(&usb_serial_driver); exit_tty: tty_unregister_driver(usb_serial_tty_driver); exit_reg_driver: bus_unregister(&usb_serial_bus_type); exit_bus: printk(KERN_ERR "usb-serial: %s - returning with error %d\n", __func__, result); put_tty_driver(usb_serial_tty_driver); return result; } static void __exit usb_serial_exit(void) { usb_serial_console_exit(); usb_serial_generic_deregister(); usb_deregister(&usb_serial_driver); //注销usb_driver tty_unregister_driver(usb_serial_tty_driver); // 注销tty_driver put_tty_driver(usb_serial_tty_driver); // 减少引用计数 bus_unregister(&usb_serial_bus_type); // 注销bus } /* * 在usb_driver的探测成员函数usb_serial_probe()中,将初始化USB端点 * 等信息,并通过usb_set_intfdata()设置接口私有数据,它也将初始化urb。 * */ static const struct tty_operations serial_ops = { .open = serial_open, .close = serial_close, .write = serial_write, .hangup = serial_hangup, .write_room = serial_write_room, .ioctl = serial_ioctl, .set_termios = serial_set_termios, .throttle = serial_throttle, .unthrottle = serial_unthrottle, .break_ctl = serial_break, .chars_in_buffer = serial_chars_in_buffer, .tiocmget = serial_tiocmget, .tiocmset = serial_tiocmset, .get_icount = serial_get_icount, .cleanup = serial_cleanup, .install = serial_install, .proc_fops = &serial_proc_fops, }; /////////////////////////////////////////// /* * USB 设备驱动实例:USB键盘驱动(部分) * 主要包含两部分: * usb_driver的成员函数 * 输入设备的打开、关闭、中断处理等函数 * */ //////////////////////////////////////////// /* * 在USB键盘设备驱动的模块加载和卸载函数中 * ,将分别注册和注销对于USB键盘的usb_driver * 结构体usb_kbd_driver */ static int __init usb_kbd_init(void) { int result = usb_register(&usb_kbd_driver); //注册USB设备驱动 if (result == 0) printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" DRIVER_DESC "\n"); return result; } static void __exit usb_kbd_exit(void) { usb_deregister(&usb_kbd_driver); } static struct usb_driver usb_kbd_driver = { .name = "usbkbd", .probe = usb_kbd_probe, .disconnect = usb_kbd_disconnect, .id_table = usb_kbd_id_table, }; // 支持的设备列表 static struct usb_device_id usb_kbd_id_table [] = { { USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT, USB_INTERFACE_PROTOCOL_KEYBOARD) }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE (usb, usb_kbd_id_table); /* * 在usb_driver的探测函数中,将进行input设备的初始化和注册。 * usb键盘要使用的中断urb和控制urb的初始化,并设置接口的私有数据。 */ static int usb_kbd_probe(struct usb_interface *iface, const struct usb_device_id *id) { ... } /* 设置接口私有数据为NULL、终止已提交的urb并注销输入设备。*/ static void usb_kbd_disconnect(struct usb_interface *intf) { ... } /* * 键盘中断处理函数中,也就是urb的完成函数中,将会通过input_report_key() * 报告按键事件,通过input_sync()报告同步事件,并发起一次新的控制urb传输。 */ static void usb_kbd_irq(struct urb *urb) { struct usb_kbd *kbd = urb->context; int i; switch (urb->status) { case 0: /* success */ break; case -ECONNRESET: /* unlink */ case -ENOENT: case -ESHUTDOWN: return; /* -EPIPE: should clear the halt */ default: /* error */ goto resubmit; } for (i = 0; i < 8; i++) { input_report_key(kbd->dev, usb_kbd_keycode[i + 224], (kbd->new[0] >> i) & 1); } for (i = 2; i < 8; i++) { if (kbd->old[i] > 3 && memscan(kbd->new + 2, kbd->old[i], 6) == kbd->new + 8) { if (usb_kbd_keycode[kbd->old[i]]) { input_report_key(kbd->dev, usb_kbd_keycode[kbd->old[i]], 0); } else { dev_info(&urb->dev->dev, "Unknown key (scancode %#x) released.\n", kbd->old[i]); } } if (kbd->new[i] > 3 && memscan(kbd->old + 2, kbd->new[i], 6) == kbd->old + 8) { if (usb_kbd_keycode[kbd->new[i]]) input_report_key(kbd->dev, usb_kbd_keycode[kbd->new[i]], 1); else dev_info(&urb->dev->dev, "Unknown key (scancode %#x) released.\n", kbd->new[i]); } } input_sync(kbd->dev); memcpy(kbd->old, kbd->new, 8); resubmit: i = usb_submit_urb (urb, GFP_ATOMIC); if (i) { err_hid ("can't resubmit intr, %s-%s/input0, status %d", kbd->usbdev->bus->bus_name, kbd->usbdev->devpath, i); } }
小结:
这个只能了解usb设备驱动的大概,要真正深刻理解USB驱动,需要对USB源码进行分析和对相关协议的理解。这里稍微总结一下:
USB驱动分为USB主机驱动和USB设备驱动,如果系统的USB主机控制器符合OHCI等标准,这主机驱动的绝大部分工作都可以沿用通用的代码。
对于一个USB设备而言,它至少具备两重身份:首先它是“USB”的,其次它是“自己”的。USB设备是“USB”的,指它挂接在USB总线上,其必须完成usb_driver的初始化和注册;USB设备是“自己”的,意味着本身可能是一个字符设备、tty设备、网路设备等,因此,USB设备驱动中必须实现符合相应框架的代码。
USB设备驱动的自身设备驱动部分的读写等操作流程有其特殊性,即以URB来贯穿始终,一个USB的生命周期通常包含创建、初始化、提交,和被USB核心及USB主机传递及完成后回调函数被调用的过程,当然,在URB被驱动提交后,也可以被取消。此外,简单的控制及批量消息传递可以用同步的usb_bulk_msg()、usb_control_msg()函数完成。