歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

Mini2440 USB gadget --使用與測試

USB Gadget驅動又稱USB器件驅動。主要用於運行linux的嵌入式系統中,使得系統擁有普通USB設備的功能。mini2440具有USB1.1設備控制器,所以可以使用USB Gadget功能。但是linux2.6.32.2內核對於mini2440的支持不是很完全。開啟USB Gadget功能之後,不能使得主機發現USB硬件。這個問題主要是USB接口的上拉電阻的問題,mini2440使用GPC5來上拉USB,使得主機集線器發現有USB設備鏈接從而枚舉設備。但是在linux2.6.32.2內核中,沒有設置GPC5的代碼。所以導致不能使用Gadget功能。解決辦法網上也有一些,就是增加額外的模塊置位GPC5,但是我認為這樣不是最好的辦法。認真分析s3c2410_udc.c以及g_zero.c的代碼後,發現在注冊Gadget功能驅動的時候會調用s3c2410_udc.c提供的usb_gadget_register_driver函數,而這個函數最後會調用s3c2410_udc_enable。這個函數就是使能UDC的。代碼如下:
  1. static void s3c2410_udc_enable(struct s3c2410_udc *dev)  
  2. {  
  3.     int i;  
  4.   
  5.     dprintk(DEBUG_NORMAL, "s3c2410_udc_enable called\n");  
  6.   
  7.     /* dev->gadget.speed = USB_SPEED_UNKNOWN; */  
  8.     dev->gadget.speed = USB_SPEED_FULL;  
  9.   
  10.     /* Set MAXP for all endpoints */  
  11.     for (i = 0; i < S3C2410_ENDPOINTS; i++) {  
  12.         udc_write(i, S3C2410_UDC_INDEX_REG);  
  13.         udc_write((dev->ep[i].ep.maxpacket & 0x7ff) >> 3,  
  14.                 S3C2410_UDC_MAXP_REG);  
  15.     }  
  16.   
  17.     /* Set default power state */  
  18.     udc_write(DEFAULT_POWER_STATE, S3C2410_UDC_PWR_REG);  
  19.   
  20.     /* Enable reset and suspend interrupt interrupts */  
  21.     udc_write(S3C2410_UDC_USBINT_RESET | S3C2410_UDC_USBINT_SUSPEND,  
  22.             S3C2410_UDC_USB_INT_EN_REG);  
  23.   
  24.     /* Enable ep0 interrupt */  
  25.     udc_write(S3C2410_UDC_INT_EP0, S3C2410_UDC_EP_INT_EN_REG);  
  26.   
  27.     /* time to say "hello, world" */  
  28.   
  29.     if (udc_info && udc_info->udc_command) {  
  30.         udc_info->udc_command(S3C2410_UDC_P_ENABLE);  
  31.     }  
  32. }  
        我們發現這個函數除了前面使能中斷的操作後,最後有個判斷語句,判斷udc_info以及udc_info->command是否有值。然後調用udc_command,這個函數的調用參數為S3C2410_UDC_P_ENABLE。很顯然這個就是使能UDC的關鍵操作。我們看一下udc_info又是什麼,在s3c2410_udc.c的最開始有這樣的定義:

        static struct s3c2410_udc_mach_info *udc_info;

        說明這是一個指向s3c2410_udc_mach_info結構的指針。s3c2410_udc_mach_info結構在udc.h中定義:

  1. struct s3c2410_udc_mach_info {  
  2.     void    (*udc_command)(enum s3c2410_udc_cmd_e);  
  3.     void    (*vbus_draw)(unsigned int ma);  
  4.     unsigned int vbus_pin;  
  5.     unsigned char vbus_pin_inverted;  
  6. };  
        那麼這個指針又是什麼時候賦值的,是在s3c2410_udc_probe函數中。這就說明在注冊s3c2410_udc驅動的時候,由platform總線找到相應的設備匹配後,調用的。如下:
udc_info = pdev->dev.platform_data;
        那麼什麼又是platfom_data呢,這個又是在什麼時候賦值的呢。要理解這個還得需要平台驅動的只是,也就是platform driver的知識。s3c2410的udc驅動是一個platform驅動,所以USB設備控制器是platform device。那麼這個platform_data又是在哪賦的值。一般而言platform device在系統板級初始化的時候初始化的。也就是板級初始化的時候賦值。但是用Kscope怎麼也找不到給他賦值的語句。說明根本就沒人給他賦值。所以在注冊g_zero功能驅動的時候udc_info是空的,沒有執行udc_info->udc_command()。我們要做的就是給usb gadget platform device的platform_data初始化。在mach-mini2440.c中增加如下代碼:
  1. static void s3c2410_udc_pullup(enum s3c2410_udc_cmd_e cmd)  
  2. {  
  3.     switch (cmd) {  
  4.     case S3C2410_UDC_P_ENABLE :  
  5.         s3c2410_gpio_setpin(S3C2410_GPC(5), 1);  
  6.         break;  
  7.     case S3C2410_UDC_P_DISABLE :  
  8.         s3c2410_gpio_setpin(S3C2410_GPC(5), 0);  
  9.         break;  
  10.     case S3C2410_UDC_P_RESET :  
  11.         break;  
  12.     default:  
  13.         break;  
  14.     }  
  15. }  
        這個函數就是udc_info->udc_command()執行的函數,在這裡使得GPC5為高電平,使能USB設備。
  1. static struct s3c2410_udc_mach_info s3c2410_udc_cfg __initdata = {  
  2.     .udc_command        = s3c2410_udc_pullup,  
  3. };  
        這個結構體定義了platform_data的初始值。

        修改mini2440_machine_init函數,增加s3c24xx_udc_set_platdata(&s3c2410_udc_cfg);如下

  1. static void __init mini2440_machine_init(void)  
  2. {  
  3. #if defined (LCD_WIDTH)   
  4.     s3c24xx_fb_set_platdata(&mini2440_fb_info);  
  5. #endif   
  6.     s3c_i2c0_set_platdata(NULL);  
  7.   
  8.     s3c2410_gpio_cfgpin(S3C2410_GPC(0), S3C2410_GPC0_LEND);  
  9.   
  10.     s3c_device_nand.dev.platform_data = &friendly_arm_nand_info;  
  11.     s3c_device_sdi.dev.platform_data = &mini2440_mmc_cfg;  
  12.     s3c24xx_udc_set_platdata(&s3c2410_udc_cfg); //增加的代碼   
  13.     platform_add_devices(mini2440_devices, ARRAY_SIZE(mini2440_devices));  
  14.     s3c_pm_init();  
  15. }  
        s3c24xx_udc_set_platdata()這個函數定義與devs.c,如下:
  1. void __init s3c24xx_udc_set_platdata(struct s3c2410_udc_mach_info *pd)  
  2. {  
  3.     struct s3c2410_udc_mach_info *npd;  
  4.   
  5.     npd = kmalloc(sizeof(*npd), GFP_KERNEL);  
  6.     if (npd) {  
  7.         memcpy(npd, pd, sizeof(*npd));  
  8.         s3c_device_usbgadget.dev.platform_data = npd;  
  9.     } else {  
  10.         printk(KERN_ERR "no memory for udc platform data\n");  
  11.     }  
  12. }  
        最後還要在頭文件中包含plat/udc.h。這樣我們注冊Gadget功能驅動的時候自動使能了USB設備功能。但是在卸載驅動的時候發生了問題,內核打印出一大堆調試信息。問題出在composite.c中的composite_unbind函數中。這個函數開頭有一行代碼WARN_ON(cdev->config);就是如果cdev-config不為0,那麼內核就會打印出調試信息。上面還給了注釋
/* composite_disconnect() must already have been called
* by the underlying peripheral controller driver!
* so there's no i/o concurrency that could affect the
* state protected by cdev->lock.
*/
        這個composite_unbind是在卸載udc功能驅動的時候調用的,調用關系如下:usb_composite_unregister 調用 usb_gadget_unregister_driver而usb_gadget_unregister_driver如下定義:
  1. int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)  
  2. {  
  3.     struct s3c2410_udc *udc = the_controller;  
  4.   
  5.     if (!udc)  
  6.         return -ENODEV;  
  7.   
  8.     if (!driver || driver != udc->driver || !driver->unbind)  
  9.         return -EINVAL;  
  10.   
  11.     dprintk(DEBUG_NORMAL,"usb_gadget_register_driver() '%s'\n",  
  12.         driver->driver.name);  
  13.   
  14.     driver->disconnect(&udc->gadget);  
  15. //此處為新加語句,這條語句調用 composite_disconnect,然後使得cdev->config為NULL   
  16.     driver->unbind(&udc->gadget);  
  17. //這裡就是composite_unbind   
  18.   
  19.   
  20.     device_del(&udc->gadget.dev);  
  21.     udc->driver = NULL;  
  22.   
  23.     /* Disable udc */  
  24.     s3c2410_udc_disable(udc);  
  25.   
  26.     return 0;  
  27. }  
        從注釋上可以看出調用composite_unbind的前提是要首先保證composite_disconnect被調用。這樣才不會出現警告的內核信息。在增加上面的代碼後重新編譯內核,將USB Gadget設置稱為模塊。然後make modules 在通過ftp將s3c2410_udc.ko與g_zero.ko傳入開發板,先後加載這兩個模塊。在主機上lsusb會發現出現新設備
Bus 005 Device 023: ID 0525:a4a0 Netchip Technology, Inc. Linux-USB "Gadget Zero"
        卸載g_zero.ko後,新設備就會消失。這樣基本的USB Gadget驅動功能就開啟了。類似的還可以測試其他的USB Gagget。
Copyright © Linux教程網 All Rights Reserved