自己板子是插上鼠标后,没有反应,只有在插上鼠标,板子重新上电,鼠标才有作用,这实在是不解,好像板子是有鼠标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结构体
USB设备驱动的匹配之通过id_table,和platfrom平台驱动匹配方式(设备名字匹配的)不同,这里是想匹配鼠标,所以在id_table 里添加
这样,usb总线驱动识别出了鼠标,id_table匹配上了,就会调用相应的probe函数
在函数之外定义几个结构体,做全局调用
当中还要对 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);
在对应的“中断程序”里添加 上报事件
重新编译,重新加载,而这里特别要注意usb_buf数组里的值与鼠标的操作一定要对应起来,这个需要自己测出来(在一张图片里可以看到)。 插上鼠标,能移动,有反应,拔掉,又插上,没有问题(有问题,操作不正当,就看看数组里的值是不是对应的),这才像usb鼠标嘛
最后,官方有这个鼠标完整的例子,在/drivers/hid/usbhid/usbmouse.c,要注意,data数组里的值是不是对应的。
插上鼠标,终端打印了这些话,
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结构体
USB设备驱动的匹配之通过id_table,和platfrom平台驱动匹配方式(设备名字匹配的)不同,这里是想匹配鼠标,所以在id_table 里添加
这样,usb总线驱动识别出了鼠标,id_table匹配上了,就会调用相应的probe函数
在函数之外定义几个结构体,做全局调用
当中还要对 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);
在对应的“中断程序”里添加 上报事件
重新编译,重新加载,而这里特别要注意usb_buf数组里的值与鼠标的操作一定要对应起来,这个需要自己测出来(在一张图片里可以看到)。 插上鼠标,能移动,有反应,拔掉,又插上,没有问题(有问题,操作不正当,就看看数组里的值是不是对应的),这才像usb鼠标嘛
最后,官方有这个鼠标完整的例子,在/drivers/hid/usbhid/usbmouse.c,要注意,data数组里的值是不是对应的。