JZ2440开发板学习------中级(二十五:下)
2019-07-12 14:24发布
生成海报
自己写驱动程序之USB
对于自己要写的每个驱动程序都要借鉴与内核,内核是一个非常丰富的代码库。里面有丰富的例子。我们要写的驱动程序与鼠标有关,所以就参照内核提供的驱动程序吧:
第一步:程序大框
从usbmouse.c大体的程序可以看出,它主要是写设备,驱动涉及的比较少。我们要使其能够正常运行就需要将驱动补充一下!驱动的写法大体都是一样的啦:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//#include //POWER Manager
#include
#include
#include
#include
#include
#include
#include
#include
#include
static int usbmouse_init(void)
{
return 0;
}
static void usbmouse_exit(void)
{
}
module_init(usbmouse_init);
module_exit(usbmouse_exit);
MODULE_LICENSE("GPL");
第二步:完善初始化函数init()
从usb_driver中尝试猜测有没有usb_register,通过搜索,在driversisdngigasetBas-gigaset.c中我们查到了使用方法:
usb_register(&gigaset_usb_driver);
所以在init()里只需要写: usb_register(&usbmouse_driver);
再从usbmouse.c中找到usbmouse_driver类似的结构体:
static struct usb_driver usbmouse_driver = {
.name = "usbmouse",
.probe = usbmouse_probe,
.disconnect = usbmouse_disconnect,
.id_table = usbmouse_id_table,
};
第三步:完善usbmouse_driver中的函数:
第一挑简单的哦,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 */
};
第二直接probe啦,虽然比较难,首先将通用的留下:
struct input_dev *mouse_dev;
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, len;
interface = intf->cur_altsetting;
endpoint = &interface->endpoint[0].desc;
}
其次:
因为usb也是属于input结构体写法的一种,所以按照:
1. 分配一个input_dev结构体
2. 能产生哪类事件
3. 能产生这类操作里的哪些事件:
4. 注册
5. 硬件操作作zuo
mouse_dev = input_allocate_device();
mouse_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
set_bit(KEY_L, mouse_dev->keybit);
set_bit(KEY_S, mouse_dev->keybit);
set_bit(KEY_ENTER, mouse_dev->keybit);
input_register_device(mouse_dev);
/* 数据传输3要素: 源,目的,长度 */
/* 源: USB设备的某个端点 */
pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
/* 长度: */
len = endpoint->wMaxPacketSize; //注释1
/* 目的: */
mouse->data = usb_alloc_coherent(dev, 8, GFP_ATOMIC, &mouse->data_dma);
搜索mouse中发现data为:
struct usb_mouse {
char name[128];
char phys[64];
struct usb_device *usbdev;
struct input_dev *dev;
struct urb *irq;
signed char *data;
dma_addr_t data_dma;
};
所以我们定义相同的东东:
static signed char *usb_data;
static dma_addr_t data_dma;
之后:
usb_data = usb_alloc_coherent(dev, len, GFP_ATOMIC, &data_dma);
/* 使用"3要素" */
/* 分配usb request block */
根据mouse->irq = usb_alloc_urb(0, GFP_KERNEL);定义相同的东东:
static struct urb *urb_irq;
urb_irq = usb_alloc_urb(0, GFP_KERNEL);
/* 使用"3要素设置urb" */
usb_fill_int_urb(urb_irq, dev, pipe, usb_data, len,
usb_mouse_irq, NULL, endpoint->bInterval);
urb_irq->transfer_dma = data_dma;
urb_irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
/* 使用URB */
在usbmouse.c的probe函数中:
input_dev->open = usb_mouse_open;
static int usb_mouse_open(struct input_dev *dev)
{
struct usb_mouse *mouse = input_get_drvdata(dev);
mouse->irq->dev = mouse->usbdev;
if (usb_submit_urb(mouse->irq, GFP_KERNEL))
return -EIO;
return 0;
}
加粗部分就是在使用urb:
usb_submit_urb(urb_irq, GFP_KERNEL);
return 0;
第三:完成usbmouse_disconnect()函数哦!
static void usb_mouse_disconnect(struct usb_interface *intf)
{
struct usb_device *dev = interface_to_usbdev(intf);
usb_kill_urb(urb_irq);
input_unregister_device(mouse_dev);
input_free_device(mouse_dev);
usb_free_urb(urb_irq);
usb_free_coherent(dev, len, usb_data, data_dma);
}
方法是一样的,参考,裁剪!
第四步:完善usb_mouse_irq
在usb_fill_int_urb(urb_irq, dev, pipe, usb_data, len,
usb_mouse_irq, NULL, endpoint->bInterval);
之中有个函数我们没有实现:usb_mouse_irq:
通过参考,裁剪之后的代码如下:
static void usb_mouse_irq(struct urb *urb)
{
int status;
input_sync(mouse_dev);
usb_submit_urb (urb_irq, GFP_ATOMIC);
}
通过input_sync(mouse_dev);让我们想起之前写触摸屏的时候,具体见下链接:
http://blog.csdn.net/ziyedianyuxiao/article/details/41554055
我们找到了:
if(pinval)// 1按下
{
input_event(buttons_dev, EV_KEY, pindesc->key_val, 0);
input_sync(buttons_dev); //见注释4
}
else
{
input_event(buttons_dev,EV_KEY, pindesc->key_val, 1);
input_sync(buttons_dev);
}
我们知道input_event的作用是在中断函数或者工作队列中调用input_event上报事件,观察其函数内部我们可以发现,涉及按键的时候可以使用input_event来上报:
static void usb_mouse_irq(struct urb *urb)
{
static unsigned char status;
/* USB鼠标数据含义
* data[0]: bit0-左键, 1-按下, 0-松开
* bit1-右键, 1-按下, 0-松开
* bit2-中键, 1-按下, 0-松开
*
*/
if ((status l & (1<<0)) != (usb_data[0] & (1<<0)))
{
/* 左键发生了变化 */
input_event(mouse_dev, EV_KEY, KEY_L, (usb_data[0] & (1<<0)) ? 1 : 0);
input_sync(mouse_dev);
}
if ((status l & (1<<1)) != (usb_data[0] & (1<<1)))
{
/* 右键发生了变化 */
input_event(mouse_dev, EV_KEY, KEY_S, (usb_data[0] & (1<<1)) ? 1 : 0);
input_sync(mouse_dev);
}
if ((status l & (1<<2)) != (usb_data[0] & (1<<2)))
{
/* 中键发生了变化 */
input_event(mouse_dev, EV_KEY, KEY_ENTER, (usb_data[0] & (1<<2)) ? 1 : 0);
input_sync(mouse_dev);
}
status = usb_data[0];
/* 重新提交urb */
usb_submit_urb (urb_irq, GFP_ATOMIC);
}
第五步:完善usbmouse_exit
static void usbmouse_exit(void)
{
usb_deregister(&usbmouse_driver);
}
完整代码如下:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//#include //POWER Manager
#include
#include
#include
#include
#include
#include
#include
#include
#include
struct input_dev *mouse_dev;
static signed char *usb_data;
static dma_addr_t data_dma;
static struct urb *urb_irq;
static int len;
static void usb_mouse_irq(struct urb *urb)
{
static unsigned char status;
/* USB鼠标数据含义
* data[0]: bit0-左键, 1-按下, 0-松开
* bit1-右键, 1-按下, 0-松开
* bit2-中键, 1-按下, 0-松开
*
*/
if ((status & (1<<0)) != (usb_data[0] & (1<<0)))
{
/* 左键发生了变化 */
input_event(mouse_dev, EV_KEY, KEY_L, (usb_data[0] & (1<<0)) ? 1 : 0);
input_sync(mouse_dev);
}
if ((status & (1<<1)) != (usb_data[0] & (1<<1)))
{
/* 右键发生了变化 */
input_event(mouse_dev, EV_KEY, KEY_S, (usb_data[0] & (1<<1)) ? 1 : 0);
input_sync(mouse_dev);
}
if ((status & (1<<2)) != (usb_data[0] & (1<<2)))
{
/* 中键发生了变化 */
input_event(mouse_dev, EV_KEY, KEY_ENTER, (usb_data[0] & (1<<2)) ? 1 : 0);
input_sync(mouse_dev);
}
status = usb_data[0];
/* 重新提交urb */
usb_submit_urb (urb_irq, GFP_ATOMIC);
}
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;
mouse_dev = input_allocate_device();
mouse_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
set_bit(KEY_L, mouse_dev->keybit);
set_bit(KEY_S, mouse_dev->keybit);
set_bit(KEY_ENTER, mouse_dev->keybit);
input_register_device(mouse_dev);
pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
len = endpoint->wMaxPacketSize;
usb_data = usb_alloc_coherent(dev, len, GFP_ATOMIC, &data_dma);
urb_irq = usb_alloc_urb(0, GFP_KERNEL);
usb_fill_int_urb(urb_irq, dev, pipe, usb_data, len,
usb_mouse_irq, NULL, endpoint->bInterval);
urb_irq->transfer_dma = data_dma;
urb_irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
usb_submit_urb(urb_irq, GFP_KERNEL);
return 0;
}
static void usbmouse_disconnect(struct usb_interface *intf)
{
struct usb_device *dev = interface_to_usbdev(intf);
usb_kill_urb(urb_irq);
input_unregister_device(mouse_dev);
input_free_device(mouse_dev);
usb_free_urb(urb_irq);
usb_free_coherent(dev, len, usb_data, data_dma);
}
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 */
};
static struct usb_driver usbmouse_driver = {
.name = "usbmouse",
.probe
= usbmouse_probe,
.disconnect
= usbmouse_disconnect,
.id_table
= usbmouse_id_table,
};
static int usbmouse_init(void)
{
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");
编译结果:
**************************************************************************************************************************************************************************************************************************************
http://www.cnblogs.com/image-eye/archive/2011/08/24/2152446.html
注释1:
在usbmouse.c中:
maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); //取得端点所支持的最大数据数
从这一点可以看出它的意思应该与长度是等效的:len = endpoint->wMaxPacketSize;
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮