【驱动】第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