1. usb hub
以前不太了解hub,一直认为它只是一个可选设备,和网络集线器类似,有它不多,少它也可;
太低调了,以至于都不晓得它长在哪里,今天在网上百度了一下,发现它是window和linux系统上一个必备的设备;是EHCI/UHCI的私生子,一直躺在妈妈的怀里;
设备部分:<usb_device_type 篇>
hub是usb控制器的私生子,那么他就在hcd.c中生成:
usb_add_hcd()
{
...
rhdev = usb_alloc_dev(NULL, &hcd->self, 0);
hcd->self.root_hub = rhdev;
register_root_hub(hcd);//完成设备添加了;
...
}
下面中的介绍usb_alloc_dev和register_root_hub
函数一
点击(此处)折叠或打开
- /**
- * usb_add_hcd - finish generic HCD structure initialization and register
- * @hcd: the usb_hcd structure to initialize
- * @irqnum: Interrupt line to allocate
- * @irqflags: Interrupt type flags
- *
- * Finish the remaining parts of generic HCD initialization: allocate the
- * buffers of consistent memory, register the bus, request the IRQ line,
- * and call the driver's reset() and start() routines.
- */
- int usb_add_hcd(struct usb_hcd *hcd,
- unsigned int irqnum, unsigned long irqflags)
- {
- int retval;
- struct usb_device *rhdev;
- dev_info(hcd->self.controller, "%s\n", hcd->product_desc);
- hcd->authorized_default = hcd->wireless? 0 : 1;
- set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
- /* HC is in reset state, but accessible. Now do the one-time init,
- * bottom up so that hcds can customize the root hubs before khubd
- * starts talking to them. (Note, bus id is assigned early too.)
- */
- if ((retval = hcd_buffer_create(hcd)) != 0) {
- dev_dbg(hcd->self.controller, "pool alloc failed\n");
- return retval;
- }
- if ((retval = usb_register_bus(&hcd->self)) < 0)
- goto err_register_bus;
- if ((rhdev = usb_alloc_dev(NULL, &hcd->self, 0)) == NULL) {
- dev_err(hcd->self.controller, "unable to allocate root hub\n");
- retval = -ENOMEM;
- goto err_allocate_root_hub;
- }
- switch (hcd->driver->flags & HCD_MASK) {
- case HCD_USB11:
- rhdev->speed = USB_SPEED_FULL;
- break;
- case HCD_USB2:
- rhdev->speed = USB_SPEED_HIGH;
- break;
- case HCD_USB3:
- rhdev->speed = USB_SPEED_SUPER;
- break;
- default:
- goto err_allocate_root_hub;
- }
- hcd->self.root_hub = rhdev;//设备
- /* wakeup flag init defaults to "everything works" for root hubs,
- * but drivers can override it in reset() if needed, along with
- * recording the overall controller's system wakeup capability.
- */
- device_init_wakeup(&rhdev->dev, 1);
- /* "reset" is misnamed; its role is now one-time init. the controller
- * should already have been reset (and boot firmware kicked off etc).
- */
- //控制器复位:ehci_pci_setup
- if (hcd->driver->reset && (retval = hcd->driver->reset(hcd)) < 0) {
- dev_err(hcd->self.controller, "can't setup\n");
- goto err_hcd_driver_setup;
- }
- /* NOTE: root hub and controller capabilities may not be the same */
- if (device_can_wakeup(hcd->self.controller)
- && device_can_wakeup(&hcd->self.root_hub->dev))
- dev_dbg(hcd->self.controller, "supports USB remote wakeup\n");
- //控制器中断处理接口
- /* enable irqs just before we start the controller */
- if (hcd->driver->irq) {
- /* IRQF_DISABLED doesn't work as advertised when used together
- * with IRQF_SHARED. As usb_hcd_irq() will always disable
- * interrupts we can remove it here.
- */
- if (irqflags & IRQF_SHARED)
- irqflags &= ~IRQF_DISABLED;
- snprintf(hcd->irq_descr, sizeof(hcd->irq_descr), "%s:usb%d",
- hcd->driver->description, hcd->self.busnum);
- if ((retval = request_irq(irqnum, &usb_hcd_irq, irqflags,
- hcd->irq_descr, hcd)) != 0) {
- dev_err(hcd->self.controller,
- "request interrupt %d failed\n", irqnum);
- goto err_request_irq;
- }
- hcd->irq = irqnum;
- dev_info(hcd->self.controller, "irq %d, %s 0x%08llx\n", irqnum,
- (hcd->driver->flags & HCD_MEMORY) ?
- "io mem" : "io base",
- (unsigned long long)hcd->rsrc_start);
- } else {
- hcd->irq = -1;
- if (hcd->rsrc_start)
- dev_info(hcd->self.controller, "%s 0x%08llx\n",
- (hcd->driver->flags & HCD_MEMORY) ?
- "io mem" : "io base",
- (unsigned long long)hcd->rsrc_start);
- }
- //控制器run:ehci_run
- if ((retval = hcd->driver->start(hcd)) < 0) {
- dev_err(hcd->self.controller, "startup error %d\n", retval);
- goto err_hcd_driver_start;
- }
- /* starting here, usbcore will pay attention to this root hub */
- rhdev->bus_mA = min(500u, hcd->power_budget);
- if ((retval = register_root_hub(hcd)) != 0)//设备添加到内核中了;
- goto err_register_root_hub;
- retval = sysfs_create_group(&rhdev->dev.kobj, &usb_bus_attr_group);
- if (retval < 0) {
- printk(KERN_ERR "Cannot register USB bus sysfs attributes: %d\n",
- retval);
- goto error_create_attr_group;
- }
- if (hcd->uses_new_polling && hcd->poll_rh)
- usb_hcd_poll_rh_status(hcd);
- return retval;
- error_create_attr_group:
- mutex_lock(&usb_bus_list_lock);
- usb_disconnect(&hcd->self.root_hub);
- mutex_unlock(&usb_bus_list_lock);
- err_register_root_hub:
- hcd->driver->stop(hcd);
- err_hcd_driver_start:
- if (hcd->irq >= 0)
- free_irq(irqnum, hcd);
- err_request_irq:
- err_hcd_driver_setup:
- hcd->self.root_hub = NULL;
- usb_put_dev(rhdev);
- err_allocate_root_hub:
- usb_deregister_bus(&hcd->self);
- err_register_bus:
- hcd_buffer_destroy(hcd);
- return retval;
- }
函数二
点击(此处)折叠或打开
- /**
- * usb_alloc_dev - usb device constructor (usbcore-internal)
- * @parent: hub to which device is connected; null to allocate a root hub
- * @bus: bus used to access the device
- * @port1: one-based index of port; ignored for root hubs
- * Context: !in_interrupt()
- *
- * Only hub drivers (including virtual root hub drivers for host
- * controllers) should ever call this.
- *
- * This call may not be used in a non-sleeping context.
- */
- struct usb_device *usb_alloc_dev(struct usb_device *parent,
- struct usb_bus *bus, unsigned port1)
- {
- struct usb_device *dev;
- struct usb_hcd *usb_hcd = container_of(bus, struct usb_hcd, self);
- unsigned root_hub = 0;
- //usb设备对象;
- dev = kzalloc(sizeof(*dev), GFP_KERNEL);
- if (!dev)
- return NULL;
- if (!usb_get_hcd(bus_to_hcd(bus))) {
- kfree(dev);
- return NULL;
- }
- /* Root hubs aren't true devices, so don't allocate HCD resources */
- if (usb_hcd->driver->alloc_dev && parent &&
- !usb_hcd->driver->alloc_dev(usb_hcd, dev)) {
- usb_put_hcd(bus_to_hcd(bus));
- kfree(dev);
- return NULL;
- }
- //usb_device_type
- //usb设备的基本属性还是device;
- device_initialize(&dev->dev);
- dev->dev.bus = &usb_bus_type;//所属总线;
- dev->dev.type = &usb_device_type;//usb设备类型,有别于usb_if_device_type;
- dev->dev.groups = usb_device_groups;
- dev->dev.dma_mask = bus->controller->dma_mask;
- set_dev_node(&dev->dev, dev_to_node(bus->controller));
- //USB设备的状态变化;表示已连接上(生来就是在一起的)
- //后面这个状态会一直变化的;
- dev->state = USB_STATE_ATTACHED;
- atomic_set(&dev->urbnum, 0);
- INIT_LIST_HEAD(&dev->ep0.urb_list);
- //初始化端点信息
- dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE;
- dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT;
- /* ep0 maxpacket comes later, from device descriptor */
- //使能控制:ep->enabled = 1;
- usb_enable_endpoint(dev, &dev->ep0, false);
- dev->can_submit = 1;
- /* Save readable and stable topology id, distinguishing devices
- * by location for diagnostics, tools, driver model, etc. The
- * string is a path along hub ports, from the root. Each device's
- * dev->devpath will be stable until USB is re-cabled, and hubs
- * are often labeled with these port numbers. The name isn't
- * as stable: bus->busnum changes easily from modprobe order,
- * cardbus or pci hotplugging, and so on.
- */
- if (unlikely(!parent)) {//hub就是这条路;
- dev->devpath[0] = '0';
- dev->route = 0;
- dev->dev.parent = bus->controller;
- dev_set_name(&dev->dev, "usb%d", bus->busnum);//设备名称usbXX
- root_hub = 1;
- } else {
- /* match any labeling on the hubs; it's one-based */
- if (parent->devpath[0] == '0') {
- snprintf(dev->devpath, sizeof dev->devpath,
- "%d", port1);
- /* Root ports are not counted in route string */
- dev->route = 0;
- } else {
- snprintf(dev->devpath, sizeof dev->devpath,
- "%s.%d", parent->devpath, port1);
- /* Route string assumes hubs have less than 16 ports */
- if (port1 < 15)
- dev->route = parent->route +
- (port1 << ((parent->level - 1)*4));
- else
- dev->route = parent->route +
- (15 << ((parent->level - 1)*4));
- }
- dev->dev.parent = &parent->dev;
- dev_set_name(&dev->dev, "%d-%s", bus->busnum, dev->devpath);
- /* hub driver sets up TT records */
- }
- dev->portnum = port1;
- dev->bus = bus;
- dev->parent = parent;
- INIT_LIST_HEAD(&dev->filelist);
- #ifdef CONFIG_PM
- mutex_init(&dev->pm_mutex);
- INIT_DELAYED_WORK(&dev->autosuspend, usb_autosuspend_work);
- INIT_WORK(&dev->autoresume, usb_autoresume_work);
- dev->autosuspend_delay = usb_autosuspend_delay * HZ;
- dev->connect_time = jiffies;
- dev->active_duration = -jiffies;
- #endif
- if (root_hub) /* Root hub always ok [and always wired] */
- dev->authorized = 1;//hub 默认;
- else {
- dev->authorized = usb_hcd->authorized_default;
- dev->wusb = usb_bus_is_wusb(bus)? 1 : 0;
- }
- return dev;
- }
函数三
点击(此处)折叠或打开
- /**
- * register_root_hub - called by usb_add_hcd() to register a root hub
- * @hcd: host controller for this root hub
- *
- * This function registers the root hub with the USB subsystem. It sets up
- * the device properly in the device tree and then calls usb_new_device()
- * to register the usb device. It also assigns the root hub's USB address
- * (always 1).
- */
- static int register_root_hub(struct usb_hcd *hcd)
- {
- struct device *parent_dev = hcd->self.controller;
- struct usb_device *usb_dev = hcd->self.root_hub;
- const int devnum = 1;
- int retval;
- usb_dev->devnum = devnum;
- usb_dev->bus->devnum_next = devnum + 1;
- memset (&usb_dev->bus->devmap.devicemap, 0,
- sizeof usb_dev->bus->devmap.devicemap);
- set_bit (devnum, usb_dev->bus->devmap.devicemap);
- //作为usb设备状态,第二种:USB_STATE_ADDRESS
- usb_set_device_state(usb_dev, USB_STATE_ADDRESS);
- mutex_lock(&usb_bus_list_lock);
- usb_dev->ep0.desc.wMaxPacketSize = cpu_to_le16(64);
- //usb_get_descriptor--usb_control_msg--usb_start_wait_urb--usb_hcd_submit_urb--rh_urb_enqueue
- //其实只知道一点就好了,roothub的描述符都是不需要控制器帮忙的,
- //自带的;hub.c中有列出来;
- retval = usb_get_device_descriptor(usb_dev, USB_DT_DEVICE_SIZE);
- if (retval != sizeof usb_dev->descriptor) {
- mutex_unlock(&usb_bus_list_lock);
- dev_dbg (parent_dev, "can't read %s device descriptor %d\n",
- dev_name(&usb_dev->dev), retval);
- return (retval < 0) ? retval : -EMSGSIZE;
- }
- //这里面就是很熟悉的代码了
- //device_add(dev);
- retval = usb_new_device (usb_dev);
- if (retval) {
- dev_err (parent_dev, "can't register root hub for %s, %d\n",
- dev_name(&usb_dev->dev), retval);
- }
- mutex_unlock(&usb_bus_list_lock);
- if (retval == 0) {
- spin_lock_irq (&hcd_root_hub_lock);
- hcd->rh_registered = 1;
- spin_unlock_irq (&hcd_root_hub_lock);
- /* Did the HC die before the root hub was registered? */
- if (hcd->state == HC_STATE_HALT)
- usb_hc_died (hcd); /* This time clean up */
- }
- return retval;
- }
hub的设备出生后,就要找驱动;哪里找呢?看关键字<usb_device_type,for_devices>
看代码很多后,才发现,所谓usb驱动分为接口驱动和设备驱动,大多时候,网友口口相传驱动都指定为接口驱动;而我们这里讲的是设备驱动,据我对代码的查看,在usb hub驱动时找到一例;至于其他地方,我们不要去理会了,少则得,多则惑;
后来,我界定,这种驱动还只是属于设备创建的一部分,它只是创建接口设备;
代码的起始点:retval = usb_register_device_driver(&usb_generic_driver, THIS_MODULE);
点击(此处)折叠或打开
- struct usb_device_driver usb_generic_driver = {
- .name = "usb",
- .probe = generic_probe,
- .disconnect = generic_disconnect,
- #ifdef CONFIG_PM
- .suspend = generic_suspend,
- .resume = generic_resume,
- #endif
- .supports_autosuspend = 1,
- }
点击(此处)折叠或打开
- /**
- * usb_register_device_driver - register a USB device (not interface) driver
- * @new_udriver: USB operations for the device driver
- * @owner: module owner of this driver.
- *
- * Registers a USB device driver with the USB core. The list of
- * unattached devices will be rescanned whenever a new driver is
- * added, allowing the new driver to attach to any recognized devices.
- * Returns a negative error code on failure and 0 on success.
- */
- int usb_register_device_driver(struct usb_device_driver *new_udriver,
- struct module *owner)
- {
- int retval = 0;
- if (usb_disabled())
- return -ENODEV;
- //对devices;主要是Mark一下,引起注意;
- //在总线匹配中,区分接口设备和usb设备<usb_device_type,>;
- new_udriver->drvwrap.for_devices = 1;
- new_udriver->drvwrap.driver.name = (char *) new_udriver->name;
- new_udriver->drvwrap.driver.bus = &usb_bus_type;//所属总线;
- new_udriver->drvwrap.driver.probe = usb_probe_device;
- new_udriver->drvwrap.driver.remove = usb_unbind_device;
- new_udriver->drvwrap.driver.owner = owner;
- //通用设备驱动的注册
- retval = driver_register(&new_udriver->drvwrap.driver);
- if (!retval) {
- pr_info("%s: registered new device driver %s\n",
- usbcore_name, new_udriver->name);
- usbfs_update_special();
- } else {
- printk(KERN_ERR "%s: error %d registering device "
- " driver %s\n",
- usbcore_name, retval, new_udriver->name);
- }
- return retval;
- }
上面就是usb设备类型的驱动,只要是满足{usb_device_type,for_devices==1}的设备,都会来找他配对;然后生出{usb_if_device_type,for_devices==0}这样的设备;
usb_device_type,usb_if_device_type为usb设备的类型,用来总线匹配驱动。for_devices是驱动中设置,用来总线匹配匹配。
需要牢记一点,出生的设备最新还是需要在那根红线usb_bus_type上仔细找usb_device_match驱动usb_generic_driver;
usb hub 3 驱动的匹配:
只要是驱动,必然有一个标准的方式
按照驱动套路:
driver_register-->bus_add_driver-->driver_attach-->__driver_attach-->,(关键位置出来了,总线匹配)
-->driver_probe_device-->drv->probe==驱动(usb_probe_device)-->udriver->probe==通用驱动(generic_probe)。
驱动查找:
点击(此处)折叠或打开
- static int __driver_attach(struct device *dev, void *data)
- {
- struct device_driver *drv = data;
- //这个时候就是总线找设备:usb_device_match,和
- //看之前的关键字关键字<usb_device_type,for_devices>
- if (!driver_match_device(drv, dev))//总线匹配;见代码注释
- return 0;
- if (dev->parent) /* Needed for USB */
- down(&dev->parent->sem);
- down(&dev->sem);
- if (!dev->driver)
- driver_probe_device(drv, dev);//最终会调用的函数driver_probe_device;
- up(&dev->sem);
- if (dev->parent)
- up(&dev->parent->sem);
- return 0;
- }
//总线匹配:
点击(此处)折叠或打开
- static int usb_device_match(struct device *dev, struct device_driver *drv)
- {
- /* devices and interfaces are handled separately */
- if (is_usb_device(dev)) {//设备驱动的路口<usb_device_type>
- /* interface drivers never match devices */
- //这里需要看usb.c里面的.
- //匹配到usb_register_device_driver(&usb_generic_driver, THIS_MODULE);
- if (!is_usb_device_driver(drv))//路口字<for_devices>
- return 0;
- /* TODO: Add real matching code */
- return 1;//这里就告诉我们,这是usb_device_type,且for_devices==1;
- } else if (is_usb_interface(dev)) {//接口设备的路口,后面再来弄;
- struct usb_interface *intf;
- struct usb_driver *usb_drv;
- const struct usb_device_id *id;
- /* device drivers never match interfaces */
- if (is_usb_device_driver(drv))
- return 0;
- intf = to_usb_interface(dev);
- usb_drv = to_usb_driver(drv);
- id = usb_match_id(intf, usb_drv->id_table);
- if (id)
- return 1;
- id = usb_match_dynamic_id(intf, usb_drv);
- if (id)
- return 1;
- }
- return 0;
- }
- //device的探测函数
- static int usb_probe_device(struct device *dev)
- {
- struct usb_device_driver *udriver = to_usb_device_driver(dev->driver);
- struct usb_device *udev = to_usb_device(dev);
- int error = -ENODEV;
- dev_dbg(dev, "%s\n", __func__);
- /* TODO: Add real matching code */
- /* The device should always appear to be in use
- * unless the driver suports autosuspend.
- */
- udev->pm_usage_cnt = !(udriver->supports_autosuspend);
- error = udriver->probe(udev);//usb_driver,回到通用驱动usb_generic_driver
- return error;
- }
//通用驱动探测
点击(此处)折叠或打开
- static int generic_probe(struct usb_device *udev)
- {
- int err, c;
- /* Choose and set the configuration. This registers the interfaces
- * with the driver core and lets interface drivers bind to them.
- */
- if (usb_device_is_owned(udev))
- ; /* Don't configure if the device is owned */
- else if (udev->authorized == 0)
- dev_err(&udev->dev, "Device is not authorized for usage\n");
- else {
- c = usb_choose_configuration(udev);
- if (c >= 0) {
- // 既然已经选好配置了,那就告诉设备选好的配置,这个过程是在usb_set_configuration()中完成的
- //控制器和外设(hub)的通讯
- err = usb_set_configuration(udev, c);//这里又会生仔(设备)哟;
- if (err) {
- dev_err(&udev->dev, "can't set config #%d, error %d\n",c, err);
- /* This need not be fatal. The user can try to
- * set other configurations. */
- }
- }
- }
- /* USB device state == configured ... usable */
- usb_notify_add_device(udev);
- return 0;
- }
流程走完了;
这里完成后,整个驱动到了一个新的阶段,usb的枚举阶段的设备配置就完成;配置设备的含义==控制器讲:"你这个设备能够提供这么强大的力量,我选择一种"。
真正usb的功能驱动才刚刚开始,通常讲mass storage,webcam,包括hub的真正的驱动。
之前讲的那些驱动,都是些皮毛,还没有到肉,至少我们还没有弄明白,我们没有学会真正地控制usb;其实里面有好多的usb设备信息读取,我都漏掉,再整理的时候,找个时间再补充上每一章上去;
在用户态下编程可以通过main()的来传递命令行参数,而编写一个内核模块则通过module_param()
module_param宏是Linux 2.6内核中新增的,该宏被定义在include/linux/moduleparam.h文件中,具体定义如下
#define module_param(name, type, perm) 其中使用了 3 个参数:要传递的参数变量名, 变量的数据类型, 以及访问参数的权限。 <<< perm参数的作用是什么? 最后的 module_param 字段是一个权限值,表示此参数在sysfs文件系统中所对应的文件节点的属性。你应当使用 <linux/stat.h> 中定义的值. 这个值控制谁可以存取这些模块参数在 sysfs 中的表示.当perm为0时,表示此参数不存在 sysfs文件系统下对应的文件节点。 否则, 模块被加载后,在/sys/module/ 目录下将出现以此模块名命名的目录, 带有给定的权限.。
这个宏定义应当放在任何函数之外, 典型地是出现在源文件的前面.定义如: static char *whom = "world"; 模块参数支持许多类型: boolinvbool 一个布尔型( true 或者 false)值(相关的变量应当是 int 类型). invbool 类型颠倒了值, 所以真值变成 false, 反之亦然. charp :一个字符指针值. 内存为用户提供的字串分配, 指针因此设置. int long short uint ulong ushort 基本的变长整型值. 以 u 开头的是无符号值. 数组参数, 用逗号间隔的列表提供的值, 模块加载者也支持. 声明一个数组参数, 使用: module_param_array(name,type,num,perm); 这里 name 是你的数组的名子(也是参数名), type 是数组元素的类型, num 是一个整型变量, perm 是通常的权限值. 如果数组参数在加载时设置, num 被设置成提供的数的个数. 模块加载者拒绝比数组能放下的多的值. 测试模块,源程序hello.c内容如下: #include <linux/init.h> #include <linux/module.h> #include <linux/moduleparam.h> MODULE_LICENSE("Dual BSD/GPL"); static char *who= "world"; static int times = 1; module_param(times,int,S_IRUSR); module_param(who,charp,S_IRUSR); static int hello_init(void) { int i; for(i=0;i<times;i++) printk(KERN_ALERT "(%d) hello, %s!\n",i,who); return 0; } static void hello_exit(void) { printk(KERN_ALERT"Goodbye, %s!\n",who); } module_init(hello_init); module_exit(hello_exit); 编译生成可执行文件hello 插入: # insmod hello who="world" times=5 出现5次"hello,world!": #(1)hello,world! #(2)hello,world! #(3)hello,world! #(4)hello,world! #(5)hello,world! 卸载: # rmmod hello 出现: #Goodbye,world! |