JZ2440开发板学习------中级(二十五:下)

来源:互联网 发布:战争知乎 编辑:程序博客网 时间:2024/05/20 18:41

自己写驱动程序之USB
    对于自己要写的每个驱动程序都要借鉴与内核,内核是一个非常丰富的代码库。里面有丰富的例子。我们要写的驱动程序与鼠标有关,所以就参照内核提供的驱动程序吧:
第一步:程序大框
从usbmouse.c大体的程序可以看出,它主要是写设备,驱动涉及的比较少。我们要使其能够正常运行就需要将驱动补充一下!驱动的写法大体都是一样的啦:
#include <linux/module.h>
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <linux/irq.h>
#include <asm/io.h>
#include <mach/regs-gpio.h>
#include <mach/hardware.h>
#include <mach/irqs.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/gpio.h>
#include <linux/device.h>
#include <linux/input.h>
#include <linux/platform_device.h>
#include <linux/errno.h>
#include <linux/fb.h>
#include <mach/fb.h>
#include <mach/regs-lcd.h>
#include <linux/dma-mapping.h>
//#include <linux/pm.h>  //POWER Manager 
#include <asm/gpio.h>
#include <linux/clk.h>
#include <asm/irq.h>
#include <plat/ts.h>
#include <plat/regs-adc.h>
#include <linux/serio.h>


#include <linux/slab.h>
#include <linux/usb/input.h>
#include <linux/hid.h>
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,通过搜索,在drivers\isdn\gigaset\Bas-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 <linux/module.h>
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <linux/irq.h>
#include <asm/io.h>
#include <mach/regs-gpio.h>
#include <mach/hardware.h>


#include <mach/irqs.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/gpio.h>


#include <linux/device.h>
#include <linux/input.h>
#include <linux/platform_device.h>


#include <linux/errno.h>
#include <linux/fb.h>
#include <mach/fb.h>
#include <mach/regs-lcd.h>
#include <linux/dma-mapping.h>
//#include <linux/pm.h>  //POWER Manager 
#include <asm/gpio.h>


#include <linux/clk.h>
#include <asm/irq.h>
#include <plat/ts.h>
#include <plat/regs-adc.h>
#include <linux/serio.h>


#include <linux/slab.h>
#include <linux/usb/input.h>
#include <linux/hid.h>


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; 




0 0
原创粉丝点击