usb.c源码:
// 参考drivers/hid/usbhid/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"
#include "linux/input.h"
static struct input_dev *mk_dev;
static int len;
static char *buf;
static dma_addr_t buf_phys;
static struct urb *mk_urb;
static struct usb_device_id usb_mk_id_table [] = {
{ USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
USB_INTERFACE_PROTOCOL_MOUSE) },
//{USB_DEVICE(0x46d, 0xc52f)},
{ } // Terminating entry
};
// 当USB主机控制器获得鼠标数据后,
// 会调用这个函数
static void uk_callback(struct urb *urb)
{
int i;
static char pre_val;
#if 0
printk("Get datas:\n");
for (i = 0; i < len; i++)
{
printk("x ", buf[i]);
}
printk("\n");
#endif
// 鼠标数据含义:
// buf[0]: bit0-左键, 0-松开, 1-按下
// bit1-右键, 0-松开, 1-按下
// bit2-中键, 0-松开, 1-按下
// buf[1],buf[2]构成一个整数, 表示X方向的相对位移
// >0 : 右移
// <0 : 左移
// buf[3],buf[4]构成一个整数, 表示Y方向的相对位移
// >0 : 下移
// <0 : 上移
// buf[6]: 滚轮
// 确定按键值
// 上报数据
if ((pre_val & (1<<0)) != (buf[0] & (1<<0)))
{
// 左键按下或松开
input_event(mk_dev, EV_KEY, KEY_L, (buf[0] & (1<<0)) ? 1 : 0);
input_sync(mk_dev);
}
if ((pre_val & (1<<1)) != (buf[0] & (1<<1)))
{
// 右键按下或松开
input_event(mk_dev, EV_KEY, KEY_S, (buf[0] & (1<<1)) ? 1 : 0);
input_sync(mk_dev);
}
if ((pre_val & (1<<2)) != (buf[0] & (1<<2)))
{
// 中键按下或松开
input_event(mk_dev, EV_KEY, KEY_ENTER, (buf[0] & (1<<2)) ? 1 : 0);
input_sync(mk_dev);
}
pre_val = buf[0];
// 重新提交URB
usb_submit_urb(mk_urb, GFP_KERNEL);
}
static int usb_mk_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;
static int first = 1;
if (!first)
return -EIO;
first = 0;
// 每一个设备都有端点0
// interface->endpoint[]数组里放"除了端点0外的其他端点"
// interface->endpoint[0]表示"除端点0外的第1个端点"
// interface->endpoint[1]表示"除端点0外的第2个端点"
interface = intf->cur_altsetting;
endpoint = &interface->endpoint[0].desc;
// 1. 分配inputd_dev
mk_dev = input_allocate_device();
// 2. 设置
// 2.1 能产生哪类事件
set_bit(EV_KEY, mk_dev->evbit);
set_bit(EV_REP, mk_dev->evbit);
// 2.2 能产生这类事件里的哪些事件
set_bit(KEY_L, mk_dev->keybit);
set_bit(KEY_S, mk_dev->keybit);
set_bit(KEY_ENTER, mk_dev->keybit);
// 3. 注册
input_register_device(mk_dev);
// 4. 硬件相关的操作:
// 对于GPIO按键, 是request_irq, 在中断处理函数里上报按键
// 对于USB设备, 是使用"USB主机驱动程序提供的函数"发起USB传输获得数据
// 数据传输3要素: 源, 目的, 长度
// A. 源: USB设备的某个端点
// ((PIPE_INTERRUPT << 30) | (dev->devnum << 8) | (endpoint << 15) | USB_DIR_IN)
pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
// C. 长度: 这个端点描述符的wMaxPacketSize
len = endpoint->wMaxPacketSize;
// B. 目的: 分配buffer
buf = usb_buffer_alloc(dev, len, GFP_ATOMIC, &buf_phys);
// D. 怎么使用这3要素 ?
// 分配URB: USB Reqeust Block
mk_urb = usb_alloc_urb(0, GFP_KERNEL);
// 用3要素填充URB
usb_fill_int_urb(mk_urb, dev, pipe, buf, len, uk_callback, NULL, endpoint->bInterval);
mk_urb->transfer_dma = buf_phys;
mk_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
// 使用URB
usb_submit_urb(mk_urb, GFP_KERNEL);
return 0;
}
static void usb_mk_disconnect(struct usb_interface *intf)
{
struct usb_device *dev = interface_to_usbdev(intf);
printk("disconnect usb mouse!!!!!\n");
usb_kill_urb(mk_urb);
usb_free_urb(mk_urb);
usb_buffer_free(dev,len, buf, buf_phys);
input_unregister_device(mk_dev);
input_free_device(mk_dev);
}
// 1. 分配usb_driver
// 2. 设置
static struct usb_driver usb_mk_driver = {
.name = "usbmk",
.probe = usb_mk_probe,
.disconnect = usb_mk_disconnect,
.id_table = usb_mk_id_table,
};
static int usb_mk_init(void)
{
// 3. 注册
usb_register(&usb_mk_driver);
return 0;
}
static void usb_mk_exit(void)
{
usb_deregister(&usb_mk_driver);
}
module_init(usb_mk_init);
module_exit(usb_mk_exit);
MODULE_LICENSE("GPL");
=====================================================================
Makefile文件:
KERN_DIR = /home/linux/linux-3.0.1
all:
make -C $(KERN_DIR) M=`pwd` modules
clean:
make -C $(KERN_DIR) M=`pwd` modules clean
rm -rf modules.order
obj-m += usb.o
=====================================================================
测试部分参考:JZ2440的USB设备驱动程序
上一篇:OK6410块设备驱动之用内存模拟磁盘
下一篇:OK6410分层分离(总线-驱动-设备模型)
推荐阅读最新更新时间:2024-03-16 16:15