学习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");
View Code

 





以上是关于学习Linux下s3c2440的USB鼠标驱动笔记的主要内容,如果未能解决你的问题,请参考以下文章

Linux 下wifi 驱动开发—— USB接口WiFi驱动浅析

Linux-USB驱动笔记

usb的驱动应该怎么写?

Linux驱动之USB总线驱动程序框架简析

Linux USB 驱动开发—— USB 鼠标驱动注解及测试

Linux USB 驱动开发实例—— USB 鼠标驱动注解及测试