S3C JZ2440 USB 驱动程序完整

/* 参考例子:drivers\hid\usbhid\usbmouse.c
 * 功能:完整的USB驱动程序
 *
 * 2016年6月23日21:37:10
 */


#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 input_dev * uk_dev;
static char * usb_buf;//虚拟地址
static dma_addr_t usb_buf_phys;//物理地址
static struct urb *uk_urb;
static int len;


static void usbmouse_as_key_irq(struct urb *urb)
{
static unsigned char pre_val;
#if 0
int i;
static int cnt = 0;
printk("data cnt &d:",++cnt);

for(i = 0;i < len; i++)
{
printk("%02x",usb_buf[i]);
}

printk("\n");


#endif


/* USB鼠标数据的含义
* data[0]: bit0-左键,1-按下,0-松开
*   : bit1-右键,1-按下,0-松开
*   : bit2-中键,1-按下,0-松开
*/


if(pre_val & (1<<0) != usb_buf[0] & (1<<0))
{
/*左键发生变化*/
input_event(uk_dev,EV_KEY,KEY_L,(usb_buf[0] & (1<<0)) ? 1 : 0);
input_sync(uk_dev);


}


if(pre_val & (1<<1) != usb_buf[0] & (1<<1))
{
/*左键发生变化*/
input_event(uk_dev,EV_KEY,KEY_S,(usb_buf[0] & (1<<1)) ? 1 : 0);
input_sync(uk_dev);


}


if(pre_val & (1<<2) != usb_buf[0] & (1<<2))
{
/*左键发生变化*/
input_event(uk_dev,EV_KEY,KEY_ENTER,(usb_buf[0] & (1<<2)) ? 1 : 0);
input_sync(uk_dev);


}


/*记录上一个值*/
pre_val = usb_buf[0];



/* 重新提交urb */
usb_submit_urb(uk_urb, GFP_KERNEL);
}






/* USB_DEVICE 宏进行分析
 * #define USB_DEVICE(vend,prod) \
 * .match_flags = USB_DEVICE_ID_MATCH_DEVICE, .idVendor = (vend), \
 * .idProduct = (prod)
 *
 * 该宏定义支持的厂家ID,和设备ID
 */
 
/* USB_INTERFACE_INFO宏分析:
 * #define USB_INTERFACE_INFO(cl,sc,pr) \
 * .match_flags = USB_DEVICE_ID_MATCH_INT_INFO, .bInterfaceClass = (cl), \
 * .bInterfaceSubClass = (sc), .bInterfaceProtocol = (pr)
 *
 * 
 * match_flags:表示匹配这个设备描述符里面的哪一项,
 * USB_DEVICE_ID_MATCH_INT_INFO表示匹配接口信息(接口的信息在接口描述符里),
 * 只要接口描述符里面的接口类.bInterfaceClass是cl(什么东西),
 * 接口描述符里的接口子类.bInterfaceSubClass是sc(什么东西),
 * 接口描述符里的协议.bInterfaceProtocol是pr(什么东西),就能支持
 */




/* 只要usb设备的接口描述符里的类是HID类,子类是BOOT,协议是MOUSE就能支持
 *
 */
static struct usb_device_id usbmouse_as_key_id_table [] = {
{ USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
USB_INTERFACE_PROTOCOL_MOUSE) },
/*该宏的定义指定了usb设备驱动程序只支持某个厂家生产(0x1234)的某款产品(0x5678)*/
// {USB_DEVICE(0x1234,0x5678)}, 
{ } /* Terminating entry */
};




/*注册驱动后,usb_bus_type中的match函数把usb_interface和usb_driver的id_table比较
 * 若能匹配成功,则调用usb_driver中的usbmouse_as_key_probe函数。
 */
static int usbmouse_as_key_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
/*通过接口得到usb_device结构体*/
struct usb_device *dev = interface_to_usbdev(intf);
struct usb_host_interface *interface;
struct usb_endpoint_descriptor *endpoint;
/*获取usb接口结构体中的usb_host接口结构体*/
interface = intf->cur_altsetting;
/*获取usb_host接口结构体中的端点描述结构体*/
endpoint = &interface->endpoint[0].desc;


int pipe 


/*a.分配一个input_dev结构体*/
uk_dev = input_allocate_device();
/*b.设置*/
/*b.1能产生哪类事件*/
set_bit(EV_KEY,uk_dev->evbit);
set_bit(EV_REP,uk_dev->evbit);
/*b.2能产生哪些事件*/
set_bit(KEY_L,uk_dev->keybit);
set_bit(KEY_S,uk_dev->keybit);
set_bit(KEY_ENTER,uk_dev->keybit);


/*c.注册*/
input_register_device(uk_dev);

/*d.硬件相关的操作*/
/*数据传输三要素:源,长度,目的*/


/* 源:usb设备的某个端点
* 把指定usb设备的指定端口设置为一个控制IN端点
* 创建管道,用于连接驱动程序缓冲区和设备端口
*/
pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);


/*长度:
* 是端点描述符里面的最大包大小
*/
len = endpoint->wMaxPacketSize;
/* 目的:
* 这就是驱动程序缓冲区了,usb_buffer_alloc函数同时分配物理地址和虚拟地址,
* 当usb主机控制器查询到有数据时,会将数据存放到usb_buf_phys缓冲区中,
*/
 
usb_buf = usb_buffer_alloc(dev, len, GFP_ATOMIC, &usb_buf_phys);


/*使用三要素:*/


/* URB处理流程:
* (1)USB设备驱动程序创建并初始化一个访问特定USB设备特定端点的urb,并提交给USB core
* (2)USR core提交该urb到到USB总线驱动程序。
* (3)USB总线驱动程序根据该urb描述的信息,来访问usb设备
* (4)当设备访问结束后,USB总线驱动程序通知USB设备驱动程序。
*
*/

/* 分配usb request block */
uk_urb = usb_alloc_urb(0, GFP_KERNEL);

/* 使用"3要素设置urb" 
* 设置urb请求块,可以通过设置它来控制驱动程序与设备端点之间的通信
*
* usb主机控制器不断查询usb设备有无数据,当usb主机控制器查询到有数据时,
* 会将数据存放到usb_buf_phys缓冲区中,
* 会产生一个中断,usb总线驱动程序就会调用usb_fill_int_urb函数中的complete_fn(完成)函数。
* endpoint->bInterval是usb主机控制器查询usb设备的频率。
*/
//中断类型
usb_fill_int_urb(uk_urb, dev, pipe, usb_buf,len,usbmouse_as_key_irq, NULL, endpoint->bInterval);


/* usb主机控制器得到数据后,要往哪个物理地址写入数据
* 如果要操作读取的数据的话,则要用虚拟地址
*/
uk_urb->transfer_dma = usb_buf_phys;
/*设置某些标记*/
uk_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
/* 使用urb
* 提交urb给usb总线驱动程序驱动
*/
usb_submit_urb(uk_urb, GFP_KERNEL);
return 0;


}


/*拔掉usb设备后,则执行usbmouse_as_key_disconnect函数*/
static void usbmouse_as_key_disconnect(struct usb_interface *intf)
{
// printk("disconnect usbmouse!");


usb_kill_urb(uk_urb);
usb_free_urb(uk_urb);
usb_buffer_free(dev, len, usb_buf, usb_buf_phys);
input_unregister_device(uk_dev);
input_free_device(uk_dev);
}
}




/*分配/设置usb_driver结构体*/
static struct usb_driver usbmouse_as_key_driver = {
.name = "usbmouse_as_key",
.probe = usbmouse_as_key_probe,
.disconnect = usbmouse_as_key_disconnect,
.id_table = usbmouse_as_key_id_table,
};


static int usbmouse_as_key_init(void)
{
/*注册*/
usb_register(&usbmouse_as_key_driver);
return 0;


}


static void usbmouse_as_key_exit(void)
{
/*卸载*/
usb_deregister(&usbmouse_as_key_driver);
}


module_init(usbmouse_as_key_init);
module_exit(usbmouse_as_key_exit);
MODULE_LICENSE("GPL");
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值