一、实验平台:开发板fs2410,采用三星s3c2410的CPU,linux操作系统。
二、实现功能:用USB鼠标模拟按键输入,按键左键输入l,按下右键输入s,按下中键为回车,并在LCD屏幕上显示文件信息。
三、实验原理:
在linux内核中有USB总线驱动程序,当有USB设备插入时,USB总线驱动程序会检测到该设备,并创建一个struct usb_device结构体,并寻找匹配的驱动程序。
这里我们只写USB设备驱动程序,使用总线驱动程序的一些函数来获得数据。获取数据后再将这些数据赋予一定的意义(比如右键为s等),再上报给输入子系统。
四、实验现象:
加载模块后,插入USB鼠标,可以看到有检测到设备的提示信息。再按下鼠标左键、右键,LCD屏幕上出现ls,再按鼠标中键,LCD屏幕上显示文件信息。
五、实验总结:
USB鼠标也是输入设备,与案件不同的是数据来源。USB鼠标的数据来源是USB总线,而按键的数据来源就是s3c2410的GPIO管脚。得到数据后,写代码的思路和步骤与按键驱动的后部分一样。
USB设备的数据的传送是通过中断的方式告诉CPU的,而实际上是采用查询的方式,因为所有USB设备都没有主动发送数据的功能,只有USB主机要接收数据时,USB设备才被动发送数据。USB控制器负责了查询了工作,它会对USB设备不断的查询,当获取了有效数据后,USB控制器产生中断告诉CPU有了数据。
六、示例代码:
/*驱动代码usbmouse.c*/
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/usb/input.h>
#include <linux/hid.h>
static struct usb_device_id uk_id_table [] = {
{USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
USB_INTERFACE_PROTOCOL_MOUSE)},
{ } /* Terminating entry */
};
static struct input_dev *uk_dev;
static unsigned char *buf;
static unsigned long buf_phys;
static struct urb *uk_urb;
static void uk_irq(struct urb *urb)
{
static int cnt = 0;
int i;
static unsigned char pre_val;
if ((pre_val & (1<<0)) != (buf[0] & (1<<0)))
{
input_event(uk_dev, EV_KEY, KEY_L, (buf[0] & (1<<0)) ? 1 : 0);
}
if ((pre_val & (1<<1)) != (buf[0] & (1<<1)))
{
input_event(uk_dev, EV_KEY, KEY_S, (buf[0] & (1<<1)) ? 1 : 0);
}
if ((pre_val & (1<<2)) != (buf[0] & (1<<2)))
{
input_event(uk_dev, EV_KEY, KEY_ENTER, (buf[0] & (1<<2)) ? 1 : 0);
}
if (pre_val != buf[0])
input_sync(uk_dev);
pre_val = buf[0];
usb_submit_urb (uk_urb, GFP_ATOMIC);
}
static int uk_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;
int len;
interface = intf->cur_altsetting;
endpoint = &interface->endpoint[0].desc;
uk_dev = input_allocate_device();
__set_bit(EV_KEY, uk_dev->evbit);
__set_bit(EV_REP, uk_dev->evbit);
__set_bit(KEY_L, uk_dev->keybit);
__set_bit(KEY_S, uk_dev->keybit);
__set_bit(KEY_ENTER, uk_dev->keybit);
input_register_device(uk_dev);
pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
buf = usb_buffer_alloc(dev, 4, GFP_ATOMIC, &buf_phys);
len = 4;
uk_urb = usb_alloc_urb(0, GFP_KERNEL);
usb_fill_int_urb(uk_urb, dev, pipe, buf,len,uk_irq, NULL, endpoint->bInterval);
uk_urb->transfer_dma = buf_phys;
uk_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
usb_submit_urb(uk_urb, GFP_KERNEL);
return 0;
}
static void uk_disconnect (struct usb_interface *intf)
{
struct usb_device *dev = interface_to_usbdev(intf);
input_unregister_device(uk_dev);
input_free_device(uk_dev);
usb_kill_urb(uk_urb);
usb_buffer_free(dev, 4, buf, buf_phys);
usb_free_urb(uk_urb);
}
static struct usb_driver usbmouse_key_drv = {
.name = "usbmouse_key",
.id_table = uk_id_table,
.probe = uk_probe,
.disconnect = uk_disconnect,
};
static int usbmouse_as_key_init(void)
{
usb_register(&usbmouse_key_drv);
return 0;
}
static void usbmouse_as_key_exit(void)
{
usb_deregister(&usbmouse_key_drv);
}
module_init(usbmouse_as_key_init);
module_exit(usbmouse_as_key_exit);
MODULE_LICENSE("GPL");