乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      linux usb初始化

       lchjczw 2012-03-15

      linux usb初始化

      謹以此文紀念過往的歲月

       一.前言

      對于usb的普通驅(qū)動,我們了解了不少,但是對于usb的真正核心還是不是太理解。該文中對于usb的初始化進行一定的學習,如有不對之處,請各位多多指教。

       

      .usb子系統(tǒng)初始化。

      話說在linux啟動之初,就會將usb子系統(tǒng)初始化完成,亦如input子系統(tǒng)和V4L2一樣。usb_init就完成了初始化以及啟動usb hub守護進程。那來看usb_init中的各個函數(shù)的實現(xiàn)。

      2.1 ksuspend_usb_init

      static int ksuspend_usb_init(void)

      {

          ksuspend_usb_wq = create_freezeable_workqueue("ksuspend_usbd");

          if (!ksuspend_usb_wq)

              return -ENOMEM;

          return 0;

      }

      創(chuàng)建一個名為ksuspend_usbd的工作隊列。不過在該函數(shù)說明中也說明了,該函數(shù)在多CPU中并不能很好的工作。也許大家對這個函數(shù)會很奇怪,不知道該工作隊列的作用。

      這個工作隊列如何使用的,將在看usbsuspendresume時再具體看這個東東具體有什么用。

      2.2 bus_register

      usb_init中第二個調(diào)用的函數(shù)是bus_register(&usb_bus_type);這個應該很熟悉吧,注冊一個usb總線,其會在/sys/bus下創(chuàng)建一個usb的文件夾,在其中會創(chuàng)建bus屬性文件和driversdevices文件夾,以后所有的usb設(shè)備和usb驅(qū)動都會在這兩個文件夾下。bus總線需要指明devicedriver匹配的規(guī)則,例如platform busname進行匹配,而usb則以id進行匹配。對于bus_register在前文中講述多,這里不多此一舉了。那主要來看usb bus的特征。

      struct bus_type usb_bus_type = {

      .name =      "usb",              --定義busname,這個也會是在/sys/bus下看見的文件夾得名稱。

          .match =    usb_device_match,   --定義busdevicedriver的匹配規(guī)則

          .uevent =   usb_uevent,         --usb的觸發(fā)事件處理。

      };

      下面來看usb的匹配規(guī)則函數(shù)。不過有一點需要說明的是一般usb的驅(qū)動為usbinterface的驅(qū)動,而不是usb設(shè)備的驅(qū)動。為了方便描述,并沒有加以說明,要注意了。

      static int usb_device_match(struct device *dev, struct device_driver *drv)

      {

          if (is_usb_device(dev)) {       --判斷是否為usb device

          if (!is_usb_device_driver(drv)) --判斷是否為為usb device的驅(qū)動。interface 驅(qū)動不能與device匹配。

                  return 0;

              return 1;      --這個不是主要的,下面才是真正的驅(qū)動和設(shè)備的匹配。

          } else {

              struct usb_interface *intf;

              struct usb_driver *usb_drv;

              const struct usb_device_id *id;

              if (is_usb_device_driver(drv))   --usb device driver不能驅(qū)動interface。

                  return 0;

              intf = to_usb_interface(dev);    --取得設(shè)備的當前interface

              usb_drv = to_usb_driver(drv);    --取得驅(qū)動。

             id = usb_match_id(intf, usb_drv->id_table);  --真正的匹配規(guī)則。對于這個函數(shù)我們就不加描述。感興趣的可以去看具體的實現(xiàn),其實這個函數(shù)的額實現(xiàn)也很簡單。就是對usb interface中的ididVendor ,idProduct, bDeviceClass等參數(shù)進行匹配。

          if (id)

                  return 1;

              id = usb_match_dynamic_id(intf, usb_drv);

              if (id)

                  return 1;

          }

          return 0;

      }

      對于usb match比較好理解,而usb_uevent中,則定義了usb的熱插拔的處理函數(shù)。這個的作用就是將設(shè)備的信息存儲到env中,可以供用戶空間讀。對于設(shè)備的信息,我們可以通過在用戶空間的程序中讀取/proc/bus/usb/下的文件取得這些設(shè)備的信息。

      static int usb_uevent(struct device *dev, struct kobj_uevent_env *env)

      {

          struct usb_device *usb_dev;

          if (is_usb_device(dev))

              usb_dev = to_usb_device(dev);

          else {

              struct usb_interface *intf = to_usb_interface(dev);

              usb_dev = interface_to_usbdev(intf);

          }

       

          if (usb_dev->devnum < 0) {

                  return -ENODEV;

          }

          if (!usb_dev->bus) {

              return -ENODEV;

          }

       

      #ifdef  CONFIG_USB_DEVICEFS     --添加設(shè)備名稱

          if (add_uevent_var(env, "DEVICE=/proc/bus/usb/%03d/%03d",

                     usb_dev->bus->busnum, usb_dev->devnum))

              return -ENOMEM;

      #endif

          if (add_uevent_var(env, "PRODUCT=%x/%x/%x",  --添加設(shè)備id

                     le16_to_cpu(usb_dev->descriptor.idVendor),

                     le16_to_cpu(usb_dev->descriptor.idProduct),

                     le16_to_cpu(usb_dev->descriptor.bcdDevice)))

              return -ENOMEM;

          if (add_uevent_var(env, "TYPE=%d/%d/%d",   --添加設(shè)備類型。

                     usb_dev->descriptor.bDeviceClass,

                     usb_dev->descriptor.bDeviceSubClass,

                     usb_dev->descriptor.bDeviceProtocol))

              return -ENOMEM;

       

          return 0;

      }

      對于uevent的理解可能比較難懂一點,不過你可以把uevent的操作看成將一些設(shè)備和驅(qū)動的信息寫到/proc下對應的文件中,讓usrspcae的用戶程序可以讀取從而獲取設(shè)備的信息。

      2.3  usb_host_init

      也許從這個函數(shù)名上看不出這個函數(shù)的具體應用是什么,既然看函數(shù)名不知道干什么,那我們來看該函數(shù)的具體實現(xiàn)。你會發(fā)現(xiàn)這個函數(shù)好像挺簡單的,就是創(chuàng)建一個usb host 類。

      int usb_host_init(void)

      {

          int retval = 0;

          usb_host_class = class_create(THIS_MODULE, "usb_host");

          if (IS_ERR(usb_host_class))

              retval = PTR_ERR(usb_host_class);

          return retval;

      }

      關(guān)于這個設(shè)備類有什么用,以后再說,咱們還是繼續(xù)usb init的主線來看usb。

      2.4 usb_major_init

      注冊usb major其實是注冊一個以USB_MAJOR為主設(shè)備號的cdev。不過其還分配了256個從設(shè)備號。提供一個公共的open函數(shù)。

      int usb_major_init(void)

      {

          int error;

       

          error = register_chrdev(USB_MAJOR, "usb", &usb_fops);

          if (error)

              printk(KERN_ERR "Unable to get major %d for usb devices\n",

                     USB_MAJOR);

       

          return error;

      }

      對于每一個usb設(shè)備的打開都會先調(diào)用主設(shè)備的open,而后根據(jù)不同的設(shè)備調(diào)用不同的open函數(shù)。下面就是cdevops操作集。

      static const struct file_operations usb_fops = {

          .owner =    THIS_MODULE,

          .open =     usb_open,

      };

      static int usb_open(struct inode * inode, struct file * file)

      {

          int minor = iminor(inode);

          const struct file_operations *c;

          int err = -ENODEV;

          const struct file_operations *old_fops, *new_fops = NULL;

       

          lock_kernel();

          down_read(&minor_rwsem);

          c = usb_minors[minor];   --關(guān)于這個全局變量在以后的usb設(shè)備注冊時會看到,這里先有個底。

          if (!c || !(new_fops = fops_get(c)))

              goto done;

       

          old_fops = file->f_op;

          file->f_op = new_fops;

          /* Curiouser and curiouser... NULL ->open() as "no device" ? */

          if (file->f_op->open)

              err = file->f_op->open(inode,file);  --調(diào)用真正的open

          if (err) {

              fops_put(file->f_op);

              file->f_op = fops_get(old_fops);

          }

          fops_put(old_fops);

       done:

          up_read(&minor_rwsem);

          unlock_kernel();

          return err;

      }

      其實上面的公共的open就是提供一個對于所有的usb 設(shè)備的公共接口,真正的open其實是usb_minors中存儲的fops->open.

      2.5 usb_register

      該函數(shù)是注冊usbfs_driver驅(qū)動。不過注冊該驅(qū)動不知是為什么。

      2.6 usb_devio_init

      對于這個函數(shù)就更加困惑了,這個同樣是注冊一個以USB_DEVICE_DEV為主設(shè)備號的cdev設(shè)備。

      int __init usb_devio_init(void)

      {

          int retval;

          retval = register_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX,

                          "usb_device");

          if (retval) {

              goto out;

          }

          cdev_init(&usb_device_cdev, &usbdev_file_operations);

          retval = cdev_add(&usb_device_cdev, USB_DEVICE_DEV, USB_DEVICE_MAX);

          if (retval) {

              goto error_cdev;

          }

          usb_classdev_class = class_create(THIS_MODULE, "usb_device");

          if (IS_ERR(usb_classdev_class)) {

              goto out;

          }

          usb_classdev_class->dev_kobj = NULL;

          usb_register_notify(&usbdev_nb);

          return retval;

      }

      關(guān)于這個函數(shù)具體有什么用,以后再看,先跳過。

      2.7 usbfs_init

      int __init usbfs_init(void)

      {

          int retval;

          retval = register_filesystem(&usb_fs_type); --注冊filesystem

          if (retval)

              return retval;

          usb_register_notify(&usbfs_nb);

          usbdir = proc_mkdir("bus/usb", NULL);  --usbfs創(chuàng)建掛載點

          return 0;

      }

      2.8 usb_hub_init

      int usb_hub_init(void)

      {

          if (usb_register(&hub_driver) < 0) {  --注冊hub驅(qū)動

              printk(KERN_ERR "%s: can't register hub driver\n",

                  usbcore_name);

              return -1;

          }

          khubd_task = kthread_run(hub_thread, NULL, "khubd"); --創(chuàng)建hub守護進程

          if (!IS_ERR(khubd_task))

              return 0;

          usb_deregister(&hub_driver);

          return -1;

      }

      2.9 usb_register_device_driver

      注冊一個通用usb驅(qū)動。usb_register_device_driver(&usb_generic_driver, THIS_MODULE);

      OK,到此usb init是看完了,不過這里面卻有種種的迷霧,讓人不解困惑。比如為什么要注冊兩個usb major,還注冊了兩個古怪的驅(qū)動,這些種種讓人不解。不過這些都將會在后面的學習中來了解這些。

      .總結(jié)

      對于大牛們而言,也許這些東西很簡單,不過對于我這個菜鳥而言,卻是那么的難弄。在此本文也僅僅是對自己學習的一個記錄。

        本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
        轉(zhuǎn)藏 分享 獻花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多