学习Linux下s3c2440的USB鼠标驱动笔记
Posted robot developer
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了学习Linux下s3c2440的USB鼠标驱动笔记相关的知识,希望对你有一定的参考价值。
1、ARM-Linux下USB驱动程序开发
1.1.1、linux下USB配置:
*********(MassStorage:存储设备)************************************
-> Device Drivers
-> SCSI device support(通用设备)
-> SCSI disk support (磁盘支持)
-> SCSI device support(设备支持)
-> Device Drivers
-> USB support (USB设备)
-> USB device filesystem (USB设备文件系统)
-> OHCI HCD support (主要是非PC上的USB芯片)
-> USB Mass Storage support(USB大容量设备)
-> USB Monitor (USB 主设备)
-> File systems
-> DOS/FAT/NT Filesystems
-> MSDOS fs support
-> VFAT (Windows-95) fs support
-> Partition Types (分区类型)
-> PC Bios (MSDOS partition tables) support
-> Native Language Suppor (本地语言设置)
-> Simplified Chinese charset (CP936, GB2312)
-> NLS UTF-8
make uImage (生成uImage)
测试 mount /dev/sda1 /mnt/
*********(HID:人机接口(鼠标、键盘))********************************
-> Device Drivers
HID Devices --->
-> USB Human Interface Device (full HID) support
USB support --->
-> Support for Host-side USB
make uImage (生成uImage)
测试 cat /dev/mouse1
*********(RNDIS:网卡)********************************
-> Device Drivers x
-> USB support x
-> USB Gadget Support
<M> Support for USB Gadgets
<M> Ethernet Gadget (with CDC Et hernet support) x x
[*] RNDIS support (EXPERIMENTAL) (NEW)
编译内核模块
cp drivers/usb/gadget/_ether.ko /work/nfs_root/first_fs/
cp /arch/arm/boot/uImage /work/nfs_root/new_uImage
*********(CDC-ACM:USB虚拟串口)********************************
(未能识别USB driver)可能是没有配置USB设备
1.2.1、驱动程序编写
struct usb_driver {
const char *name; /*USB驱动名字*/
int (*probe) (struct usb_interface *intf,const struct usb_device_id *id);/*USB core发现该驱动程序能够处理USB接口时,调用*/
void (*disconnect) (struct usb_interface *intf);/*USB移除的时候调用*/
const struct usb_device_id *id_table; /*该驱动程序支持哪些设备 idVendor(制造商ID) idProduct(产品id)*/
};
1.2.2、linux提供宏来定义 一种 设备 :
USB_DEVICE(vend,prod)
vend:USB Vendor ID 制造商ID
prod:USB Product ID 设备ID
1.2.3、linux提供宏来定义 一类 设备 :
USB_INTERFACE_INFO(cl,sc,pr)
cl:类 blnterfaceClass Value
sc:子类 blnterfaceSubClass value
pr:协议 blnterfaceProtocil Value
1.2.4、USB注册:传入一个参数usb_driver
static inline int usb_register(struct usb_driver *driver)
1.2.5、usb_device结构
int devnum; /* Address on USB bus */
char devpath [16]; /* Use in messages: /port/port/... */
enum usb_device_state state; /* configured, not attached, etc */
enum usb_device_speed speed; /* high/full/low (or error) */
struct usb_device_descriptor descriptor; /* Descriptor 设备描述符号*/
struct usb_host_config *config; /* All of the configs */
struct usb_config_descriptor desc; /*usb配置描述符*/
struct usb_interface *interface[USB_MAXINTERFACES];
ruct usb_host_interface *cur_altsetting; /* the currently
/*USB 接口描述符 一个[配置]包含一个或者多个接口,一个接口包含一个或者多个[设置] */
struct usb_interface_descriptor desc;
struct usb_host_endpoint *endpoint; /*USB端点*/
struct usb_endpoint_descriptor desc;/*USB 端点描述符 */
1.3.1、URB(usb request block)请求块 ,承载USB之间的数据传输
①URB处理流程:
1、USB设备驱动程序创建并初始化一个访问特点USB设备指定的端点的URB,并提交给USB Core
2、USB core提交该URB到USB主控制驱动程序
3、USB主控制器驱动程序根据该URB的描述信息,来访问USB设备
4、当访问设备结束后,USB主控制器驱动程序通知USB设备驱动(device)程序
②创建urb的函数为:
struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags)
参数1:iso_packets:urb所含的等时数据包个数
参数2:mem_flags:内存分配标示
③初始化urb函数为:interrupt
static inline void usb_fill_int_urb (
struct urb *urb, //要初始化urb指针
struct usb_device *dev, //usb_device设备
unsigned int pipe, //要访问的端点所对应的管道,使用usb_sndintpipe()/usb_rcvintpipe()
void *transfer_buffer, //要传输数据的缓冲区
int buffer_length, //要传输数据的长度
usb_complete_t complete_fn, //当完成urb所请求的操作时候调用的回调函数
void *context, //通常取值为DEV
int interval //URB被调度的时间间隔
);
问:何为管道?
答:管道:驱动程序的数据缓冲区与一个端点的连接,代表一个在两者之间要移动数据的能力。
批量urb:使用usb_fill_bulk_urb()
控制urb: 使用usb_control_urb()
等时urb没有像中断、控制、批量传输那样有URB初始化函数,我们只有手动初始化urb.
④提交URB
在完成urb的创建和初始化后,URB就可以通过usb_smbmit_urb函数来提交给usb core
int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
urb:指向URB的指针
mem_flags:内存分配标示,用于告知USB core如何分配内存换成区。
⑤URB处理 以下三种情况被认为URB处理完成,调用complete_fn函数
1、URB成功发送给设备,并且设备返回正确,URB->status = 0
2、如果接收和发送发生错误时候 urb->status = error
3、urb被取消,就发生在驱动程序通过,usb_unlink_urb() / usb_kill_urb()
鼠标驱动程序:
1 #include <linux/kernel.h> 2 #include <linux/errno.h> 3 #include <linux/init.h> 4 #include <linux/slab.h> 5 #include <linux/module.h> 6 #include <linux/kref.h> 7 #include <asm/uaccess.h> 8 #include <linux/usb.h> 9 #include <linux/mutex.h> 10 #include <linux/hid.h> 11 #include <linux/input.h> 12 13 14 /*创建输入设备*/ 15 static struct input_dev *uk_dev; 16 static int len; 17 static char *usb_buf; 18 static dma_addr_t usb_data_dma; 19 static struct urb *uk_urb; 20 21 22 23 24 //usb支持的设备列表 25 static struct usb_device_id usbmouse_key_table [] = { 26 { USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT, 27 USB_INTERFACE_PROTOCOL_MOUSE) }, 28 //{USB_DEVICE(0x1234,0x5678)}, 29 { } /* Terminating entry */ 30 }; 31 32 static void usb_mouse_irq(struct urb *urb) 33 { 34 static unsigned char pre_val; 35 #if 0 36 int i; 37 char b[100]; 38 static int cnt = 0; 39 printk("data cnt %d: ", ++cnt); 40 for (i = 0; i < len; i++) 41 { 42 printk("%02x ", usb_buf[i]); 43 } 44 printk("\\n"); 45 46 47 48 /* USB鼠标数据含义 49 * data[1]: bit0-左键, 1-按下, 0-松开 50 * bit1-右键, 1-按下, 0-松开 51 * bit2-中键, 1-按下, 0-松开 52 * 53 */ 54 // if ((pre_val & (1<<0)) != (usb_buf[1] & (1<<0))) 55 // { 56 // /* 左键发生了变化 */ 57 // input_event(uk_dev, EV_KEY, KEY_L, (usb_buf[1] & (1<<0)) ? 1 : 0); 58 // input_sync(uk_dev); 59 // } 60 61 // if ((pre_val & (1<<1)) != (usb_buf[1] & (1<<1))) 62 // { 63 // /* 右键发生了变化 */ 64 // input_event(uk_dev, EV_KEY, KEY_S, (usb_buf[1] & (1<<1)) ? 1 : 0); 65 // input_sync(uk_dev); 66 // } 67 68 // if ((pre_val & (1<<2)) != (usb_buf[1] & (1<<2))) 69 // { 70 // /* 中键发生了变化 */ 71 // input_event(uk_dev, EV_KEY, KEY_ENTER, (usb_buf[1] & (1<<2)) ? 1 : 0); 72 // input_sync(uk_dev); 73 // } 74 75 // pre_val = usb_buf[1]; 76 /* 重新提交urb */ 77 usb_submit_urb(uk_urb, GFP_KERNEL); 78 79 #else 80 81 switch (urb->status) { 82 case 0: /* success */ 83 break; 84 case -ECONNRESET: /* unlink */ 85 case -ENOENT: 86 case -ESHUTDOWN: 87 return; 88 /* -EPIPE: should clear the halt */ 89 default: /* error */ 90 goto resubmit; 91 } 92 93 input_report_key(uk_dev, BTN_LEFT, usb_buf[1] & 0x01); 94 input_report_key(uk_dev, BTN_RIGHT, usb_buf[1] & 0x02); 95 input_report_key(uk_dev, BTN_MIDDLE, usb_buf[1] & 0x04); 96 input_report_key(uk_dev, BTN_SIDE, usb_buf[1] & 0x08); 97 input_report_key(uk_dev, BTN_EXTRA, usb_buf[1] & 0x10); 98 99 input_report_rel(uk_dev, REL_X, usb_buf[3]); 100 input_report_rel(uk_dev, REL_Y, usb_buf[4]); 101 input_report_rel(uk_dev, REL_WHEEL, usb_buf[5]); 102 103 input_sync(uk_dev); 104 resubmit: 105 usb_submit_urb (urb, GFP_ATOMIC); 106 #endif 107 108 109 110 111 } 112 113 static int usbmouse_key_probe(struct usb_interface *intf, const struct usb_device_id *id) 114 { 115 struct usb_device *dev = interface_to_usbdev(intf); 116 struct usb_host_interface *interface; 117 struct usb_endpoint_descriptor *endpoint; 118 int pipe; 119 /*获取当前usb接口的设置*/ 120 interface = intf->cur_altsetting; 121 endpoint = &interface->endpoint[0].desc; 122 123 /* a. 分配一个input_dev */ 124 uk_dev = input_allocate_device(); 125 /* b. 设置 */ 126 /* b.1 能产生哪类事件 */ 127 set_bit(EV_KEY, uk_dev->evbit); 128 set_bit(EV_REL, uk_dev->evbit); 129 130 // /* b.2 能产生这类操作里的哪些事件: L,S,ENTER,LEFTSHIT */ 131 // set_bit(BTN_LEFT, uk_dev->keybit); 132 // set_bit(BTN_RIGHT, uk_dev->keybit); 133 // set_bit(BTN_MIDDLE, uk_dev->keybit); 134 135 // set_bit(REL_X,uk_dev->keybit); 136 // set_bit(REL_Y,uk_dev->keybit); 137 // set_bit(REL_WHEEL,uk_dev->keybit); 138 139 uk_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL); 140 uk_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE); 141 uk_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y); 142 uk_dev->keybit[LONG(BTN_MOUSE)] |= BIT(BTN_SIDE) | BIT(BTN_EXTRA); 143 uk_dev->relbit[0] |= BIT(REL_WHEEL); 144 145 /* c. 注册 */ 146 input_register_device(uk_dev); 147 148 /* d. 硬件相关操作 */ 149 /* 数据传输3要素: 源,目的,长度 */ 150 /* 源: USB设备的某个端点 */ 151 pipe = usb_rcvintpipe(dev,endpoint->bEndpointAddress); 152 /* 长度: */ 153 len = endpoint->wMaxPacketSize; 154 /* 目的: */ 155 usb_buf = usb_buffer_alloc(dev,len,GFP_ATOMIC,&usb_data_dma); 156 /* 使用"3要素" */ 157 /* 分配usb request block */ 158 uk_urb = usb_alloc_urb(0, GFP_KERNEL); 159 160 /* 使用"3要素设置urb" */ 161 usb_fill_int_urb(uk_urb, dev, pipe,usb_buf,len,usb_mouse_irq, NULL, endpoint->bInterval); 162 uk_urb->transfer_dma = usb_data_dma; 163 uk_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 164 165 /* 使用URB */ 166 usb_submit_urb(uk_urb, GFP_KERNEL); 167 168 169 printk("found usbmouse!\\n"); 170 171 printk("bcdUSB = %x\\n", dev->descriptor.bcdUSB); 172 printk("VID = 0x%x\\n", dev->descriptor.idVendor); 173 printk("PID = 0x%x\\n", dev->descriptor.idProduct); 174 175 return 0; 176 } 177 178 static void usbmouse_key_disconnect(struct usb_interface *interface) 179 { 180 struct usb_device *dev = interface_to_usbdev(interface); 181 182 printk("usbmouse_key_disconnect\\n"); 183 input_unregister_device(uk_dev); 184 input_free_device(uk_dev); 185 usb_buffer_free(dev,len,usb_buf,usb_data_dma); 186 usb_kill_urb(uk_urb); 187 usb_free_urb(uk_urb); 188 189 } 190 191 MODULE_DEVICE_TABLE (usb, usbmouse_key_table); 192 193 /*usbmouse_key_probe usbmouse_key_disconnect 函数指针 194 *当设备与在id_table 中变量信息匹配时,此函数被调用 195 */ 196 static struct usb_driver usbmouse_key_driver = { 197 .name = "usbmouse_key", 198 .probe = usbmouse_key_probe, 199 .disconnect = usbmouse_key_disconnect, 200 .id_table = usbmouse_key_table, 201 202 }; 203 204 /* 205 *USB骨架 最基本的usb驱动模板 206 */ 207 static int __init usb_usbmouse_key_init(void) 208 { 209 int result; 210 211 printk("usb_usbmouse_key_init\\n"); 212 213 /* register this driver with the USB subsystem */ 214 result = usb_register(&usbmouse_key_driver); 215 if (result) 216 err("usb_register failed. Error number %d", result); 217 218 return result; 219 } 220 221 static void __exit usb_usbmouse_key_exit(void) 222 { 223 printk("usb_usbmouse_key_exit\\n"); 224 /* deregister this driver with the USB subsystem */ 225 usb_deregister(&usbmouse_key_driver); 226 } 227 228 module_init(usb_usbmouse_key_init); 229 module_exit(usb_usbmouse_key_exit); 230 MODULE_LICENSE("GPL");
以上是关于学习Linux下s3c2440的USB鼠标驱动笔记的主要内容,如果未能解决你的问题,请参考以下文章
Linux 下wifi 驱动开发—— USB接口WiFi驱动浅析