1. 程式人生 > >【驅動】第6課、USB驅動之學習筆記

【驅動】第6課、USB驅動之學習筆記

主   機:VMWare--Ubuntu-16.04.2-x64-100ask

開發板:Mini2440--256M NandFlash,   2M NorFlash,   64M SDRAM,   LCD-TD35;
    bootlorder:u-boot1.16,        Kernel:2.6.22.6;
編譯器:arm-linux-gcc-3.4.5


 

目錄:

程式設計
一、搭建usb匯流排裝置驅動模型框架
二、加入對USB滑鼠的廠家ID, 裝置ID的列印;
三、I.probe()函式:
II.usbmouse_as_key_irq()函式
四、重做usbmouse_as_key_irq()函式


原始碼


【程式設計】
目的:用USB滑鼠做按鍵,左鍵-'L',右鍵-'S',中鍵-'ENTER'。
步驟:
一、搭建usb匯流排裝置驅動模型框架
目的:在開發板上接入、拔出USB滑鼠並在終端列印USB滑鼠插拔狀態;
1. 分配一個usb_driver結構體:
static struct usb_driver usbmouse_as_key_driver = {
.id_table
.probe
.disconnect};
static struct usb_device_id usbmouse_as_key_id_table [] = {
{ USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
USB_INTERFACE_PROTOCOL_MOUSE) },};
static int usbmouse_as_key_probe(struct usb_interface *intf, const struct usb_device_id *id){printk("found usbmouse!\n");}
static void usbmouse_as_key_disconnect(struct usb_interface *intf){ printk("disconnect usbmouse!\n");}
2.配置結構體usb_driver;
3.註冊結構體usb_driver;
usb_register(&usbmouse_as_key_driver);
static int usbmouse_as_key_init(void) {usb_register(&usbmouse_as_key_driver);}
static void usbmouse_as_key_exit(void) { usb_deregister(&usbmouse_as_key_driver);}
module_init(usbmouse_as_key_init);
module_exit(usbmouse_as_key_exit);

二、加入對USB滑鼠的廠家ID, 裝置ID的列印;
usbmouse_as_key_probe(struct usb_interface *intf, const struct usb_device_id *id){
struct usb_device *dev = interface_to_usbdev(intf);
printk("bcdUSB = %x\n", dev->descriptor.bcdUSB);
printk("VID = 0x%x\n", dev->descriptor.idVendor);
printk("PID = 0x%x\n", dev->descriptor.idProduct);
}
三、I.probe()函式:
(在probe()函式中)加入以滑鼠為輸入裝置的輸入子系統;
1.分配一個input_dev;
2.配置該結構體;
3.註冊該結構體;
4、硬體相關的操作;
4.1資料傳輸的三要素:源,長度,目的(地)。
a.源:USB裝置的某個端點。int pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
b.長度:len = endpoint->wMaxPacketSize;
c.目的(地):從USB讀出的資料儲存到的緩衝區地址(虛擬地址),
usb_buf = usb_buffer_alloc(dev, len, GFP_ATOMIC, &usb_buf_phys); //返回值是一個虛擬地址。
4.2(使用三要素)分配並初始化URB:
a.分配usb request block,即:uk_urb = usb_alloc_urb(0, GFP_KERNEL);
b.使用“三要素”設定/填充urb;
usb_fill_int_urb(uk_urb, dev, pipe, usb_buf, len, usbmouse_as_key_irq, NULL, endpoint->bInterval);
uk_urb->transfer_dma = usb_buf_phys;
uk_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
4.3提交URB;
usb_submit_urb(uk_urb, GFP_KERNEL);

II.usbmouse_as_key_irq()函式:在USB主機控制器得到資料併產生中斷 usbmouse_as_key_irq(),在此中斷中處理函式內處理中斷;
1.列印從usb裝置讀到的資料:
for(i = 0; i < len; i++) printk("%02x ", usb_buf[i]);
2.重新提交URB:
usb_submit_urb(uk_urb, GFP_KERNEL);
四、重做usbmouse_as_key_irq()函式
1.提交USB滑鼠按鍵資料
* 滑鼠按鍵: usb_buf[0];
* 左鍵: bit0; 右鍵:bit1; 中鍵: bit2;
if((preval & (1<<0)) != (usb_buf[0] & (1<<0)))
{
input_event(uk_dev, EV_KEY, KEY_L, (usb_buf[0] & (1<<0)) ? 1 : 0);
input_sync(uk_dev);
}
2.重新提交URB:
usb_submit_urb(uk_urb, GFP_KERNEL);

【測試】
測試1th/2th:
1. make menuconfig去掉原來的USB滑鼠驅動
-> Device Drivers
-> HID Devices
<> USB Human Interface Device (full HID) support
2. make uImage 並使用新的核心啟動
3. insmod usbmouse_as_key.ko
4. 在開發板上接入、拔出USB滑鼠

測試3th:
1. insmod usbmouse_as_key.ko
2. ls /dev/event*
3. 接上USB滑鼠
4. ls /dev/event*
5. 操作滑鼠觀察資料
問題1:122: warning: ISO C90 forbids mixed declarations and code
翻譯:ISO C90禁止混合宣告和程式碼
問題原始碼:
static void usbmouse_as_key_disconnect (struct usb_interface *intf)
{
printk("disconnect usbmouse!\n");
struct usb_device *dev = interface_to_usbdev(intf); //122行;
...
}

測試4th:
1. insmod usbmouse_as_key.ko
2. ls /dev/event*
3. 接上USB滑鼠
4. ls /dev/event*
5. cat /dev/tty1 然後按滑鼠鍵
6. hexdump /dev/event0

【原始碼】

原始碼:usbmouse_as_key.c

  1 /*
  2  * 2019-01-04
  3  * 功能: 用USB滑鼠做按鍵;
  4  */
  5 #include <linux/kernel.h>
  6 #include <linux/slab.h>
  7 #include <linux/module.h>
  8 #include <linux/init.h>
  9 #include <linux/usb/input.h>
 10 #include <linux/hid.h>
 11 MODULE_LICENSE("GPL");
 12 
 13 static struct input_dev *uk_dev;
 14 static struct urb *uk_urb;
 15 static int len;                /* 資料長度 */
 16 static char *usb_buf;        /* 虛擬地址 */
 17 static dma_addr_t usb_buf_phys;    /* 實體地址 */
 18 
 19 /* usb滑鼠中斷處理函式 */
 20 static void usbmouse_as_key_irq(struct urb *urb)
 21 {
 22     static char preval;
 23     #if 0
 24     /* 1.列印從usb裝置讀到的資料 */
 25     static int cnt = 0;
 26     int i;
 27     printk("usbmouse data cnt %d:   ", ++cnt);
 28     for(i = 0; i < len; i++)
 29     {
 30         printk("%02x ", usb_buf[i]);
 31     }
 32     printk("\n");
 33     #endif
 34     /* 1.提交資料
 35      * 滑鼠按鍵: usb_buf[0];
 36      * 左鍵: bit0; 右鍵:bit1; 中鍵: bit2;
 37      */
 38     /* 左鍵發生變化 */
 39     if((preval & (1<<0)) != (usb_buf[0] & (1<<0)))
 40     {
 41         input_event(uk_dev, EV_KEY, KEY_L, (usb_buf[0] & (1<<0)) ? 1 : 0);
 42         input_sync(uk_dev);
 43     }
 44     /* 右鍵發生變化 */
 45     if((preval & (1<<1)) != (usb_buf[0] & (1<<1)))
 46     {
 47         input_event(uk_dev, EV_KEY, KEY_S, (usb_buf[0] & (1<<1)) ? 1 : 0);
 48         input_sync(uk_dev);
 49     }
 50     /* 中鍵發生變化 */
 51     if((preval & (1<<2)) != (usb_buf[0] & (1<<2)))
 52     {
 53         input_event(uk_dev, EV_KEY, KEY_ENTER, (usb_buf[0] & (1<<2)) ? 1 : 0);
 54         input_sync(uk_dev);
 55     }
 56     preval = usb_buf[0];
 57     /* 2.重新提交uK_urb */
 58     usb_submit_urb(uk_urb, GFP_KERNEL);
 59 }
 60 static int usbmouse_as_key_probe (struct usb_interface *intf, const struct usb_device_id *id)
 61 {
 62     struct usb_device *dev = interface_to_usbdev(intf);
 63     struct usb_endpoint_descriptor *endpoint;
 64     struct usb_host_interface *hostintf;
 65     int pipe;
 66 
 67     hostintf = intf->cur_altsetting;
 68     if (hostintf->desc.bNumEndpoints != 1)
 69         return -ENODEV;
 70     endpoint = &hostintf->endpoint[0].desc;
 71     if (!usb_endpoint_is_int_in(endpoint))
 72         return -ENODEV;
 73     printk("found usbmouse!\n");
 74 
 75      #if 0
 76     printk("bcdUSB = 0X%04X\n", dev->descriptor.bcdUSB);
 77     printk("VID = 0X%04X\n", dev->descriptor.idVendor);
 78     printk("PID = 0X%04X\n", dev->descriptor.idProduct);
 79      #endif
 80     /* 1.分配一個input_dev結構體 */
 81     uk_dev = input_allocate_device();
 82     if(!uk_dev)
 83     {
 84         printk(KERN_ERR "Unable to allocate uk_dev input device!\n");
 85         goto err_fail1;
 86     }
 87      /* 2.配置該dev */
 88      /* 2.1配置該裝置支援哪類事件 */
 89     set_bit(EV_KEY, uk_dev->evbit);
 90     set_bit(EV_REP, uk_dev->evbit);
 91     /* 2.2配置該裝置支援哪些事件 */
 92     set_bit(KEY_L, uk_dev->keybit);
 93     set_bit(KEY_S, uk_dev->keybit);
 94     set_bit(KEY_ENTER, uk_dev->keybit);
 95     /* 3.註冊該結構體 */
 96     if(input_register_device(uk_dev) < 0)
 97     {
 98         printk(KERN_ERR "Unable to register uk_dev input device!\n");
 99         goto err_fail2;
100     }
101     /* 4.硬體相關的配置 */
102     /* 4.1資料傳輸三要素: 資料來源,目的地,長度 */
103     pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
104     len = endpoint->wMaxPacketSize;
105     usb_buf = usb_buffer_alloc(dev, len, GFP_ATOMIC, &usb_buf_phys);
106     if(!usb_buf)
107     {
108         printk(KERN_ERR "Unable to allocate usb_buf transfer buffer!\n");
109         goto err_fail3;
110     }
111     /* 4.2分配並初始化urb */
112     uk_urb = usb_alloc_urb(0, GFP_KERNEL);
113     if(!uk_urb)
114     {
115         printk(KERN_ERR "Unable to allocate uk_urb usb request block!\n");
116         goto err_fail4;
117     }
118     usb_fill_int_urb(uk_urb, dev, pipe, usb_buf, len, usbmouse_as_key_irq, 
119         NULL, endpoint->bInterval);
120     uk_urb->transfer_dma = usb_buf_phys;
121     uk_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
122     /* 4.3提交urb */
123     if(usb_submit_urb(uk_urb, GFP_KERNEL) < 0)
124     {
125         printk(KERN_ERR "Unable to submit uk_urb usb request block!\n");
126         goto err_fail5;
127     }
128  
129     return 0;
130  err_fail5:
131      usb_kill_urb(uk_urb);
132  err_fail4:
133      usb_free_urb(uk_urb);
134  err_fail3:
135      usb_buffer_free(dev, len, usb_buf, usb_buf_phys);
136  err_fail2:
137      input_unregister_device(uk_dev);
138  err_fail1:
139      input_free_device(uk_dev);
140     return -ENOMEM;
141 }
142 
143 static void usbmouse_as_key_disconnect (struct usb_interface *intf)
144 {
145     struct usb_device *dev = interface_to_usbdev(intf);
146 
147     printk("disconnect usbmouse!\n");
148     usb_kill_urb(uk_urb);
149      usb_free_urb(uk_urb);
150      usb_buffer_free(dev, len, usb_buf, usb_buf_phys);
151      input_unregister_device(uk_dev);
152      input_free_device(uk_dev);
153 }
154 
155 static struct usb_device_id usbmouse_as_key_id_table[] = {
156     {USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT, \
157         USB_INTERFACE_PROTOCOL_MOUSE)},
158     //{USB_DEVICE(vend, prod)},
159     {},
160 };
161 
162 static struct usb_driver usbmouse_as_key_driver = {
163     .name = "usbmouse_as_key2",
164     .probe = usbmouse_as_key_probe,
165     .disconnect = usbmouse_as_key_disconnect,
166     .id_table = usbmouse_as_key_id_table,
167 };
168 
169 static int usbmouse_as_key_init(void)
170 {
171     int retval = usb_register(&usbmouse_as_key_driver);
172     if(retval < 0)
173     {
174         printk("Unable to register the usb_driver of usbmouse_as_key_driver!\n");
175     }
176     return retval;
177 }
178 static void usbmouse_as_key_exit(void)
179 {
180     usb_deregister(&usbmouse_as_key_driver);
181 }
182 
183 module_init(usbmouse_as_key_init);
184 module_exit(usbmouse_as_key_exit);

Makefile

 1 ifneq ($(KERNELRELEASE),)
 2     obj-m := usbmouse_as_key8.o
 3 else
 4     KERN_DIR ?= /home/book/workbook/mini2440/systems/linux-2.6.22.6
 5 
 6     PWD = $(shell pwd)
 7 all:
 8     $(MAKE) -C $(KERN_DIR) M=$(PWD) modules
 9 clean:
10     $(MAKE) -C $(KERN_DIR) M=$(PWD) modules clean
11     rm -rf modules.order
12 
13 endif