自己板子是插上鼠标后,没有反应,只有在插上鼠标,板子重新上电,鼠标才有作用,这实在是不解,好像板子是有鼠标USB驱动,而USB驱动是支持热拔插的,不应该出现这种情况的,出现了,就想着解决。
首先必须的知道USB插上设备之后,内核做了哪些工作。(这一步很重要)
插上鼠标,终端打印了这些话,
new full speed USB device using xxxx
拔开鼠标,也会打印
USB disconnect
所以,这些话是在哪打印的呢? 通过全局搜索,发现在hub_port_init函数里面,再玩上找会找到hub_port_connect_change函数,这个函数就是重点了。
在这里需要先了解USB的驱动框架,这里不做过多的阐述,都是别人的话,具体可以参考别人写的Linux书,每一本都会讲到USB,USB的基础概念,框架,各个结构体......
提出其中对我有用的地方,就是USB设备一插上了之后,就会引起中断,USB总线驱动就会发现设备,给新设备分配地址(choose_address(udev)
),
告诉USB设备(hub_set_address
),
发出命令获取描述符(usb_get_device_descriptor(udev, 8),usb_get_configuration(udev)
),最后
device_add。把device放入usb_bus_type的dev链表
从usb_bus_type的driver链表里取出usb_driver,
把usb_interface和usb_driver的id_table
如果能匹配,调用usb_driver的probe
所以,做这个USB开发的,就只需要
分配/设置usb_driver结构体,做好.probe函数。就行了。这就是USB的驱动框架了。内核都跟你做好了准备工作了,分工明确,做驱动开发也可以很轻松。
1),开始写一个最简单的USB驱动程序
1,注册
2,分配设置usb_driver结构体
/* 1. 分配/设置usb_driver */ static struct usb_driver usbmouse_driver = { .name = "usbmouse_", .probe = usbmouse_probe, .disconnect = usbmouse_disconnect, .id_table = usbmouse_id_table, }; static int usbmouse_init(void) { /* 2. 注册 */ usb_register(&usbmouse_driver); return 0; } static void usbmouse_exit(void) { usb_deregister(&usbmouse_driver); } module_init(usbmouse_init); module_exit(usbmouse_exit); MODULE_LICENSE("GPL"); 复制代码
USB设备驱动的匹配之通过id_table,和platfrom平台驱动匹配方式(设备名字匹配的)不同,这里是想匹配鼠标,所以在id_table 里添加
static struct usb_device_id usbmouse_id_table [] = { { USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT, USB_INTERFACE_PROTOCOL_MOUSE) }, { } /* Terminating entry */ }; 复制代码
这样,usb总线驱动识别出了鼠标,id_table匹配上了,就会调用相应的probe函数
在函数之外定义几个结构体,做全局调用
static char *usb_buf; static dma_addr_t usb_buf_phys; static int len; static struct urb *uk_urb; 复制代码
static int usbmouse_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_device *dev = interface_to_usbdev(intf); struct usb_host_interface *interface; struct usb_endpoint_descriptor *endpoint; int pipe; interface = intf->cur_altsetting; endpoint = &interface->endpoint[0].desc; /* 数据传输3要素: 源,目的,长度 */ /* 源: USB设备的某个端点 */ pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); /* 长度: */ len = endpoint->wMaxPacketSize; /* 目的: */ usb_buf = usb_alloc_coherent(dev, len, GFP_ATOMIC, &usb_buf_phys); /* 使用"3要素" */ /* 分配usb request block */ uk_urb = usb_alloc_urb(0, GFP_KERNEL); /* 使用"3要素设置urb" */ usb_fill_int_urb(uk_urb, dev, pipe, usb_buf, len, usbmouse_irq, NULL, endpoint->bInterval); uk_urb->transfer_dma = usb_buf_phys; uk_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; /* 使用URB */ usb_submit_urb(uk_urb, GFP_KERNEL); return 0; } 复制代码
当中还要对
usbmouse_irq函数做处理,咋一看是中断函数,其实不是中断,因为USB通信是主从关系,从机设备是没有主动打断主机的能力,只有主机查询,而主机有USB专门的控制器,由它查询,查询到不同就会给CPU中断,这个一定要理解。
static void usbmouse_as_key_irq(struct urb *urb)
{
static unsigned char pre_val;
int i;
static int cnt = 0;
printk("data cnt %d: ", ++cnt);
for (i = 0; i < len; i++)
{
printk("%02x ", usb_buf);
} printk("\n"); } 这样算是最简单的USB鼠标驱动程序了,把原先的鼠标驱动程序在内核里去掉,make menuconfig,就OK了 重新烧写或者网络升级,加载这个最简单的驱动程序,插上鼠标,移动,按下左右键 知道这些数值的意义,就很好办事了,这个最简单的USB驱动程序,只不过是内核的自娱自乐罢了,真正要让鼠标有意义起来就得让应用层知道啊,那就要使用输入子系统了,而输入子系统做过记录,就不在累述,输入子系统就几个步骤 1,分配一个input_dev 2,设置能产生哪类事件还有这类事件的哪些事件(有点绕口) 3,注册 4,在对应的“中断程序”里,上报事件, 在函数外定义 static struct input_dev *uk_dev; //全局使用 在probe函数里添加 /* 分配一个input_dev */ uk_dev = input_allocate_device(); uk_dev ->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); uk_dev ->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE); uk_dev ->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y); uk_dev ->keybit[BIT_WORD(BTN_MOUSE)] |= BIT_MASK(BTN_SIDE) | BIT_MASK(BTN_EXTRA); uk_dev ->relbit[0] |= BIT_MASK(REL_WHEEL); /* 注册 */ input_register_device(uk_dev); 在对应的“中断程序”里添加 上报事件
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_report_key(uk_dev, BTN_LEFT, usb_buf[1] & 0x01); input_report_key(uk_dev, BTN_RIGHT, usb_buf[1] & 0x02); input_report_key(uk_dev, BTN_MIDDLE, usb_buf[1] & 0x04); input_report_key(uk_dev, BTN_SIDE, usb_buf[1] & 0x08); input_report_key(uk_dev, BTN_EXTRA, usb_buf[1] & 0x10); input_report_rel(uk_dev, REL_X, usb_buf[3]); input_report_rel(uk_dev, REL_Y, usb_buf[4]); input_report_rel(uk_dev, REL_WHEEL, usb_buf[2]); input_sync(dev); 复制代码
重新编译,重新加载,而这里特别要注意usb_buf数组里的值与鼠标的操作一定要对应起来,这个需要自己测出来(在一张图片里可以看到)。
插上鼠标,能移动,有反应,拔掉,又插上,没有问题(有问题,操作不正当,就看看数组里的值是不是对应的),这才像usb鼠标嘛
最后,官方有这个鼠标完整的例子,在/drivers/hid/usbhid/usbmouse.c,要注意,data数组里的值是不是对应的。
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】 进行投诉反馈!