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

📄 auermain.c

📁 ep9315平台下USB驱动的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*****************************************************************************//* *      auermain.c  --  Auerswald PBX/System Telephone usb driver. * *      Copyright (C) 2002  Wolfgang M黣s (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 <linux/slab.h>#include <linux/module.h>#include <linux/init.h>#include <linux/devfs_fs_kernel.h>#undef DEBUG			/* include debug macros until it's done */#include <linux/usb.h>#include "auerchain.h"#include "auerbuf.h"#include "auerchar.h"#include "auerserv.h"#include "auermain.h"#include "auerisdn.h"/*-------------------------------------------------------------------*//* Debug support 						     */#ifdef DEBUG#define dump( desc, adr, len) \do {			\	unsigned int u;	\	printk (KERN_DEBUG); \	printk (desc); \	for (u = 0; u < len; u++) \		printk (" %02X", adr[u] & 0xFF); \	printk ("\n"); \} while (0)#else#define dump( desc, adr, len)#endif/*-------------------------------------------------------------------*//* Version Information */#define DRIVER_VERSION "1.2.3"#define DRIVER_AUTHOR  "Wolfgang M黣s <wolfgang@iksw-muees.de>"#define DRIVER_DESC    "Auerswald PBX/System Telephone usb driver"/*-------------------------------------------------------------------*//* Internal data structures                                          *//* the global usb devfs handle */extern devfs_handle_t usb_devfs_handle;/* array of pointers to our devices that are currently connected */struct auerswald *auerdev_table[AUER_MAX_DEVICES];/* lock to protect the auerdev_table structure */struct semaphore auerdev_table_mutex;/*-------------------------------------------------------------------*//* Forwards */static void auerswald_ctrlread_complete(struct urb *urb);/*-------------------------------------------------------------------*//* Completion handlers *//* Values of urb->status or results of usb_submit_urb():0		Initial, OK-EINPROGRESS	during submission until end-ENOENT		if urb is unlinked-ETIMEDOUT	Transfer timed out, NAK-ENOMEM		Memory Overflow-ENODEV		Specified USB-device or bus doesn't exist-ENXIO		URB already queued-EINVAL		a) Invalid transfer type specified (or not supported)		b) Invalid interrupt interval (0n256)-EAGAIN		a) Specified ISO start frame too early		b) (using ISO-ASAP) Too much scheduled for the future wait some time and try again.-EFBIG		Too much ISO frames requested (currently uhci900)-EPIPE		Specified pipe-handle/Endpoint is already stalled-EMSGSIZE	Endpoint message size is zero, do interface/alternate setting-EPROTO		a) Bitstuff error		b) Unknown USB error-EILSEQ		CRC mismatch-ENOSR		Buffer error-EREMOTEIO	Short packet detected-EXDEV		ISO transfer only partially completed look at individual frame status for details-EINVAL		ISO madness, if this happens: Log off and go home-EOVERFLOW	babble*//* check if a status code allows a retry */static int auerswald_status_retry(int status){	switch (status) {	case 0:	case -ETIMEDOUT:	case -EOVERFLOW:	case -EAGAIN:	case -EPIPE:	case -EPROTO:	case -EILSEQ:	case -ENOSR:	case -EREMOTEIO:		return 1;	/* do a retry */	}	return 0;		/* no retry possible */}/* Completion of asynchronous write block */void auerchar_ctrlwrite_complete(struct urb *urb){	struct auerbuf *bp = (struct auerbuf *) urb->context;	struct auerswald *cp =	    ((struct auerswald *) ((char *) (bp->list) -				   (unsigned				    long) (&((struct auerswald *) 0)->					   bufctl)));	dbg("auerchar_ctrlwrite_complete called");	/* reuse the buffer */	auerbuf_releasebuf(bp);	/* Wake up all processes waiting for a buffer */	wake_up(&cp->bufferwait);}/* Completion handler for dummy retry packet */static void auerswald_ctrlread_wretcomplete(struct urb *urb){	struct auerbuf *bp = (struct auerbuf *) urb->context;	struct auerswald *cp;	int ret;	dbg("auerswald_ctrlread_wretcomplete called");	dbg("complete with status: %d", urb->status);	cp = ((struct auerswald *) ((char *) (bp->list) -				    (unsigned				     long) (&((struct auerswald *) 0)->					    bufctl)));	/* check if it is possible to advance */	if (!auerswald_status_retry(urb->status) || !cp->usbdev) {		/* reuse the buffer */		err("control dummy: transmission error %d, can not retry",		    urb->status);		auerbuf_releasebuf(bp);		/* Wake up all processes waiting for a buffer */		wake_up(&cp->bufferwait);		return;	}	/* fill the control message */	bp->dr->bRequestType = AUT_RREQ;	bp->dr->bRequest = AUV_RBLOCK;	bp->dr->wLength = bp->dr->wValue;	/* temporary stored */	bp->dr->wValue = cpu_to_le16(1);	/* Retry Flag */	/* bp->dr->wIndex    = channel id;          remains */	FILL_CONTROL_URB(bp->urbp, cp->usbdev,			 usb_rcvctrlpipe(cp->usbdev, 0),			 (unsigned char *) bp->dr, bp->bufp,			 le16_to_cpu(bp->dr->wLength),			 (usb_complete_t) auerswald_ctrlread_complete, bp);	/* submit the control msg as next paket */	ret = auerchain_submit_urb_list(&cp->controlchain, bp->urbp, 1);	if (ret) {		dbg("auerswald_ctrlread_complete: nonzero result of auerchain_submit_urb_list %d", ret);		bp->urbp->status = ret;		auerswald_ctrlread_complete(bp->urbp);	}}/* completion handler for receiving of control messages */static void auerswald_ctrlread_complete(struct urb *urb){	unsigned int serviceid;	struct auerswald *cp;	struct auerscon *scp;	struct auerbuf *bp = (struct auerbuf *) urb->context;	int ret;	dbg("auerswald_ctrlread_complete called");	cp = ((struct auerswald *) ((char *) (bp->list) -				    (unsigned				     long) (&((struct auerswald *) 0)->					    bufctl)));	/* check if there is valid data in this urb */	if (urb->status) {		dbg("complete with non-zero status: %d", urb->status);		/* should we do a retry? */		if (!auerswald_status_retry(urb->status)		    || !cp->usbdev || (cp->version < AUV_RETRY)		    || (bp->retries >= AU_RETRIES)) {			/* reuse the buffer */			err("control read: transmission error %d, can not retry", urb->status);			auerbuf_releasebuf(bp);			/* Wake up all processes waiting for a buffer */			wake_up(&cp->bufferwait);			return;		}		bp->retries++;		dbg("Retry count = %d", bp->retries);		/* send a long dummy control-write-message to allow device firmware to react */		bp->dr->bRequestType = AUT_WREQ;		bp->dr->bRequest = AUV_DUMMY;		bp->dr->wValue = bp->dr->wLength;	/* temporary storage */		// bp->dr->wIndex    channel ID remains		bp->dr->wLength = cpu_to_le16(32);	/* >= 8 bytes */		FILL_CONTROL_URB(bp->urbp, cp->usbdev,				 usb_sndctrlpipe(cp->usbdev, 0),				 (unsigned char *) bp->dr, bp->bufp, 32,				 (usb_complete_t)				 auerswald_ctrlread_wretcomplete, bp);		/* submit the control msg as next paket */		ret =		    auerchain_submit_urb_list(&cp->controlchain, bp->urbp,					      1);		if (ret) {			dbg("auerswald_ctrlread_complete: nonzero result of auerchain_submit_urb_list %d", ret);			bp->urbp->status = ret;			auerswald_ctrlread_wretcomplete(bp->urbp);		}		return;	}	/* get the actual bytecount (incl. headerbyte) */	bp->len = urb->actual_length;	serviceid = bp->bufp[0] & AUH_TYPEMASK;	dbg("Paket with serviceid %d and %d bytes received", serviceid,	    bp->len);	/* dispatch the paket */	scp = cp->services[serviceid];	if (scp) {		/* look, Ma, a listener! */		scp->dispatch(scp, bp);	}	/* release the paket */	auerbuf_releasebuf(bp);	/* Wake up all processes waiting for a buffer */	wake_up(&cp->bufferwait);}/*-------------------------------------------------------------------*//* Handling of Interrupt Endpoint                                    *//* This interrupt Endpoint is used to inform the host about waiting   messages from the USB device.*//* int completion handler. */static void auerswald_int_complete(struct urb *urb){	unsigned int channelid;	unsigned int bytecount;	int ret;	struct auerbuf *bp = NULL;	struct auerswald *cp = (struct auerswald *) urb->context;	dbg("auerswald_int_complete called");	/* do not respond to an error condition */	if (urb->status != 0) {		dbg("nonzero URB status = %d", urb->status);		return;	}	/* check if all needed data was received */	if (urb->actual_length < AU_IRQMINSIZE) {		dbg("invalid data length received: %d bytes",		    urb->actual_length);		return;	}	/* check the command code */	if (cp->intbufp[0] != AU_IRQCMDID) {		dbg("invalid command received: %d", cp->intbufp[0]);		return;	}	/* check the command type */	if (cp->intbufp[1] != AU_BLOCKRDY) {		dbg("invalid command type received: %d", cp->intbufp[1]);		return;	}	/* now extract the information */	channelid = cp->intbufp[2];	bytecount = le16_to_cpup(&cp->intbufp[3]);	/* check the channel id */	if (channelid >= AUH_TYPESIZE) {		dbg("invalid channel id received: %d", channelid);		return;	}	/* check the byte count */	if (bytecount > (cp->maxControlLength + AUH_SIZE)) {		dbg("invalid byte count received: %d", bytecount);		return;	}	dbg("Service Channel = %d", channelid);	dbg("Byte Count = %d", bytecount);	/* get a buffer for the next data paket */	bp = auerbuf_getbuf(&cp->bufctl);	/* if no buffer available: skip it */	if (!bp) {		dbg("auerswald_int_complete: no data buffer available");		/* can we do something more?		   This is a big problem: if this int packet is ignored, the		   device will wait forever and not signal any more data.		   The only real solution is: having enought buffers!		   Or perhaps temporary disabling the int endpoint?		 */		return;	}	/* fill the control message */	bp->dr->bRequestType = AUT_RREQ;	bp->dr->bRequest = AUV_RBLOCK;	bp->dr->wValue = cpu_to_le16(0);	bp->dr->wIndex = cpu_to_le16(channelid | AUH_DIRECT | AUH_UNSPLIT);	bp->dr->wLength = cpu_to_le16(bytecount);	FILL_CONTROL_URB(bp->urbp, cp->usbdev,			 usb_rcvctrlpipe(cp->usbdev, 0),			 (unsigned char *) bp->dr, bp->bufp, bytecount,			 (usb_complete_t) auerswald_ctrlread_complete, bp);	/* submit the control msg */	ret = auerchain_submit_urb(&cp->controlchain, bp->urbp);	if (ret) {		dbg("auerswald_int_complete: nonzero result of auerchain_submit_urb %d", ret);		bp->urbp->status = ret;		auerswald_ctrlread_complete(bp->urbp);		/* here applies the same problem as above: device locking! */	}}/* int memory deallocation   NOTE: no mutex please!*/static void auerswald_int_free(struct auerswald *cp){	if (cp->inturbp) {		usb_free_urb(cp->inturbp);		cp->inturbp = NULL;	}	kfree(cp->intbufp);}/* This function is called to activate the interrupt   endpoint. This function returns 0 if successfull or an error code.   NOTE: no mutex please!*/static int auerswald_int_open(struct auerswald *cp){	int ret;	struct usb_endpoint_descriptor *ep;	int irqsize;	dbg("auerswald_int_open");	ep = usb_epnum_to_ep_desc(cp->usbdev, USB_DIR_IN | AU_IRQENDP);	if (!ep) {		ret = -EFAULT;		goto intoend;	}	irqsize = ep->wMaxPacketSize;	cp->irqsize = irqsize;	/* allocate the urb and data buffer */	if (!cp->inturbp) {		cp->inturbp = usb_alloc_urb(0);		if (!cp->inturbp) {			ret = -ENOMEM;			goto intoend;		}	}	if (!cp->intbufp) {		cp->intbufp = (char *) kmalloc(irqsize, GFP_KERNEL);		if (!cp->intbufp) {			ret = -ENOMEM;			goto intoend;		}	}	/* setup urb */	FILL_INT_URB(cp->inturbp, cp->usbdev,		     usb_rcvintpipe(cp->usbdev, AU_IRQENDP), cp->intbufp,		     irqsize, auerswald_int_complete, cp, ep->bInterval);	/* start the urb */	cp->inturbp->status = 0;	/* needed! */	ret = usb_submit_urb(cp->inturbp);      intoend:	if (ret < 0) {		/* activation of interrupt endpoint has failed. Now clean up. */		dbg("auerswald_int_open: activation of int endpoint failed");		/* deallocate memory */		auerswald_int_free(cp);	}	return ret;}/* This function is called to deactivate the interrupt   endpoint. This function returns 0 if successfull or an error code.   NOTE: no mutex please!*/static int auerswald_int_release(struct auerswald *cp){	int ret = 0;	dbg("auerswald_int_release");	/* stop the int endpoint */	if (cp->inturbp) {		ret = usb_unlink_urb(cp->inturbp);		if (ret)			dbg("nonzero int unlink result received: %d", ret);	}	/* deallocate memory */	auerswald_int_free(cp);	return ret;}/* --------------------------------------------------------------------- *//* Helper functions                                                      *//* Delete an auerswald driver context */void auerswald_delete(struct auerswald *cp){	dbg("auerswald_delete");	if (cp == NULL)

⌨️ 快捷键说明

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