de3_drv.c
来自「linux嵌入式课程实践中的一个关于声卡驱动程序 。」· C语言 代码 · 共 508 行
C
508 行
/* * CY7C67200/300 Design Example 3 Keyboard Driver * * Copyright (c) 2002, 2003 by Cypress Semiconductor Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * * * History: * */#include <linux/config.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/signal.h>#include <linux/errno.h>#include <linux/poll.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/fcntl.h>#include <linux/module.h>#include <linux/spinlock.h>#include <linux/list.h>#include <linux/smp_lock.h>//#include <linux/devfs_fs_kernel.h>#include <linux/usb.h>#include "de3_drv.h"#ifdef CONFIG_USB_DEBUG static int debug = 1;#else static int debug;#endif/* Use our own dbg macro */#undef dbg#define dbg(format, arg...) do { if (debug) printk(KERN_DEBUG __FILE__ ": " format "\n" , ## arg); } while (0)/* Version Information */#define DRIVER_VERSION "v0.1"#define DRIVER_AUTHOR "usbapps@cypress.com"#define DRIVER_DESC "CY7C67200/300 Design Example 3 Keyboard Driver"#define DE3_DEVICE_NAME "DE3"/* Module paramaters */MODULE_PARM(debug, "i");MODULE_PARM_DESC(debug, "Debug enabled or not");/* Define these values to match your device */#define DEVICE_CONNECTED 1#define DEVICE_NOTCONNECTED 0#define DE3_BUFFER_SIZE 8#define DE3_DEVICE_MAJOR 252/* table of devices that work with this driver */static struct usb_device_id de3_kbd_id_table [] = { { USB_INTERFACE_INFO(3, 1, 1) }, { } /* Terminating entry */};MODULE_DEVICE_TABLE (usb, de3_kbd_id_table);/* Structure to hold all of our device specific stuff */struct USB_DE3_KBD { struct usb_device * udev; /* save off the usb device pointer */ struct usb_interface * interface; /* the interface for this device */ unsigned char major; /* the starting minor number for this device */ unsigned char connect_state; /* connect state of the device */ unsigned char * int_in_buffer; /* the buffer to receive interrupt data */ int int_in_size; /* the size of the receive interrupt buffer */ int int_in_pipe; /* the address of the interrupt in endpoint */ struct urb int_in_urb; /* interrupt in urb */ int pending_request;/* pending interrupt in request */ hid_keyboard_report_t hid_rpt; /* hid keyboard report buffer */ struct tq_struct tqueue; /* task queue for line discipline waking up */ int open_count; /* number of times this port has been opened */ struct semaphore sem; /* locks this structure */};/* local function prototypes */static int de3_kbd_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);static int de3_kbd_open (struct inode *inode, struct file *file);static int de3_kbd_release (struct inode *inode, struct file *file); static void * de3_kbd_probe (struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id);static void de3_kbd_disconnect (struct usb_device *dev, void *ptr);static void de3_kbd_int_callback (struct urb *urb);/* DE1 structure */static struct USB_DE3_KBD *dev = NULL;/* * File operations needed when we register this driver. */static struct file_operations de3_kbd_fops = { owner: THIS_MODULE, ioctl: de3_kbd_ioctl, open: de3_kbd_open, release: de3_kbd_release,}; /* usb specific object needed to register this driver with the usb subsystem */static struct usb_driver de3_kbd_driver = { name: "de3_kbd", probe: de3_kbd_probe, disconnect: de3_kbd_disconnect, id_table: de3_kbd_id_table,};/** * USB_DE3_KBD_debug_data */static inline void de3_kbd_debug_data (const char *function, int size, const unsigned char *data){ int i; if (!debug) return; printk (KERN_DEBUG __FILE__": %s - length = %d, data = ", function, size); for (i = 0; i < size; ++i) { printk ("%.2x ", data[i]); } printk ("\n");}/** * de3_kbd_delete */static inline void de3_kbd_delete (struct USB_DE3_KBD *dev){ /* Release buffers and URB(s) */ if (dev != NULL) { /* Free interrupt buffer and urb */ if (dev->int_in_buffer != NULL) kfree (dev->int_in_buffer); /* Free device structure */ kfree (dev); } }/** * de3_kbd_open */static int de3_kbd_open (struct inode *inode, struct file *file){ int retval = 0; info ("DE3 keyboard device open"); dbg(__FUNCTION__); if (dev == NULL) { dbg(__FUNCTION__ " - object is NULL"); return -ENODEV; } if (dev->open_count > 0) { err(__FUNCTION__ " - Device already open!"); return -ENODEV; } /* Increment our usage count for the module. * This is redundant here, because "struct file_operations" * has an "owner" field. This line is included here soley as * a reference for drivers using lesser structures... ;-) */ MOD_INC_USE_COUNT; /* lock this device */ down (&dev->sem); /* increment our usage count for the driver */ ++dev->open_count; /* save our object in the file's private structure */ file->private_data = dev; /* unlock this device */ up (&dev->sem); return retval;}/** * de3_kbd_release */static int de3_kbd_release (struct inode *inode, struct file *file){ int retval = 0; if (dev == NULL) { dbg (__FUNCTION__ " - object is NULL"); return -ENODEV; } /* lock our device */ down (&dev->sem); if (dev->open_count <= 0) { dbg (__FUNCTION__ " - device not opened"); retval = -ENODEV; goto exit_not_opened; } /* decrement our usage count for the device */ --dev->open_count; /* decrement our usage count for the module */ MOD_DEC_USE_COUNT;exit_not_opened: up (&dev->sem); return retval;}/** * de3_kbd_int_callback */static void de3_kbd_int_callback (struct urb *urb){ if (urb->status) return; if (dev->hid_rpt.valid != HID_REPORT_VALID) { /* Indicate a valid report */ dev->hid_rpt.valid = HID_REPORT_VALID; /* copy data */ memcpy(&dev->hid_rpt.report, dev->int_in_buffer, HID_REPORT_SIZE); }}/** * de3_kbd_ioctl */static int de3_kbd_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ int count = 0; int ret = 0; hid_keyboard_report_t * hidreport; if (dev == NULL) { dbg (__FUNCTION__ " - object is NULL"); return -ENODEV; } /* lock this object */ down (&dev->sem);// dbg(__FUNCTION__ " - cmd 0x%.4x, arg %ld", cmd, arg); switch (cmd) { case IOCTL_GET_REPORT: /* Get the keyboard report from the interrupt pipe */ if (dev->connect_state == DEVICE_CONNECTED) { hidreport = (hid_keyboard_report_t *) arg; /* Initialize report valid status */ hidreport->valid = HID_REPORT_INVALID; if (dev->hid_rpt.valid == HID_REPORT_VALID) { if (copy_to_user ((void *) hidreport->report, dev->hid_rpt.report, HID_REPORT_SIZE)) { ret = -EFAULT; } else { /* indicate valid report */ hidreport->valid = HID_REPORT_VALID; } /* Clear report valid status */ dev->hid_rpt.valid = HID_REPORT_INVALID; } /* Check for pending interrupt in request */ if (dev->pending_request == 0) { /* Submit the interrupt URB */ dev->pending_request = 1; dev->int_in_urb.dev = dev->udev; if (usb_submit_urb(&dev->int_in_urb)) ret = -EIO; } } else { ret = -ENOTCONN; } break; default: ret = -ENOIOCTLCMD; break; } /* unlock the device */ up (&dev->sem); return ret;}/** * de3_kbd_probe * * Called by the usb core when a new device is connected that it thinks * this driver might be interested in. */static void * de3_kbd_probe(struct usb_device *udev, unsigned int ifnum, const struct usb_device_id *id){ struct usb_interface *interface; struct usb_interface_descriptor *iface_desc; struct usb_endpoint_descriptor *endpoint; int pipe, maxp; if (dev == NULL) { dbg (__FUNCTION__ " - object is NULL"); return NULL; } interface = &udev->actconfig->interface[ifnum]; iface_desc = &interface->altsetting[interface->act_altsetting]; if (iface_desc->bNumEndpoints != 1) return NULL; endpoint = iface_desc->endpoint + 0; if (!(endpoint->bEndpointAddress & 0x80)) return NULL; if ((endpoint->bmAttributes & 3) != 3) return NULL; pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress); maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe)); usb_set_protocol(udev, iface_desc->bInterfaceNumber, 0); usb_set_idle(udev, iface_desc->bInterfaceNumber, 0, 0); /* See if we are already connected to a de1 device */ if (dev->connect_state == DEVICE_CONNECTED) { info ("Too many devices plugged in, can not handle this device."); return NULL; } /* Save info */ dev->udev = udev; dev->interface = interface; dev->int_in_pipe = pipe; FILL_INT_URB(&dev->int_in_urb, dev->udev, pipe, dev->int_in_buffer, maxp > DE3_BUFFER_SIZE ? DE3_BUFFER_SIZE : maxp, de3_kbd_int_callback, dev, endpoint->bInterval); /* Indicate that a device is connected */ dev->connect_state = DEVICE_CONNECTED; /* let the user know what node this device is now attached to */ info ("DE3 keyboard device now attached (major %d)", dev->major); return dev;}/** * de3_kbd_disconnect * * Called by the usb core when the device is removed from the system. */static void de3_kbd_disconnect(struct usb_device *udev, void *ptr){ if (dev == NULL) { dbg (__FUNCTION__ " - object is NULL"); return; } /* lock the device */ down (&dev->sem); /* unlink the Int in URB */ usb_unlink_urb(&dev->int_in_urb); /* Indicate that a device is not connected */ dev->connect_state = DEVICE_NOTCONNECTED; /* Indicate no pending interrupt in request */ dev->pending_request = 0; /* unlock the device */ up (&dev->sem); info("DE3 keyboard device now disconnected");}/** * USB_DE3_KBD_init */static int __init de3_kbd_init(void){ int result; /* allocate memory for our device state and intialize it */ dev = kmalloc (sizeof(struct USB_DE3_KBD), GFP_KERNEL); if (dev == NULL) { err ("Out of memory"); return -1; } memset ((void *) dev, 0x00, sizeof (struct USB_DE3_KBD)); /* allocate memory for the int_in buffer */ dev->int_in_buffer = kmalloc (DE3_BUFFER_SIZE, GFP_KERNEL); if (!dev->int_in_buffer) { err("Couldn't allocate int_in_buffer"); return -1; } dev->int_in_size = DE3_BUFFER_SIZE; /* Indicate invalid hid report */ dev->hid_rpt.valid = HID_REPORT_INVALID; /* register this driver with the USB subsystem */ result = usb_register(&de3_kbd_driver); if (result < 0) { err("usb_register failed for the "__FILE__" driver. Error number %d", result); return -1; } /* register this driver */#if 0 dev->major = register_chrdev( 0, DE3_DEVICE_NAME, &de3_kbd_fops ); if( dev->major == 0 ) { err("register_chrdev() failed."); return -1; }#else dev->major = DE3_DEVICE_MAJOR; result = register_chrdev( dev->major, DE3_DEVICE_NAME, &de3_kbd_fops ); if( result != 0 ) { err("register_chrdev() failed."); return -1; }#endif /* Indicate that a device is not connected */ dev->connect_state = DEVICE_NOTCONNECTED; /* Indicate no pending interrupt in request */ dev->pending_request = 0; /* Initialize the driver semaphore */ init_MUTEX (&dev->sem); info(DRIVER_DESC " " DRIVER_VERSION " (Major = %d)", dev->major); return 0;}/** * USB_DE3_KBD_exit */static void __exit de3_kbd_exit(void){ if (dev == NULL) { dbg (__FUNCTION__ " - object is NULL"); return; } /* deregister this driver with the USB subsystem */ usb_deregister(&de3_kbd_driver); /* Unregister device */ unregister_chrdev( dev->major, DE3_DEVICE_NAME ); /* Delete buffers */ de3_kbd_delete (dev);}module_init (de3_kbd_init);module_exit (de3_kbd_exit);MODULE_AUTHOR(DRIVER_AUTHOR);MODULE_DESCRIPTION(DRIVER_DESC);MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?