# This is a BitKeeper generated patch for the following project: # Project Name: Linux kernel tree # This patch format is intended for GNU patch command version 2.5 or higher. # This patch includes the following deltas: # ChangeSet 1.220 -> 1.221 # drivers/usb/auerswald.c 1.3 -> 1.4 # # The following is the BitKeeper ChangeSet Log # -------------------------------------------- # 02/02/06 greg@soap.kroah.net 1.221 # patch from Wolfgang Mües for the usb auerswald.c driver: # - Code-Review from Oliver Neukum: remove SMP races. # - Added some wake_up calls after auerbuf_releasebuf to wake up tasks waiting # for cp buffers. # - Change the module count handling to automatic (owner: THIS_MODULE). # -------------------------------------------- # diff -Nru a/drivers/usb/auerswald.c b/drivers/usb/auerswald.c --- a/drivers/usb/auerswald.c Wed Feb 6 20:47:18 2002 +++ b/drivers/usb/auerswald.c Wed Feb 6 20:47:18 2002 @@ -49,7 +49,7 @@ /*-------------------------------------------------------------------*/ /* Version Information */ -#define DRIVER_VERSION "0.9.9" +#define DRIVER_VERSION "0.9.11" #define DRIVER_AUTHOR "Wolfgang Mües " #define DRIVER_DESC "Auerswald PBX/System Telephone usb driver" @@ -191,6 +191,13 @@ 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 */ @@ -330,7 +337,7 @@ urb = acep->urbp; dbg ("auerchain_complete: submitting next urb from chain"); urb->status = 0; /* needed! */ - result = usb_submit_urb( urb); + result = usb_submit_urb(urb, GFP_KERNEL); /* check for submit errors */ if (result) { @@ -408,7 +415,7 @@ if (acep) { dbg("submitting urb immediate"); urb->status = 0; /* needed! */ - result = usb_submit_urb( urb); + result = usb_submit_urb(urb, GFP_KERNEL); /* check for submit errors */ if (result) { urb->status = result; @@ -600,8 +607,10 @@ /* completion handler for synchronous chained URBs */ static void auerchain_blocking_completion (struct urb *urb) { - wait_queue_head_t *wakeup = (wait_queue_head_t *)urb->context; - wake_up (wakeup); + pauerchain_chs_t pchs = (pauerchain_chs_t)urb->context; + pchs->done = 1; + wmb(); + wake_up (&pchs->wqh); } @@ -609,36 +618,43 @@ static int auerchain_start_wait_urb (pauerchain_t acp, struct urb *urb, int timeout, int* actual_length) { DECLARE_WAITQUEUE (wait, current); - DECLARE_WAIT_QUEUE_HEAD (wqh); + auerchain_chs_t chs; int status; dbg ("auerchain_start_wait_urb called"); - init_waitqueue_head (&wqh); - current->state = TASK_INTERRUPTIBLE; - add_wait_queue (&wqh, &wait); - urb->context = &wqh; - status = auerchain_submit_urb ( acp, urb); + init_waitqueue_head (&chs.wqh); + chs.done = 0; + + set_current_state (TASK_UNINTERRUPTIBLE); + add_wait_queue (&chs.wqh, &wait); + urb->context = &chs; + status = auerchain_submit_urb (acp, urb); if (status) { /* something went wrong */ - current->state = TASK_RUNNING; - remove_wait_queue (&wqh, &wait); + set_current_state (TASK_RUNNING); + remove_wait_queue (&chs.wqh, &wait); return status; } - if (urb->status == -EINPROGRESS) { - while (timeout && urb->status == -EINPROGRESS) - status = timeout = schedule_timeout (timeout); - } else - status = 1; - - current->state = TASK_RUNNING; - remove_wait_queue (&wqh, &wait); + while (timeout && !chs.done) + { + timeout = schedule_timeout (timeout); + set_current_state(TASK_UNINTERRUPTIBLE); + rmb(); + } - if (!status) { - /* timeout */ - dbg ("auerchain_start_wait_urb: timeout"); - auerchain_unlink_urb (acp, urb); /* remove urb safely */ - status = -ETIMEDOUT; + set_current_state (TASK_RUNNING); + remove_wait_queue (&chs.wqh, &wait); + + if (!timeout && !chs.done) { + if (urb->status != -EINPROGRESS) { /* No callback?!! */ + dbg ("auerchain_start_wait_urb: raced timeout"); + status = urb->status; + } else { + dbg ("auerchain_start_wait_urb: timeout"); + auerchain_unlink_urb (acp, urb); /* remove urb safely */ + status = -ETIMEDOUT; + } } else status = urb->status; @@ -932,6 +948,8 @@ /* 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++; @@ -1128,7 +1146,7 @@ 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); + ret = usb_submit_urb (cp->inturbp, GFP_KERNEL); intoend: if (ret < 0) { @@ -1376,9 +1394,6 @@ } up (&dev_table_mutex); - /* prevent module unloading */ - MOD_INC_USE_COUNT; - /* we have access to the device. Now lets allocate memory */ ccp = (pauerchar_t) kmalloc(sizeof(auerchar_t), GFP_KERNEL); if (ccp == NULL) { @@ -1415,7 +1430,6 @@ /* Error exit */ ofail: up (&cp->mutex); auerchar_delete (ccp); - MOD_DEC_USE_COUNT; return ret; } @@ -1568,6 +1582,8 @@ unsigned long flags; pauerchar_t ccp = (pauerchar_t) file->private_data; pauerbuf_t bp = NULL; + wait_queue_t wait; + dbg ("auerchar_read"); /* Error checking */ @@ -1630,6 +1646,11 @@ /* a read buffer is not available. Try to get the next data block. */ doreadlist: + /* Preparing for sleep */ + init_waitqueue_entry (&wait, current); + set_current_state (TASK_INTERRUPTIBLE); + add_wait_queue (&ccp->readwait, &wait); + bp = NULL; spin_lock_irqsave (&ccp->bufctl.lock, flags); if (!list_empty (&ccp->bufctl.rec_buff_list)) { @@ -1644,20 +1665,25 @@ if (bp) { ccp->readbuf = bp; ccp->readoffset = AUH_SIZE; /* for headerbyte */ + set_current_state (TASK_RUNNING); + remove_wait_queue (&ccp->readwait, &wait); goto doreadbuf; /* now we can read! */ } /* no data available. Should we wait? */ if (file->f_flags & O_NONBLOCK) { dbg ("No read buffer available, returning -EAGAIN"); + set_current_state (TASK_RUNNING); + remove_wait_queue (&ccp->readwait, &wait); up (&ccp->readmutex); up (&ccp->mutex); - return -EAGAIN; /* nonblocking, no data available */ + return -EAGAIN; /* nonblocking, no data available */ } /* yes, we should wait! */ up (&ccp->mutex); /* allow other operations while we wait */ - interruptible_sleep_on (&ccp->readwait); + schedule(); + remove_wait_queue (&ccp->readwait, &wait); if (signal_pending (current)) { /* waked up by a signal */ up (&ccp->readmutex); @@ -1688,6 +1714,7 @@ pauerbuf_t bp; unsigned long flags; int ret; + wait_queue_t wait; dbg ("auerchar_write %d bytes", len); @@ -1724,6 +1751,11 @@ up (&ccp->mutex); return -EIO; } + /* Prepare for sleep */ + init_waitqueue_entry (&wait, current); + set_current_state (TASK_INTERRUPTIBLE); + add_wait_queue (&cp->bufferwait, &wait); + /* Try to get a buffer from the device pool. We can't use a buffer from ccp->bufctl because the write command will last beond a release() */ @@ -1744,16 +1776,22 @@ /* NONBLOCK: don't wait */ if (file->f_flags & O_NONBLOCK) { + set_current_state (TASK_RUNNING); + remove_wait_queue (&cp->bufferwait, &wait); return -EAGAIN; } /* BLOCKING: wait */ - interruptible_sleep_on (&cp->bufferwait); + schedule(); + remove_wait_queue (&cp->bufferwait, &wait); if (signal_pending (current)) { /* waked up by a signal */ return -ERESTARTSYS; } goto write_again; + } else { + set_current_state (TASK_RUNNING); + remove_wait_queue (&cp->bufferwait, &wait); } /* protect against too big write requests */ @@ -1763,6 +1801,8 @@ if (copy_from_user ( bp->bufp+AUH_SIZE, buf, len)) { dbg ("copy_from_user failed"); auerbuf_releasebuf (bp); + /* Wake up all processes waiting for a buffer */ + wake_up (&cp->bufferwait); up (&cp->mutex); up (&ccp->mutex); return -EIO; @@ -1787,6 +1827,8 @@ if (ret) { dbg ("auerchar_write: nonzero result of auerchain_submit_urb %d", ret); auerbuf_releasebuf (bp); + /* Wake up all processes waiting for a buffer */ + wake_up (&cp->bufferwait); up (&ccp->mutex); return -EIO; } @@ -1831,9 +1873,6 @@ up (&ccp->mutex); auerchar_delete (ccp); - /* release the module */ - MOD_DEC_USE_COUNT; - return 0; } @@ -2154,3 +2193,4 @@ module_exit (auerswald_cleanup); /* --------------------------------------------------------------------- */ +