if (dev->product)
sprintf(mouse->name, "%s %s", mouse->name, dev->product);
if (!strlen(mouse->name))
sprintf(mouse->name, "USB HIDBP Mouse %04x:%04x",
mouse->dev.id.vendor, mouse->dev.id.product);
usb_fill_int_urb(mouse->irq, dev, pipe, mouse->data,
(maxp > 8 ? 8 : maxp),
usb_mouse_irq, mouse, endpoint->bInterval);
/*
static inline void usb_fill_int_urb (struct urb *urb,
struct usb_device *dev,
unsigned int pipe,
void *transfer_buffer,
int buffer_length,
usb_complete_t complete,
void *context,
int interval)
{
spin_lock_init(&urb->lock);
urb->dev = dev;
urb->pipe = pipe;
urb->transfer_buffer = transfer_buffer;//如果不使用DMA传输方式,则使用这个缓冲指针。如何用DMA则使用transfer_DMA,这个值会在后面单独给URB赋
urb->transfer_buffer_length = buffer_length;
urb->complete = complete;
urb->context = context;
if (dev->speed == USB_SPEED_HIGH)
urb->interval = 1 << (interval - 1);
else
urb->interval = interval;
urb->start_frame. = -1;
}
此处只是构建好一个urb,在open方法中会实现向usb core递交urb
*/
mouse->irq->transfer_dma = mouse->data_dma;
mouse->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
/*
#define URB_NO_TRANSFER_DMA_MAP 0x0004? //urb->transfer_dma valid on submit
#define URB_NO_SETUP_DMA_MAP??? 0x0008? //urb->setup_dma valid on submit
, 这里是两个DMA 相关的flag,一个是URB_NO_SETUP_DMA_MAP,而另一个是
URB_NO_TRANSFER_DMA_MAP.注意这两个是不一样的,前一个是专门为控制传输准备的,因为只有控制传输需要有这么一个setup 阶段需要准备一个setup packet。
transfer_buffer 是给各种传输方式中真正用来数据传输的,而setup_packet 仅仅是在控制传输中发送setup 的包,控制传输除了setup 阶段之外,也会有数据传输阶段,这一阶段要传输数据还是得靠transfer_buffer,而如果使用dma 方式,那么就是使用transfer_dma.
因为这里使用了mouse->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP,所以应该给urb的transfer_dma赋值。所以用了:
mouse->irq->transfer_dma = mouse->data_dma;
*/
input_register_device(&mouse->dev);
//向input系统注册input设备
printk(KERN_INFO "input: %s on %s\n", mouse->name, path);
usb_set_intfdata(intf, mouse);
/*
usb_set_intfdata().的结果就是使得
%intf->dev->driver_data= mouse,而其它函数中会调用usb_get_intfdata(intf)的作用就是把mouse从中取出来
*/
return 0;
}
三、open部分
当应用层打开鼠标设备时,usb_mouse_open将被调用
static int usb_mouse_open(struct input_dev *dev)
{
struct usb_mouse *mouse = dev->private;
mouse->irq->dev = mouse->usbdev;
if (usb_submit_urb(mouse->irq, GFP_KERNEL))
return -EIO;
//向usb core递交了在probe中构建好的中断urb,注意:此处是成功递交给usb core以后就返回,而不是等到从设备取得鼠标数据。
return 0;
}
四、urb回调函数处理部分
当出现传输错误或获取到鼠标数据后,urb回调函数将被执行
static void usb_mouse_irq(struct urb *urb, struct pt_regs *regs)
{
struct usb_mouse *mouse = urb->context;
//在usb_fill_int_urb中有对urb->context赋值
signed char *data = mouse->data;
struct input_dev *dev = &mouse->dev;
int status;
switch (urb->status) {
case 0: /* success */
break;
case -ECONNRESET: /* unlink */
case -ENOENT:
case -ESHUTDOWN:
return;
/* -EPIPE:? should clear the halt */
default: /* error */
goto resubmit;
}
input_regs(dev, regs);
input_report_key(dev, BTN_LEFT, data[0] & 0x01);
input_report_key(dev, BTN_RIGHT, data[0] & 0x02);
input_report_key(dev, BTN_MIDDLE, data[0] & 0x04);
input_report_key(dev, BTN_SIDE, data[0] & 0x08);
input_report_key(dev, BTN_EXTRA, data[0] & 0x10);
//向input系统报告key事件,分别是鼠标LEFT、RIGHT、MIDDLE、SIDE、EXTRA键,
static inline void input_report_key(struct input_dev *dev, unsigned int code, int value)中的value非0时表示按下,0表示释放
input_report_rel(dev, REL_X, data[1]);
input_report_rel(dev, REL_Y, data[2]);
input_report_rel(dev, REL_WHEEL, data[3]);
//向input系统报告rel事件,分别是x方向位移、y方向位移、wheel值
input_sync(dev);
//最后需要向事件接受者发送一个完整的报告。这是input系统的要求。
resubmit:
status = usb_submit_urb (urb, SLAB_ATOMIC);
//重新递交urb
if (status)
err ("can't resubmit intr, %s-%s/input0, status %d",
mouse->usbdev->bus->bus_name,
mouse->usbdev->devpath, status);
}
五、应用层测试代码编写
在应用层编写测试鼠标的测试程序,在我的系统中,鼠标设备为/dev/input/event3. 测试代码如下:
/*
* usb_mouse_test.c
*by lht
*/
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <linux/input.h>
int main (void)
{
int fd,i,count;
struct input_event ev_mouse[2];
fd = open ("/dev/input/event3",O_RDWR);
if (fd < 0) {
printf ("fd open failed\n");
exit(0);
}
printf ("\nmouse opened, fd=%d\n",fd);
while(1)
{
printf("...............................................\n");
count=read(fd, ev_mouse, sizeof(struct input_event));
for(i=0;i<(int)count/sizeof(struct input_event);i++)
{
printf("type=%d\n",ev_mouse[i].type);
if(EV_REL==ev_mouse[i].type)
{
printf("time:%ld.%d",ev_mouse[i].time.tv_sec,ev_mouse[i].time.tv_usec);
,usb鼠标驱动注解及测试