📄 auermain.c
字号:
/*****************************************************************************//* * 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 + -