/*-------------------------------------------------------------------*/
/* Version Information */
-#define DRIVER_VERSION "0.9.9"
+#define DRIVER_VERSION "0.9.11"
#define DRIVER_AUTHOR "Wolfgang Mües <wmues@nexgo.de>"
#define DRIVER_DESC "Auerswald PBX/System Telephone usb driver"
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 */
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) {
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;
/* 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);
}
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;
+ while (timeout && !chs.done)
+ {
+ timeout = schedule_timeout (timeout);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ rmb();
+ }
- current->state = TASK_RUNNING;
- remove_wait_queue (&wqh, &wait);
+ set_current_state (TASK_RUNNING);
+ remove_wait_queue (&chs.wqh, &wait);
- if (!status) {
- /* timeout */
- dbg ("auerchain_start_wait_urb: timeout");
- auerchain_unlink_urb (acp, urb); /* remove urb safely */
- status = -ETIMEDOUT;
+ 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;
/* 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++;
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) {
}
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) {
/* Error exit */
ofail: up (&cp->mutex);
auerchar_delete (ccp);
- MOD_DEC_USE_COUNT;
return ret;
}
unsigned long flags;
pauerchar_t ccp = (pauerchar_t) file->private_data;
pauerbuf_t bp = NULL;
+ wait_queue_t wait;
+
dbg ("auerchar_read");
/* Error checking */
/* 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)) {
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);
pauerbuf_t bp;
unsigned long flags;
int ret;
+ wait_queue_t wait;
dbg ("auerchar_write %d bytes", len);
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() */
/* 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 */
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;
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;
}
up (&ccp->mutex);
auerchar_delete (ccp);
- /* release the module */
- MOD_DEC_USE_COUNT;
-
return 0;
}
module_exit (auerswald_cleanup);
/* --------------------------------------------------------------------- */
+