Linux USB Joystick游戏杆驱动

//驱动代码(中断传输)
#include <linux/kernel.h>   
#include <linux/errno.h>   
#include <linux/init.h>   
#include <linux/slab.h>   
#include <linux/module.h>   
#include <linux/kref.h>   
#include <linux/uaccess.h>   
#include <linux/usb.h>   
#include <linux/mutex.h>   
// Define these values to match your devices   
//joystick: VENDOR_ID 0x0E8F, PRODUCT_ID 0X0002   
//icbc: VENDOR_ID 0x096E, PRODUCT_ID 0X0010   
#define USB_JOYSTICK_VENDOR_ID  0x10c4   
#define USB_JOYSTICK_PRODUCT_ID 0x0000   
/* table of devices that work with this driver */  
static struct usb_device_id joystick_table[] = {  
    { USB_DEVICE(USB_JOYSTICK_VENDOR_ID, USB_JOYSTICK_PRODUCT_ID) },  
    { }                 /* Terminating entry */  
};  
MODULE_DEVICE_TABLE(usb, joystick_table);  
//masks for each key, see file KEY_MASK for more details   
#define KEYMASK_UP      0x00   
#define KEYMASK_DOWN    0xFF   
#define KEYMASK_LEFT    0x00   
#define KEYMASK_RIGHT   0xFF   
#define KEYMASK_L1      0x01   
#define KEYMASK_L2      0x04   
#define KEYMASK_R1      0x02   
#define KEYMASK_R2      0x08   
#define KEYMASK_Y       0x1F   
#define KEYMASK_A       0x4F   
#define KEYMASK_X       0x8F   
#define KEYMASK_B       0x2F   
#define KEYMASK_SELECT  0x10   
#define KEYMASK_START   0x20   
#define INTERV_MILLI(ms)    (ms*HZ/1000)   
static struct fasync_struct *fasync_queue;  
static char *gb_data;  
// Get a minor range for your devices from the usb maintainer   
#define USB_JOYSTICK_MINOR_BASE 192   
// Structure to hold all of our device specific stuff   
struct usb_joystick {  
    struct usb_device       *udev;          /* the usb device for this device */  
    struct usb_interface    *interface;     /* the interface for this device */  
    struct semaphore        limit_sem;      /* limiting the number of writes in progress */  
    struct urb              *in_urb;        /* the urb to read data with */  
    unsigned char           *in_buffer; /* the buffer to receive data */  
    size_t                  in_buffer_size;     /* the size of the receive buffer */  
    char                    *data;  
    dma_addr_t              data_dma;  
    __u8                    in_endpointAddr;    /* the address of the bulk in endpoint */  
    __u8                    out_endpointAddr;   /* the address of the bulk out endpoint */  
    struct kref             kref;  
};  
static int joystick_fasync(int fd, struct file *file, int on);  
static int joystick_open(struct inode *inode, struct file *file)  
{  
    printk("joystick open.\n");  
    return 0;  
}  
static int joystick_release(struct inode *inode, struct file *file)  
{  
    printk("joystick release.\n");  
    joystick_fasync(-1, file, 0);  
    return 0;  
}  
static ssize_t joystick_read(struct file *file, char *buf, size_t count, loff_t *ppos)  
{  
    printk("joystick read.\n");   
    copy_to_user(buf, gb_data, 8);  
    return 0;  
}  
static ssize_t joystick_write(struct file *file, const char *buf, size_t count, loff_t *ppos)  
{  
    printk("joystick write.\n");  
    return 0;  
}  
static int joystick_fasync(int fd, struct file *file, int on)  
{  
    int retval;  
    printk("joystick fasynchronize.\n");  
    retval = fasync_helper(fd, file, on, &fasync_queue);  
    return retval;  
}  
static const struct file_operations joystick_fops = {  
    .owner      =       THIS_MODULE,  
    .open       =       joystick_open,  
    .release    =       joystick_release,  
    .read       =       joystick_read,  
    .write      =       joystick_write,  
    .fasync     =       joystick_fasync,  
};  
static void joystick_irq(struct urb *urb)  
{  
    struct usb_joystick *js_dev = urb->context;  
    char *data;  
    static unsigned long jiff_UP = 0;  
    static unsigned long jiff_DOWN = 0;  
    static unsigned long jiff_LEFT = 0;  
    static unsigned long jiff_RIGHT = 0;  
    static unsigned long jiff_Y = 0;  
    static unsigned long jiff_A = 0;  
    static unsigned long jiff_X = 0;  
    static unsigned long jiff_B = 0;  
    static unsigned long jiff_L1 = 0;  
    static unsigned long jiff_L2 = 0;  
    static unsigned long jiff_R1 = 0;  
    static unsigned long jiff_R2 = 0;  
    static unsigned long jiff_SELECT = 0;  
    static unsigned long jiff_START = 0;  
	static int cnt=0;
	int retval,status;
	status=urb->status;
	cnt++;
	if(cnt==1000)
	{
		cnt=0;
		printk("urb->status=%d\n",status);
	}
    switch(status)  
    {  
    case 0:  
		printk("success,get data...\n");
        data = js_dev->data;  
        if((data[0] != (char)0x7F) || (data[1] != (char)0x7F) || (data[2] != (char)0x7F) || (data[3] != (char)0x7F) ||   
           (data[4] != (char)0xFF) || (data[5] != (char)0x0F) || (data[6] != (char)0x00) || (data[7] != (char)0x00))  
        {  
            
            printk("%02X %02X %02X %02X %02X %02X %02X %02X\n",  
                            (char)data[0], (char)data[1], (char)data[2], (char)data[3], 
                            (char)data[4], (char)data[5], (char)data[6], (char)data[7]); 
                              
            //direction keys   
            switch(data[2])  
            {  
            case KEYMASK_LEFT:  
                if(jiffies > (jiff_LEFT + INTERV_MILLI(200)))  
                {  
                    jiff_LEFT = jiffies;  
                    printk("LEFT pressed.\n");   
                    goto signal_app;  
                }  
                break;  
            case KEYMASK_RIGHT:  
                if(jiffies > (jiff_RIGHT + INTERV_MILLI(200)))  
                {  
                    jiff_RIGHT = jiffies;  
                    printk("RIGHT pressed.\n");   
                    goto signal_app;  
                }  
                break;  
            }  
            switch(data[3])  
            {  
            case KEYMASK_UP:  
                if(jiffies > (jiff_UP + INTERV_MILLI(200)))  
                {  
                    jiff_UP = jiffies;  
                    printk("UP pressed.\n");   
                    goto signal_app;  
                }  
                break;  
            case KEYMASK_DOWN:  
                if(jiffies > (jiff_DOWN + INTERV_MILLI(200)))  
                {  
                    jiff_DOWN = jiffies;  
                    printk("DOWN pressed.\n");   
                    goto signal_app;  
                }  
                break;  
            }  
            //general function keys   
            switch(data[5])  
            {  
            case KEYMASK_Y:  
                if(jiffies > (jiff_Y + INTERV_MILLI(200)))  
                {  
                    jiff_Y = jiffies;  
                    printk("Y pressed.\n");   
                    goto signal_app;  
                }  
                break;  
            case KEYMASK_A:  
                if(jiffies > (jiff_A + INTERV_MILLI(200)))  
                {  
                    jiff_A = jiffies;  
                    printk("A pressed.\n");   
                    goto signal_app;  
                }  
                break;  
            case KEYMASK_X:  
                if(jiffies > (jiff_X + INTERV_MILLI(200)))  
                {  
                    jiff_X = jiffies;  
                    printk("X pressed.\n");   
                    goto signal_app;  
                }  
                break;  
            case KEYMASK_B:  
                if(jiffies > (jiff_B + INTERV_MILLI(200)))  
                {  
                    jiff_B = jiffies;  
                    printk("B pressed.\n");   
                    goto signal_app;  
                }  
                break;  
            }  
            //advanced function keys   
            switch(data[6])  
            {  
            case KEYMASK_L1:  
                if(jiffies > (jiff_L1 + INTERV_MILLI(200)))  
                {  
                    jiff_L1 = jiffies;  
                    printk("L1 pressed.\n");   
                    goto signal_app;  
                }  
                break;  
            case KEYMASK_L2:  
                if(jiffies > (jiff_L2 + INTERV_MILLI(200)))  
                {  
                    jiff_L2 = jiffies;  
                    printk("L2 pressed.\n");   
                    goto signal_app;  
                }  
                break;  
            case KEYMASK_R1:  
                if(jiffies > (jiff_R1 + INTERV_MILLI(200)))  
                {  
                    jiff_R1 = jiffies;  
                    printk("R1 pressed.\n");   
                    goto signal_app;  
                }  
                break;  
            case KEYMASK_R2:  
                if(jiffies > (jiff_R2 + INTERV_MILLI(200)))  
                {  
                    jiff_R2 = jiffies;  
                    printk("R2 pressed.\n");   
                    goto signal_app;  
                }  
                break;  
            case KEYMASK_SELECT:  
                if(jiffies > (jiff_SELECT + INTERV_MILLI(200)))  
                {  
                    jiff_SELECT = jiffies;  
                    printk("SELECT pressed.\n");   
                    goto signal_app;  
                }  
                break;  
            case KEYMASK_START:  
                if(jiffies > (jiff_START + INTERV_MILLI(200)))  
                {  
                    jiff_START = jiffies;  
                    printk("START pressed.\n");   
                    goto signal_app;  
                }  
                break;  
            }  
        }  
        break;  
    default:  
        break;  
    }  
    goto submit_urb;  
signal_app:  
    //notify our application that at least one key was pressed   
    if(fasync_queue) 
	{ 
        kill_fasync(&fasync_queue, SIGIO, POLL_IN); 
		printk("notify our application that at least one key was pressed.\n");
	} 
submit_urb:  
    retval=usb_submit_urb(urb, GFP_ATOMIC); 
	if(retval)
		printk("usb_submit_urb error.\n");
}  
/* 
 * usb class driver info in order to get a minor number from the usb core, 
 * and to have the device registered with the driver core 
 */  
static struct usb_class_driver joystick_class = {  
    .name =     "joystick%d",  
    .fops =     &joystick_fops,  
    .minor_base =   USB_JOYSTICK_MINOR_BASE,  
};  
static int joystick_probe(struct usb_interface *interface,  
              const struct usb_device_id *id)  
{  
    struct usb_device *dev = interface_to_usbdev(interface);  
    struct usb_joystick *js_dev = NULL;  
    struct usb_host_interface *iface_desc;  
    struct usb_endpoint_descriptor *endpoint;  
    size_t maxp;  
    int pipe;  
    int retval = -ENOMEM;  
    printk("*************** Probe for joystick. ****************\n");  
    //dev->udev = usb_get_dev(interface_to_usbdev(interface));   
    //dev->interface = interface;   
    iface_desc = interface->cur_altsetting;  
	printk("numEndpoints=%d\n",iface_desc->desc.bNumEndpoints);
    if(iface_desc->desc.bNumEndpoints < 1)  
       {
	 printk("Finding interface...");  
	 return -ENODEV; 
	} 
    endpoint = &iface_desc->endpoint[0].desc;  
    if(!endpoint)  
	{
	 printk("No endpoint");  
        return -ENODEV;
	}  
    printk("direction(%02X): ", endpoint->bEndpointAddress);  
    if(endpoint->bEndpointAddress & USB_DIR_IN)  
        printk("to host\n");  
    else  
        printk("to device\n");  
    printk("Endpoint type: ");  
    switch(endpoint->bmAttributes)  
    {  
        case 0:  
            printk("control\n");  
            break;  
        case 1:  
            printk("ISOC\n");  
            break;  
        case 2:  
            printk("bulk\n");  
            break;  
        case 3:  
            printk("intterupt\n");  
            break;  
        default:  
            printk("Unkown.\n");  
    }  
    printk("MaxPacketSize: %d\n", endpoint->wMaxPacketSize);  
    //obtain usb_device pointor from usb_interface   
    dev = interface_to_usbdev(interface);  
    pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);  
    maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));  
    printk("pipe: %08X, maxp: %08X\n", pipe, maxp);  
    printk("sizeof(struct usb_joystick)=%d\n",sizeof(struct usb_joystick));
    js_dev = kzalloc(sizeof(struct usb_joystick), GFP_KERNEL);
    printk("Oh Yeah!\n");  
    if(!js_dev)  
        goto fail0;  
    kref_init(&js_dev->kref);  
    js_dev->data = usb_alloc_coherent(dev, 64, GFP_ATOMIC, &js_dev->data_dma);  
    if(!js_dev->data)  
        goto fail1;  
    gb_data = js_dev->data;  
    js_dev->in_urb = usb_alloc_urb(0, GFP_KERNEL);  
    if(!js_dev->in_urb)  
        goto fail2;  
    usb_fill_int_urb(js_dev->in_urb, dev, pipe, js_dev->data, (maxp > 8 ? 8 : maxp), joystick_irq, js_dev, endpoint->bInterval);  
    js_dev->in_urb->transfer_dma = js_dev->data_dma;  
    js_dev->in_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;  
    js_dev->udev = usb_get_dev(dev);  
    js_dev->interface = interface;  
    usb_set_intfdata(interface, js_dev);  
    retval = usb_register_dev(interface, &joystick_class);  
    if(retval)  
    {  
        //something prevented us from registering this driver   
        err("Not able to get a minor for this driver.");  
        usb_set_intfdata(interface, NULL);  
        goto fail3;  
    }  
    usb_submit_urb(js_dev->in_urb, GFP_ATOMIC);  
    dev_info(&interface->dev, "USB JoyStick now attaches to minor %d\n", interface->minor);  
    printk("*************** End of probe ****************\n");  
    return 0;  
fail3:  
    printk("fail3.\n");  
    usb_free_urb(js_dev->in_urb);  
fail2:  
    printk("fail2.\n");  
    usb_free_coherent(dev, 8, js_dev->data, js_dev->data_dma);  
fail1:  
    printk("fail1.\n");  
    kfree(js_dev);  
fail0:  
    printk("fail0.\n");  
    return -ENODEV;  
}  
static void joystick_disconnect(struct usb_interface *interface)  
{  
    struct usb_joystick *js_dev;  
    int minor = interface->minor;  
    js_dev = usb_get_intfdata(interface);  
      
    usb_set_intfdata(interface, NULL);  
    if(js_dev)  
    {  
        usb_kill_urb(js_dev->in_urb);  
        //give back out minor   
        usb_deregister_dev(interface, &joystick_class);  
    }  
    dev_info(&interface->dev, "USB minor#%d now disconnected", minor);  
}  
static struct usb_driver joystick_driver = {  
    .name =         "joystick",  
    .probe =        joystick_probe,  
    .disconnect =   joystick_disconnect,  
    .id_table =     joystick_table,  
};  
//init USB skeleton module   
static int __init usb_joystick_init(void)  
{  
    int result;  
    /* register this driver with the USB subsystem */  
    result = usb_register(&joystick_driver);  
    if (result)  
        printk("usb_register failed. Error number %d", result);  
    printk("************** joystick driver initialized. ****************\n");  
    return result;  
}  
//unload USB skeleton module   
static void __exit usb_joystick_exit(void)  
{  
    /* deregister this driver with the USB subsystem */  
    usb_deregister(&joystick_driver);  
    printk("**************** joystick driver unloaded. ****************\n");  
}  
module_init(usb_joystick_init);  
module_exit(usb_joystick_exit);  
MODULE_LICENSE("GPL");  
MODULE_AUTHOR("Cricket Long");  


测试代码:

#include <stdio.h>  
#include <stdlib.h>  
#include <unistd.h>  
#include <fcntl.h>  
#include <signal.h>  
#include <sys/ioctl.h>  
void interrupt_handler(int num);  
int fd;  
int main(int argc, char **argv)  
{  
     char buf[2];  
     int oflags;  
     fd = open("/dev/joystick0", O_RDWR);  
     if(fd != -1)  
     {  
         printf("fd: %d/n", fd);  
         signal(SIGIO, interrupt_handler);  
         fcntl(fd, F_SETOWN, getpid());  
         oflags = fcntl(fd, F_GETFL);  
         fcntl(fd, F_SETFL, oflags | FASYNC);  
         while(1){};  
     }  
     else  
         printf("Could not open device!\n");  
     return 0;  
}  
void interrupt_handler(int num)  
{  
     char data[8];  
     read(fd, data, 8);  
     printf("%02X %02X %02X %02X %02X %02X %02X %02X/n", (char)data[0], (char)data[1], (char)data[2], (char)data[3],  
                                                        (char)data[4], (char)data[5], (char)data[6], (char)data[7]);  
}  


 


  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值