×
单片机 > 单片机程序设计 > 详情

OK6410之USB设备驱动程序

发布时间:2020-06-16 发布时间:
|

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  USB设备  驱动程序 

『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
单片机的抗干扰措施有哪些