⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 auerswald.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
/*****************************************************************************//* *      auerswald.c  --  Auerswald PBX/System Telephone usb driver. * *      Copyright (C) 2001  Wolfgang Mües (wolfgang@iksw-muees.de) * *      Very much code of this driver is borrowed from dabusb.c (Deti Fliegl) *      and from the USB Skeleton driver (Greg Kroah-Hartman). Thank you. * *      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. * *      This program is distributed in the hope that it will be useful, *      but WITHOUT ANY WARRANTY; without even the implied warranty of *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *      GNU General Public License for more details. * *      You should have received a copy of the GNU General Public License *      along with this program; if not, write to the Free Software *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /*****************************************************************************//* Standard Linux module include files */#include <asm/uaccess.h>#include <asm/byteorder.h>#include <linux/slab.h>#include <linux/module.h>#include <linux/init.h>#include <linux/wait.h>#include <linux/usb.h>/*-------------------------------------------------------------------*//* Debug support 						     */#ifdef DEBUG#define dump( adr, len) \do {			\	unsigned int u;	\	printk (KERN_DEBUG); \	for (u = 0; u < len; u++) \		printk (" %02X", adr[u] & 0xFF); \	printk ("\n"); \} while (0)#else#define dump( adr, len)#endif/*-------------------------------------------------------------------*//* Version Information */#define DRIVER_VERSION "0.9.11"#define DRIVER_AUTHOR  "Wolfgang Mües <wolfgang@iksw-muees.de>"#define DRIVER_DESC    "Auerswald PBX/System Telephone usb driver"/*-------------------------------------------------------------------*//* Private declarations for Auerswald USB driver                     *//* Auerswald Vendor ID */#define ID_AUERSWALD  	0x09BF#define AUER_MINOR_BASE	112	/* auerswald driver minor number *//* we can have up to this number of device plugged in at once */#define AUER_MAX_DEVICES 16/* Number of read buffers for each device */#define AU_RBUFFERS     10/* Number of chain elements for each control chain */#define AUCH_ELEMENTS   20/* Number of retries in communication */#define AU_RETRIES	10/*-------------------------------------------------------------------*//* vendor specific protocol                                          *//* Header Byte */#define AUH_INDIRMASK   0x80    /* mask for direct/indirect bit */#define AUH_DIRECT      0x00    /* data is for USB device */#define AUH_INDIRECT    0x80    /* USB device is relay */#define AUH_SPLITMASK   0x40    /* mask for split bit */#define AUH_UNSPLIT     0x00    /* data block is full-size */#define AUH_SPLIT       0x40    /* data block is part of a larger one,                                   split-byte follows */#define AUH_TYPEMASK    0x3F    /* mask for type of data transfer */#define AUH_TYPESIZE    0x40    /* different types */#define AUH_DCHANNEL    0x00    /* D channel data */#define AUH_B1CHANNEL   0x01    /* B1 channel transparent */#define AUH_B2CHANNEL   0x02    /* B2 channel transparent *//*                0x03..0x0F       reserved for driver internal use */#define AUH_COMMAND     0x10    /* Command channel */#define AUH_BPROT       0x11    /* Configuration block protocol */#define AUH_DPROTANA    0x12    /* D channel protocol analyzer */#define AUH_TAPI        0x13    /* telephone api data (ATD) *//*                0x14..0x3F       reserved for other protocols */#define AUH_UNASSIGNED  0xFF    /* if char device has no assigned service */#define AUH_FIRSTUSERCH 0x11    /* first channel which is available for driver users */#define AUH_SIZE	1 	/* Size of Header Byte *//* Split Byte. Only present if split bit in header byte set.*/#define AUS_STARTMASK   0x80    /* mask for first block of splitted frame */#define AUS_FIRST       0x80    /* first block */#define AUS_FOLLOW      0x00    /* following block */#define AUS_ENDMASK     0x40    /* mask for last block of splitted frame */#define AUS_END         0x40    /* last block */#define AUS_NOEND       0x00    /* not the last block */#define AUS_LENMASK     0x3F    /* mask for block length information *//* Request types */#define AUT_RREQ        (USB_DIR_IN  | USB_TYPE_VENDOR | USB_RECIP_OTHER)   /* Read Request */#define AUT_WREQ        (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER)   /* Write Request *//* Vendor Requests */#define AUV_GETINFO     0x00    /* GetDeviceInfo */#define AUV_WBLOCK      0x01    /* Write Block */#define AUV_RBLOCK      0x02    /* Read Block */#define AUV_CHANNELCTL  0x03    /* Channel Control */#define AUV_DUMMY	0x04	/* Dummy Out for retry *//* Device Info Types */#define AUDI_NUMBCH     0x0000  /* Number of supported B channels */#define AUDI_OUTFSIZE   0x0001  /* Size of OUT B channel fifos */#define AUDI_MBCTRANS   0x0002  /* max. Blocklength of control transfer *//* Interrupt endpoint definitions */#define AU_IRQENDP      1       /* Endpoint number */#define AU_IRQCMDID     16      /* Command-block ID */#define AU_BLOCKRDY     0       /* Command: Block data ready on ctl endpoint */#define AU_IRQMINSIZE	5	/* Nr. of bytes decoded in this driver *//* Device String Descriptors */#define AUSI_VENDOR   	1	/* "Auerswald GmbH & Co. KG" */#define AUSI_DEVICE   	2	/* Name of the Device */#define AUSI_SERIALNR 	3	/* Serial Number */#define AUSI_MSN      	4	/* "MSN ..." (first) Multiple Subscriber Number */#define AUSI_DLEN	100	/* Max. Length of Device Description */#define AUV_RETRY	0x101	/* First Firmware version which can do control retries *//*-------------------------------------------------------------------*//* External data structures / Interface                              */typedef struct{	char __user *buf;	/* return buffer for string contents */	unsigned int bsize;	/* size of return buffer */} audevinfo_t,*paudevinfo_t;/* IO controls */#define IOCTL_AU_SLEN	  _IOR( 'U', 0xF0, int)         /* return the max. string descriptor length */#define IOCTL_AU_DEVINFO  _IOWR('U', 0xF1, audevinfo_t) /* get name of a specific device */#define IOCTL_AU_SERVREQ  _IOW( 'U', 0xF2, int) 	/* request a service channel */#define IOCTL_AU_BUFLEN	  _IOR( 'U', 0xF3, int)         /* return the max. buffer length for the device */#define IOCTL_AU_RXAVAIL  _IOR( 'U', 0xF4, int)         /* return != 0 if Receive Data available */#define IOCTL_AU_CONNECT  _IOR( 'U', 0xF5, int)         /* return != 0 if connected to a service channel */#define IOCTL_AU_TXREADY  _IOR( 'U', 0xF6, int)         /* return != 0 if Transmitt channel ready to send *//*                              'U'  0xF7..0xFF reseved *//*-------------------------------------------------------------------*//* Internal data structures                                          *//* ..................................................................*//* urb chain element */struct  auerchain;                      /* forward for circular reference */typedef struct{        struct auerchain *chain;        /* pointer to the chain to which this element belongs */        struct urb * urbp;                   /* pointer to attached urb */        void *context;                  /* saved URB context */        usb_complete_t complete;        /* saved URB completion function */        struct list_head list;          /* to include element into a list */} auerchainelement_t,*pauerchainelement_t;/* urb chain */typedef struct auerchain{        pauerchainelement_t active;     /* element which is submitted to urb */	spinlock_t lock;                /* protection agains interrupts */        struct list_head waiting_list;  /* list of waiting elements */        struct list_head free_list;     /* list of available elements */} auerchain_t,*pauerchain_t;/* urb blocking completion helper struct */typedef struct{	wait_queue_head_t wqh;    	/* wait for completion */	unsigned int done;		/* completion flag */} auerchain_chs_t,*pauerchain_chs_t;/* ...................................................................*//* buffer element */struct  auerbufctl;                     /* forward */typedef struct{        char *bufp;                     /* reference to allocated data buffer */        unsigned int len;               /* number of characters in data buffer */	unsigned int retries;		/* for urb retries */        struct usb_ctrlrequest *dr;	/* for setup data in control messages */        struct urb * urbp;                   /* USB urb */        struct auerbufctl *list;        /* pointer to list */        struct list_head buff_list;     /* reference to next buffer in list */} auerbuf_t,*pauerbuf_t;/* buffer list control block */typedef struct auerbufctl{        spinlock_t lock;                /* protection in interrupt */        struct list_head free_buff_list;/* free buffers */        struct list_head rec_buff_list; /* buffers with receive data */} auerbufctl_t,*pauerbufctl_t;/* ...................................................................*//* service context */struct  auerscon;                       /* forward */typedef void (*auer_dispatch_t)(struct auerscon*, pauerbuf_t);typedef void (*auer_disconn_t) (struct auerscon*);typedef struct auerscon{        unsigned int id;                /* protocol service id AUH_xxxx */        auer_dispatch_t dispatch;       /* dispatch read buffer */	auer_disconn_t disconnect;	/* disconnect from device, wake up all char readers */} auerscon_t,*pauerscon_t;/* ...................................................................*//* USB device context */typedef struct{	struct semaphore 	mutex;         	    /* protection in user context */	char 			name[20];	    /* name of the /dev/usb entry */	unsigned int		dtindex;	    /* index in the device table */	struct usb_device *	usbdev;      	    /* USB device handle */	int			open_count;	    /* count the number of open character channels */        char 			dev_desc[AUSI_DLEN];/* for storing a textual description */        unsigned int 		maxControlLength;   /* max. Length of control paket (without header) */        struct urb * 		inturbp;            /* interrupt urb */        char *			intbufp;            /* data buffer for interrupt urb */	unsigned int 		irqsize;	    /* size of interrupt endpoint 1 */        struct auerchain 	controlchain;  	    /* for chaining of control messages */	auerbufctl_t 		bufctl;             /* Buffer control for control transfers */        pauerscon_t 	     	services[AUH_TYPESIZE];/* context pointers for each service */	unsigned int		version;	    /* Version of the device */	wait_queue_head_t 	bufferwait;         /* wait for a control buffer */} auerswald_t,*pauerswald_t;/* ................................................................... *//* character device context */typedef struct{	struct semaphore mutex;         /* protection in user context */	pauerswald_t auerdev;           /* context pointer of assigned device */        auerbufctl_t bufctl;            /* controls the buffer chain */        auerscon_t scontext;            /* service context */	wait_queue_head_t readwait;     /* for synchronous reading */	struct semaphore readmutex;     /* protection against multiple reads */	pauerbuf_t readbuf;		/* buffer held for partial reading */	unsigned int readoffset;	/* current offset in readbuf */	unsigned int removed;		/* is != 0 if device is removed */} auerchar_t,*pauerchar_t;/*-------------------------------------------------------------------*//* Forwards */static void auerswald_ctrlread_complete (struct urb * urb, struct pt_regs *regs);static void auerswald_removeservice (pauerswald_t cp, pauerscon_t scp);static struct usb_driver auerswald_driver;/*-------------------------------------------------------------------*//* USB chain helper functions                                        *//* --------------------------                                        *//* completion function for chained urbs */static void auerchain_complete (struct urb * urb, struct pt_regs *regs){	unsigned long flags;        int result;        /* get pointer to element and to chain */        pauerchainelement_t acep = (pauerchainelement_t) urb->context;        pauerchain_t         acp = acep->chain;        /* restore original entries in urb */        urb->context  = acep->context;        urb->complete = acep->complete;        dbg ("auerchain_complete called");        /* call original completion function           NOTE: this function may lead to more urbs submitted into the chain.                 (no chain lock at calling complete()!)                 acp->active != NULL is protecting us against recursion.*/        urb->complete (urb, regs);        /* detach element from chain data structure */	spin_lock_irqsave (&acp->lock, flags);        if (acp->active != acep) /* paranoia debug check */	        dbg ("auerchain_complete: completion on non-active element called!");        else                acp->active = NULL;        /* add the used chain element to the list of free elements */	list_add_tail (&acep->list, &acp->free_list);        acep = NULL;        /* is there a new element waiting in the chain? */        if (!acp->active && !list_empty (&acp->waiting_list)) {                /* yes: get the entry */                struct list_head *tmp = acp->waiting_list.next;                list_del (tmp);                acep = list_entry (tmp, auerchainelement_t, list);                acp->active = acep;        }        spin_unlock_irqrestore (&acp->lock, flags);        /* submit the new urb */        if (acep) {                urb    = acep->urbp;                dbg ("auerchain_complete: submitting next urb from chain");		urb->status = 0;	/* needed! */		result = usb_submit_urb(urb, GFP_ATOMIC);                /* check for submit errors */                if (result) {                        urb->status = result;                        dbg("auerchain_complete: usb_submit_urb with error code %d", result);                        /* and do error handling via *this* completion function (recursive) */                        auerchain_complete( urb, NULL);                }        } else {                /* simple return without submitting a new urb.                   The empty chain is detected with acp->active == NULL. */        };}/* submit function for chained urbs   this function may be called from completion context or from user space!   early = 1 -> submit in front of chain*/static int auerchain_submit_urb_list (pauerchain_t acp, struct urb * urb, int early){        int result;        unsigned long flags;        pauerchainelement_t acep = NULL;        dbg ("auerchain_submit_urb called");        /* try to get a chain element */        spin_lock_irqsave (&acp->lock, flags);        if (!list_empty (&acp->free_list)) {                /* yes: get the entry */                struct list_head *tmp = acp->free_list.next;                list_del (tmp);                acep = list_entry (tmp, auerchainelement_t, list);        }        spin_unlock_irqrestore (&acp->lock, flags);        /* if no chain element available: return with error */        if (!acep) {                return -ENOMEM;        }        /* fill in the new chain element values */        acep->chain    = acp;        acep->context  = urb->context;        acep->complete = urb->complete;        acep->urbp     = urb;        INIT_LIST_HEAD (&acep->list);        /* modify urb */        urb->context   = acep;        urb->complete  = auerchain_complete;        urb->status    = -EINPROGRESS;    /* usb_submit_urb does this, too */        /* add element to chain - or start it immediately */        spin_lock_irqsave (&acp->lock, flags);        if (acp->active) {                /* there is traffic in the chain, simple add element to chain */		if (early) {			dbg ("adding new urb to head of chain");			list_add (&acep->list, &acp->waiting_list);		} else {			dbg ("adding new urb to end of chain");			list_add_tail (&acep->list, &acp->waiting_list);		}		acep = NULL;        } else {                /* the chain is empty. Prepare restart */                acp->active = acep;        }        /* Spin has to be removed before usb_submit_urb! */        spin_unlock_irqrestore (&acp->lock, flags);        /* Submit urb if immediate restart */        if (acep) {                dbg("submitting urb immediate");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -