Signed-off-by: Luca Ellero <luca.ellero@xxxxxxxxxxxxxxxx> --- drivers/staging/ced1401/ced_ioc.c | 212 +++++++++++++++++++++++-------------- 1 file changed, 131 insertions(+), 81 deletions(-) diff --git a/drivers/staging/ced1401/ced_ioc.c b/drivers/staging/ced1401/ced_ioc.c index fb4e8a3..717b4ce 100644 --- a/drivers/staging/ced1401/ced_ioc.c +++ b/drivers/staging/ced1401/ced_ioc.c @@ -63,8 +63,11 @@ static void ced_flush_in_buff(struct ced_data *ced) { dev_dbg(&ced->interface->dev, "%s: current_state=%d\n", __func__, ced->current_state); - if (ced->current_state == U14ERR_TIME) /* Do nothing if hardware in trouble */ + + /* Do nothing if hardware in trouble */ + if (ced->current_state == U14ERR_TIME) return; + /* Kill off any pending I/O */ /* CharRead_Cancel(pDevObject); */ spin_lock_irq(&ced->char_in_lock); @@ -84,9 +87,11 @@ static int ced_put_chars(struct ced_data *ced, const char *ch, unsigned int count) { int ret; + spin_lock_irq(&ced->char_out_lock); /* get the output spin lock */ if ((OUTBUF_SZ - ced->num_output) >= count) { unsigned int u; + for (u = 0; u < count; u++) { ced->output_buffer[ced->out_buff_put++] = ch[u]; if (ced->out_buff_put >= OUTBUF_SZ) @@ -94,7 +99,9 @@ static int ced_put_chars(struct ced_data *ced, const char *ch, } ced->num_output += count; spin_unlock_irq(&ced->char_out_lock); - ret = ced_send_chars(ced); /* ...give a chance to transmit data */ + + /* ...give a chance to transmit data */ + ret = ced_send_chars(ced); } else { ret = U14ERR_NOOUT; /* no room at the out (ha-ha) */ spin_unlock_irq(&ced->char_out_lock); @@ -140,6 +147,7 @@ int ced_send_string(struct ced_data *ced, const char __user *data, int ced_send_char(struct ced_data *ced, char c) { int ret; + mutex_lock(&ced->io_mutex); /* Protect disconnect from new i/o */ ret = ced_put_chars(ced, &c, 1); dev_dbg(&ced->interface->dev, "ced_send_char >%c< (0x%02x)\n", c, c); @@ -177,6 +185,7 @@ int ced_send_char(struct ced_data *ced, char c) int ced_get_state(struct ced_data *ced, __u32 *state, __u32 *error) { int got; + dev_dbg(&ced->interface->dev, "%s: entry\n", __func__); *state = 0xFFFFFFFF; /* Start off with invalid state */ @@ -192,6 +201,7 @@ int ced_get_state(struct ced_data *ced, __u32 *state, __u32 *error) *error = 0; } else { int device; + dev_dbg(&ced->interface->dev, "%s: Success, state: 0x%x, 0x%x\n", __func__, ced->stat_buf[0], ced->stat_buf[1]); @@ -233,23 +243,32 @@ int ced_read_write_cancel(struct ced_data *ced) int ntStatus = STATUS_SUCCESS; bool bResult = false; unsigned int i; - /* We can fill this in when we know how we will implement the staged transfer stuff */ + + /* We can fill this in when we know how we */ + /* will implement the staged transfer stuff */ spin_lock_irq(&ced->staged_lock); - if (ced->staged_urb_pending) { /* anything to be cancelled? May need more... */ + /* anything to be cancelled? May need more... */ + if (ced->staged_urb_pending) { dev_info(&ced->interface - dev, "ced_read_write_cancel about to cancel Urb\n"); /* Clear the staging done flag */ /* KeClearEvent(&ced->StagingDoneEvent); */ USB_ASSERT(ced->pStagedIrp != NULL); - /* Release the spinlock first otherwise the completion routine may hang */ - /* on the spinlock while this function hands waiting for the event. */ + /* Release the spinlock first otherwise the completion */ + /* routine may hang on the spinlock while this function */ + /* hands waiting for the event. */ spin_unlock_irq(&ced->staged_lock); - bResult = IoCancelIrp(ced->pStagedIrp); /* Actually do the cancel */ + + /* Actually do the cancel */ + bResult = IoCancelIrp(ced->pStagedIrp); + if (bResult) { LARGE_INTEGER timeout; - timeout.QuadPart = -10000000; /* Use a timeout of 1 second */ + + /* Use a timeout of 1 second */ + timeout.QuadPart = -10000000; dev_info(&ced->interface - dev, "%s: about to wait till done\n", __func__); ntStatus = @@ -261,9 +280,11 @@ int ced_read_write_cancel(struct ced_data *ced) "%s: cancellation failed\n", __func__); ntStatus = U14ERR_FAIL; } - USB_KdPrint(DBGLVL_DEFAULT, - ("ced_read_write_cancel ntStatus = 0x%x decimal %d\n", - ntStatus, ntStatus)); + USB_KdPrint( + DBGLVL_DEFAULT, + ("ced_read_write_cancel ntStatus = 0x%x decimal %d\n", + ntStatus, + ntStatus)); } else spin_unlock_irq(&ced->staged_lock); @@ -283,6 +304,7 @@ static int ced_in_self_test(struct ced_data *ced, unsigned int *stat) { unsigned int state, error; int ret = ced_get_state(ced, &state, &error); /* see if in self-test */ + if (ret == U14ERR_NOERROR) /* if all still OK */ ret = (state == (unsigned int)-1) || /* TX problem or... */ ((state & 0xff) == 0x80); /* ...self test */ @@ -311,6 +333,7 @@ static int ced_in_self_test(struct ced_data *ced, unsigned int *stat) static bool ced_is_1401(struct ced_data *ced) { int ret; + dev_dbg(&ced->interface->dev, "%s\n", __func__); ced_draw_down(ced); /* wait for, then kill outstanding Urbs */ @@ -334,11 +357,13 @@ static bool ced_is_1401(struct ced_data *ced) ced->dma_flag = MODE_CHAR; /* Clear DMA mode flag regardless! */ if (ret == 0) { /* if all is OK still */ unsigned int state; + ret = ced_in_self_test(ced, &state); /* see if likely in */ - /* self test */ + /* self test */ if (ret > 0) { /* do we need to wait for self-test? */ /* when to give up */ unsigned long timeout = jiffies + 30 * HZ; + while ((ret > 0) && time_before(jiffies, timeout)) { schedule(); /* let other stuff run */ @@ -377,9 +402,11 @@ static bool ced_quick_check(struct ced_data *ced, bool test_buff, bool ret = false; /* assume it will fail and we will reset */ bool short_test; - short_test = ((ced->dma_flag == MODE_CHAR) && /* no DMA running */ - (!ced->force_reset) && /* Not had a real reset forced */ - (ced->current_state >= U14ERR_STD)); /* No 1401 errors stored */ + short_test = ((ced->dma_flag == MODE_CHAR) && /* no DMA running */ + /* Not had a real reset forced */ + (!ced->force_reset) && + /* No 1401 errors stored */ + (ced->current_state >= U14ERR_STD)); dev_dbg(&ced->interface->dev, "%s: DMAFlag:%d, state:%d, force:%d, testBuff:%d, short:%d\n", @@ -387,18 +414,26 @@ static bool ced_quick_check(struct ced_data *ced, bool test_buff, test_buff, short_test); if ((test_buff) && /* Buffer check requested, and... */ - (ced->num_input || ced->num_output)) { /* ...characters were in the buffer? */ - short_test = false; /* Then do the full test */ - dev_dbg(&ced->interface->dev, - "%s: will reset as buffers not empty\n", __func__); + /* ...characters were in the buffer? */ + (ced->num_input || ced->num_output)) { + short_test = false; /* Then do the full test */ + dev_dbg(&ced->interface->dev, + "%s: will reset as buffers not empty\n", + __func__); } - if (short_test || !can_reset) { /* Still OK to try the short test? */ - /* Always test if no reset - we want state update */ + /* Still OK to try the short test? */ + /* Always test if no reset - we want state update */ + if (short_test || !can_reset) { + unsigned int state, error; + dev_dbg(&ced->interface->dev, "%s: ced_get_state\n", __func__); - if (ced_get_state(ced, &state, &error) == U14ERR_NOERROR) { /* Check on the 1401 state */ - if ((state & 0xFF) == 0) /* If call worked, check the status value */ + + /* Check on the 1401 state */ + if (ced_get_state(ced, &state, &error) == U14ERR_NOERROR) { + /* If call worked, check the status value */ + if ((state & 0xFF) == 0) ret = true; /* If that was zero, all is OK, */ /* no reset needed */ } @@ -424,7 +459,7 @@ int ced_reset(struct ced_data *ced) mutex_lock(&ced->io_mutex); /* Protect disconnect from new i/o */ dev_dbg(&ced->interface->dev, "%s: About to call ced_quick_check\n", __func__); - ced_quick_check(ced, true, true); /* Check 1401, reset if not OK */ + ced_quick_check(ced, true, true); /* Check 1401, reset if not OK */ mutex_unlock(&ced->io_mutex); return U14ERR_NOERROR; } @@ -437,6 +472,7 @@ int ced_reset(struct ced_data *ced) int ced_get_char(struct ced_data *ced) { int ret = U14ERR_NOIN; /* assume we will get nothing */ + mutex_lock(&ced->io_mutex); /* Protect disconnect from new i/o */ dev_dbg(&ced->interface->dev, "%s\n", __func__); @@ -475,6 +511,7 @@ int ced_get_string(struct ced_data *ced, char __user *user, int n) { int available; /* character in the buffer */ int ret = U14ERR_NOIN; + if (n <= 0) return -ENOMEM; @@ -492,6 +529,7 @@ int ced_get_string(struct ced_data *ced, char __user *user, int n) int got = 0; int n_copy_to_user; /* number to copy to user */ char data; + do { data = ced->input_buffer[ced->in_buff_get++]; if (data == CR_CHAR) /* replace CR with zero */ @@ -507,7 +545,7 @@ int ced_get_string(struct ced_data *ced, char __user *user, int n) if (data) { /* do we need null */ buffer[got] = (char)0; /* make it tidy */ if (got < n) /* if space in user buffer... */ - ++n_copy_to_user; /* ...copy the 0 as well. */ + ++n_copy_to_user; /* ...copy the 0 as well. */ } ced->num_input -= got; @@ -534,6 +572,7 @@ int ced_get_string(struct ced_data *ced, char __user *user, int n) int ced_stat_1401(struct ced_data *ced) { int ret; + mutex_lock(&ced->io_mutex); /* Protect disconnect from new i/o */ ced_allowi(ced); /* make sure we allow pending chars */ ced_send_chars(ced); /* in both directions */ @@ -563,6 +602,7 @@ int ced_line_count(struct ced_data *ced) unsigned int index = ced->in_buff_get; /* Position for search end */ unsigned int end = ced->in_buff_put; + do { if (ced->input_buffer[index++] == CR_CHAR) ++ret; /* inc count if CR */ @@ -618,6 +658,7 @@ int ced_clear_area(struct ced_data *ced, int area) } else { /* to save typing */ struct transarea *ta = &ced->trans_def[area]; + if (!ta->used) /* if not used... */ ret = U14ERR_NOTSET; /* ...nothing to be done */ else { @@ -703,12 +744,11 @@ static int ced_set_area(struct ced_data *ced, int area, char __user *buf, unsigned long start = ((unsigned long)buf) & PAGE_MASK; unsigned int offset = ((unsigned long)buf) & (PAGE_SIZE - 1); int len = (length + offset + PAGE_SIZE - 1) >> PAGE_SHIFT; - struct transarea *ta = &ced->trans_def[area]; /* to save typing */ struct page **pages = NULL; /* space for page tables */ int n_pages = 0; /* and number of pages */ - int ret = ced_clear_area(ced, area); /* see if OK to use this area */ + if ((ret != U14ERR_NOTSET) && /* if not area unused and... */ (ret != U14ERR_NOERROR)) /* ...not all OK, then... */ return ret; /* ...we cannot use this area */ @@ -807,6 +847,7 @@ int ced_set_transfer(struct ced_data *ced, int ced_unset_transfer(struct ced_data *ced, int area) { int ret; + mutex_lock(&ced->io_mutex); ret = ced_clear_area(ced, area); mutex_unlock(&ced->io_mutex); @@ -825,6 +866,7 @@ int ced_set_event(struct ced_data *ced, struct transfer_event __user *ute) { int ret = U14ERR_NOERROR; struct transfer_event te; + struct transarea *ta; /* get a local copy of the data */ if (copy_from_user(&te, ute, sizeof(te))) @@ -832,27 +874,27 @@ int ced_set_event(struct ced_data *ced, struct transfer_event __user *ute) if (te.wAreaNum >= MAX_TRANSAREAS) /* the area must exist */ return U14ERR_BADAREA; - else { - struct transarea *ta = &ced->trans_def[te.wAreaNum]; - /* make sure we have no competitor */ - mutex_lock(&ced->io_mutex); - spin_lock_irq(&ced->staged_lock); + ta = &ced->trans_def[te.wAreaNum]; - if (ta->used) { /* area must be in use */ - ta->event_st = te.dwStart; /* set area regions */ + /* make sure we have no competitor */ + mutex_lock(&ced->io_mutex); + spin_lock_irq(&ced->staged_lock); - /* set size (0 cancels it) */ - ta->event_sz = te.dwLength; + if (ta->used) { /* area must be in use */ + ta->event_st = te.dwStart; /* set area regions */ + + /* set size (0 cancels it) */ + ta->event_sz = te.dwLength; + + /* set the direction */ + ta->event_to_host = te.wFlags & 1; + ta->wake_up = 0; /* zero the wake up count */ + } else + ret = U14ERR_NOTSET; + spin_unlock_irq(&ced->staged_lock); + mutex_unlock(&ced->io_mutex); - /* set the direction */ - ta->event_to_host = te.wFlags & 1; - ta->wake_up = 0; /* zero the wake up count */ - } else - ret = U14ERR_NOTSET; - spin_unlock_irq(&ced->staged_lock); - mutex_unlock(&ced->io_mutex); - } return ret == U14ERR_NOERROR ? (te.iSetEvent ? 1 : U14ERR_NOERROR) : ret; } @@ -866,59 +908,61 @@ int ced_set_event(struct ced_data *ced, struct transfer_event __user *ute) int ced_wait_event(struct ced_data *ced, int area, int time_out) { int ret; + int wait; + struct transarea *ta; + if ((unsigned)area >= MAX_TRANSAREAS) return U14ERR_BADAREA; - else { - int wait; - struct transarea *ta = &ced->trans_def[area]; - /* convert timeout to jiffies */ - time_out = (time_out * HZ + 999) / 1000; + ta = &ced->trans_def[area]; - /* We cannot wait holding the mutex, but we check the flags */ - /* while holding it. This may well be pointless as another */ - /* thread could get in between releasing it and the wait */ - /* call. However, this would have to clear the wake_up flag. */ - /* However, the !ta->used may help us in this case. */ + /* convert timeout to jiffies */ + time_out = (time_out * HZ + 999) / 1000; - /* make sure we have no competitor */ - mutex_lock(&ced->io_mutex); - if (!ta->used || !ta->event_sz) /* check something to */ - /* wait for... */ - return U14ERR_NOTSET; /* ...else we do nothing */ - mutex_unlock(&ced->io_mutex); + /* We cannot wait holding the mutex, but we check the flags */ + /* while holding it. This may well be pointless as another */ + /* thread could get in between releasing it and the wait */ + /* call. However, this would have to clear the wake_up flag. */ + /* However, the !ta->used may help us in this case. */ - if (time_out) - wait = wait_event_interruptible_timeout(ta->event, - ta->wake_up || - !ta->used, - time_out); - else - wait = wait_event_interruptible(ta->event, + /* make sure we have no competitor */ + mutex_lock(&ced->io_mutex); + if (!ta->used || !ta->event_sz) /* check something to */ + /* wait for... */ + return U14ERR_NOTSET; /* ...else we do nothing */ + mutex_unlock(&ced->io_mutex); + + if (time_out) + wait = wait_event_interruptible_timeout(ta->event, ta->wake_up || - !ta->used); + !ta->used, + time_out); + else + wait = wait_event_interruptible(ta->event, + ta->wake_up || !ta->used); - if (wait) - ret = -ERESTARTSYS; /* oops - we have had a SIGNAL */ - else - ret = ta->wake_up; /* else the wakeup count */ + if (wait) + ret = -ERESTARTSYS; /* oops - we have had a SIGNAL */ + else + ret = ta->wake_up; /* else the wakeup count */ + + spin_lock_irq(&ced->staged_lock); + ta->wake_up = 0; /* clear the flag */ + spin_unlock_irq(&ced->staged_lock); - spin_lock_irq(&ced->staged_lock); - ta->wake_up = 0; /* clear the flag */ - spin_unlock_irq(&ced->staged_lock); - } return ret; } /**************************************************************************** ** ced_test_event -** Test the event to see if a ced_wait_event would return immediately. Returns the -** number of times a block completed since the last call, or 0 if none or a +** Test the event to see if a ced_wait_event would return immediately. Returns +** the number of times a block completed since the last call, or 0 if none or a ** negative error. ****************************************************************************/ int ced_test_event(struct ced_data *ced, int area) { int ret; + if ((unsigned)area >= MAX_TRANSAREAS) ret = U14ERR_BADAREA; else { @@ -998,6 +1042,7 @@ int ced_kill_io(struct ced_data *ced) int ced_state_of_1401(struct ced_data *ced) { int ret; + mutex_lock(&ced->io_mutex); ced_quick_check(ced, false, false); /* get state up to date, no reset */ @@ -1018,6 +1063,7 @@ int ced_state_of_1401(struct ced_data *ced) int ced_start_self_test(struct ced_data *ced) { int got; + mutex_lock(&ced->io_mutex); dev_dbg(&ced->interface->dev, "%s\n", __func__); @@ -1050,6 +1096,7 @@ int ced_check_self_test(struct ced_data *ced, TGET_SELFTEST __user *ugst) unsigned int state, error; int ret; TGET_SELFTEST gst; /* local work space */ + memset(&gst, 0, sizeof(gst)); /* clear out the space (sets code 0) */ mutex_lock(&ced->io_mutex); @@ -1087,6 +1134,7 @@ int ced_check_self_test(struct ced_data *ced, TGET_SELFTEST __user *ugst) "Self-test error code %d\n", gst.code); } else { /* No error, check for timeout */ unsigned long now = jiffies; /* get current time */ + if (time_after(now, ced->self_test_time)) { gst.code = -2; /* Flag the timeout */ dev_dbg(&ced->interface->dev, @@ -1253,8 +1301,8 @@ int ced_dbg_poke(struct ced_data *ced, TDBGBLOCK __user *udb) /**************************************************************************** ** ced_dbg_ramp_data ** -** Execute the diagnostic ramp data operation. Parameters are in the CSBLOCK struct -** in order address, default, enable mask, size and repeats. +** Execute the diagnostic ramp data operation. Parameters are in the CSBLOCK +** struct in order address, default, enable mask, size and repeats. ****************************************************************************/ int ced_dbg_ramp_data(struct ced_data *ced, TDBGBLOCK __user *udb) { @@ -1426,6 +1474,7 @@ int ced_get_circ_block(struct ced_data *ced, TCIRCBLOCK __user *ucb) if (area < MAX_TRANSAREAS) { /* The area number must be OK */ /* Pointer to relevant info */ struct transarea *ta = &ced->trans_def[area]; + spin_lock_irq(&ced->staged_lock); /* Lock others out */ if ((ta->used) && (ta->circular) && /* Must be circular area */ @@ -1486,7 +1535,8 @@ int ced_free_circ_block(struct ced_data *ced, TCIRCBLOCK __user *ucb) bool waiting = false; if ((ta->blocks[0].size >= size) && /* Got anything? */ - (ta->blocks[0].offset == start)) { /* Must be legal data */ + /* Must be legal data */ + (ta->blocks[0].offset == start)) { ta->blocks[0].size -= size; ta->blocks[0].offset += size; -- 1.7.10.4 _______________________________________________ devel mailing list devel@xxxxxxxxxxxxxxxxxxxxxx http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel