📄 de1_drv.c
字号:
/* * CY7C67200/300 OTG Design Example 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 "de1_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.3"#define DRIVER_AUTHOR "usbapps@cypress.com"#define DRIVER_DESC "CY7C67200/300 OTG Design Example Driver"#define DE1_DEVICE_NAME "DE1"/* Module paramaters */MODULE_PARM(debug, "i");MODULE_PARM_DESC(debug, "Debug enabled or not");/* Define these values to match your device */#define USB_OTG_DE1_VENDOR_ID 0x04b4#define USB_OTG_DE1_PRODUCT_ID 0xDE01#define DEVICE_CONNECTED 1#define DEVICE_NOTCONNECTED 0#define DE1_BUFFER_SIZE 64#define DE1_DEVICE_MAJOR 253#define A_DEV 0#define B_DEV 1/* table of devices that work with this driver */static struct usb_device_id otg_de1_table [] = { { USB_DEVICE(USB_OTG_DE1_VENDOR_ID, USB_OTG_DE1_PRODUCT_ID) }, { } /* Terminating entry */};MODULE_DEVICE_TABLE (usb, otg_de1_table);/* Get a minor range for your devices from the usb maintainer */#define USB_OTG_DE1_MINOR_BASE 200 /* we can have up to this number of device plugged in at once */#define MAX_DEVICES 1#define INTERRUPT_REQ_SIZE 4 /* data request size for interrupt endpoint */#define INTERRUPT_EP_INTERVAL 100 /* interval for interrupt endpoint in millisecond */#define DE_REPORT_INVALID 0#define DE_REPORT_VALID 1/* Structure to hold all of our device specific stuff */struct USB_OTG_DE1 { 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 */ struct urb * int_in_urb; /* the urb used to receive interrupt data */ __u8 int_in_endpointAddr; /* the address of the interrupt in endpoint */ __u8 de_rpt_valid; unsigned char * de_rpt_buffer; unsigned char * int_out_buffer; /* the buffer to receive interrupt data */ int int_out_size; /* the size of the receive interrupt buffer */ __u8 int_out_endpointAddr; /* the address of the interrupt in endpoint */ unsigned char * bulk_in_buffer; /* the buffer to receive data */ int bulk_in_size; /* the size of the receive buffer */ __u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */ unsigned char * bulk_out_buffer; /* the buffer to send data */ int bulk_out_size; /* the size of the send buffer */ struct urb * bulk_out_urb; /* the urb used to send bulk out data */ __u8 bulk_out_endpointAddr; /* the address of the bulk in endpoint */ 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 ssize_t otg_de1_read (struct file *file, char *buffer, size_t count, loff_t *ppos);static ssize_t otg_de1_write (struct file *file, const char *buffer, size_t count, loff_t *ppos);static int otg_de1_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);static int otg_de1_open (struct inode *inode, struct file *file);static int otg_de1_release (struct inode *inode, struct file *file); static void * otg_de1_probe (struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id);static void otg_de1_disconnect (struct usb_device *dev, void *ptr);static void otg_de1_write_bulk_callback (struct urb *urb);static void otg_de1_int_in_callback (struct urb *urb);/* DE1 structure */static struct USB_OTG_DE1 *dev = NULL;/* * File operations needed when we register this driver. */static struct file_operations otg_de1_fops = { /* * The owner field is part of the module-locking * mechanism. The idea is that the kernel knows * which module to increment the use-counter of * BEFORE it calls the device's open() function. * This also means that the kernel can decrement * the use-counter again before calling release() * or should the open() function fail. * * Not all device structures have an "owner" field * yet. "struct file_operations" and "struct net_device" * do, while "struct tty_driver" does not. If the struct * has an "owner" field, then initialize it to the value * THIS_MODULE and the kernel will handle all module * locking for you automatically. Otherwise, you must * increment the use-counter in the open() function * and decrement it again in the release() function * yourself. */ owner: THIS_MODULE, read: otg_de1_read, write: otg_de1_write, ioctl: otg_de1_ioctl, open: otg_de1_open, release: otg_de1_release,}; /* usb specific object needed to register this driver with the usb subsystem */static struct usb_driver otg_de1_driver = { name: "otg_de1", probe: otg_de1_probe, disconnect: otg_de1_disconnect, fops: &otg_de1_fops, minor: USB_OTG_DE1_MINOR_BASE, id_table: otg_de1_table,};/** * USB_OTG_DE1_debug_data */static inline void USB_OTG_DE1_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");}/** * otg_de1_delete */static inline void otg_de1_delete (struct USB_OTG_DE1 *dev){ /* Release buffers and URB(s) */ if (dev != NULL) { /* Free bulk in buffer */ if (dev->bulk_in_buffer != NULL) kfree (dev->bulk_in_buffer); /* Free bulk out buffer and urb */ if (dev->bulk_out_buffer != NULL) kfree (dev->bulk_out_buffer); if (dev->bulk_out_urb != NULL) usb_free_urb(dev->bulk_out_urb); /* Free interrupt buffer and urb */ if (dev->int_in_buffer != NULL) kfree (dev->int_in_buffer); if (dev->int_in_urb != NULL) usb_free_urb(dev->int_in_urb); /* Free interrupt out buffer */ if (dev->int_out_buffer != NULL) kfree (dev->int_out_buffer); /* Free report buffer */ if (dev->de_rpt_buffer != NULL) kfree (dev->de_rpt_buffer); /* Free device structure */ kfree (dev); } }/** * otg_de1_open */static int otg_de1_open (struct inode *inode, struct file *file){ int retval = 0; //info ("Cypress OTG 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;}/** * otg_de1_release */static int otg_de1_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; if (dev->open_count <= 0) { /* shutdown any bulk writes that might be going on */ usb_unlink_urb (dev->bulk_out_urb); dev->open_count = 0; } /* decrement our usage count for the module */ MOD_DEC_USE_COUNT;exit_not_opened: up (&dev->sem); return retval;}/** * otg_de1_read */static ssize_t otg_de1_read (struct file *file, char *buffer, size_t count, loff_t *ppos){ int retval = 0; if (dev == NULL) { dbg (__FUNCTION__ " - object is NULL"); return -ENODEV; }// dbg(__FUNCTION__ " - count = %d", count); /* lock this object */ down (&dev->sem); /* verify that the device wasn't unplugged */ if ((dev->udev == NULL) || (dev->connect_state != DEVICE_CONNECTED)){ up (&dev->sem); return -ENODEV; } if (count > 0) { /* Do an immediate bulk read to get data from the device */ retval = usb_bulk_msg(dev->udev, usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr), dev->bulk_in_buffer, dev->bulk_in_size, &count, HZ*10); /* If the read was successful, copy the data to userspace */ if (!retval) { if (copy_to_user (buffer, dev->bulk_in_buffer, count)) retval = -EFAULT; else retval = count; } } else { dbg(__FUNCTION__ " - read negative or zero bytes"); } /* unlock the device */ up (&dev->sem); return retval;}/** * otg_de1_write */static ssize_t otg_de1_write (struct file *file, const char *buffer, size_t count, loff_t *ppos){ ssize_t bytes_written = 0; int retval = 0; if (dev == NULL) { dbg (__FUNCTION__ " - object is NULL"); return -ENODEV; }// dbg(__FUNCTION__ " - count = %d", count); /* lock this object */ down (&dev->sem); /* verify that the device wasn't unplugged */ if ((dev->udev == NULL) || (dev->connect_state != DEVICE_CONNECTED)) { retval = -ENODEV; goto exit; } /* verify that we actually have some data to write */ if (count == 0) { dbg(__FUNCTION__ " - write request of 0 bytes"); goto exit; } /* see if we are already in the middle of a write */ if (dev->bulk_out_urb->status == -EINPROGRESS) { dbg (__FUNCTION__ " - already writing"); goto exit; } /* we can only write as much as 1 urb will hold */ bytes_written = (ssize_t) min(count, dev->bulk_out_size); /* copy the data from userspace into our urb */ if (copy_from_user(dev->bulk_out_buffer, buffer, bytes_written)) { retval = -EFAULT; goto exit; } /* set up our urb */ FILL_BULK_URB(dev->bulk_out_urb, dev->udev,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -