|
@@ -113,9 +113,9 @@ static const char hcd_name[] = "isp116x-hcd";
|
|
|
|
|
|
struct isp116x isp116x_dev;
|
|
|
struct isp116x_platform_data isp116x_board;
|
|
|
-int got_rhsc = 0; /* root hub status change */
|
|
|
+static int got_rhsc; /* root hub status change */
|
|
|
struct usb_device *devgone; /* device which was disconnected */
|
|
|
-int rh_devnum = 0; /* address of Root Hub endpoint */
|
|
|
+static int rh_devnum; /* address of Root Hub endpoint */
|
|
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
|
|
|
@@ -522,11 +522,13 @@ static int unpack_fifo(struct isp116x *isp116x, struct usb_device *dev,
|
|
|
done += PTD_GET_LEN(&ptd[i]);
|
|
|
|
|
|
cc = PTD_GET_CC(&ptd[i]);
|
|
|
- if (cc == TD_DATAUNDERRUN) { /* underrun is no error... */
|
|
|
- DBG("allowed data underrun");
|
|
|
- cc = TD_CC_NOERROR;
|
|
|
- }
|
|
|
- if (cc != TD_CC_NOERROR && ret == TD_CC_NOERROR)
|
|
|
+
|
|
|
+ /* Data underrun means basically that we had more buffer space than
|
|
|
+ * the function had data. It is perfectly normal but upper levels have
|
|
|
+ * to know how much we actually transferred.
|
|
|
+ */
|
|
|
+ if (cc == TD_NOTACCESSED ||
|
|
|
+ (cc != TD_CC_NOERROR && (ret == TD_CC_NOERROR || ret == TD_DATAUNDERRUN)))
|
|
|
ret = cc;
|
|
|
}
|
|
|
|
|
@@ -592,11 +594,19 @@ static int isp116x_interrupt(struct isp116x *isp116x)
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-#define PTD_NUM 64 /* it should be enougth... */
|
|
|
-struct ptd ptd[PTD_NUM];
|
|
|
+/* With one PTD we can transfer almost 1K in one go;
|
|
|
+ * HC does the splitting into endpoint digestible transactions
|
|
|
+ */
|
|
|
+struct ptd ptd[1];
|
|
|
+
|
|
|
static inline int max_transfer_len(struct usb_device *dev, unsigned long pipe)
|
|
|
{
|
|
|
- return min(PTD_NUM * usb_maxpacket(dev, pipe), PTD_NUM * 16);
|
|
|
+ unsigned mpck = usb_maxpacket(dev, pipe);
|
|
|
+
|
|
|
+ /* One PTD can transfer 1023 bytes but try to always
|
|
|
+ * transfer multiples of endpoint buffer size
|
|
|
+ */
|
|
|
+ return 1023 / mpck * mpck;
|
|
|
}
|
|
|
|
|
|
/* Do an USB transfer
|
|
@@ -610,13 +620,21 @@ static int isp116x_submit_job(struct usb_device *dev, unsigned long pipe,
|
|
|
int max = usb_maxpacket(dev, pipe);
|
|
|
int dir_out = usb_pipeout(pipe);
|
|
|
int speed_low = usb_pipeslow(pipe);
|
|
|
- int i, done, stat, timeout, cc;
|
|
|
- int retries = 10;
|
|
|
+ int i, done = 0, stat, timeout, cc;
|
|
|
+
|
|
|
+ /* 500 frames or 0.5s timeout when function is busy and NAKs transactions for a while */
|
|
|
+ int retries = 500;
|
|
|
|
|
|
DBG("------------------------------------------------");
|
|
|
dump_msg(dev, pipe, buffer, len, "SUBMIT");
|
|
|
DBG("------------------------------------------------");
|
|
|
|
|
|
+ if (len >= 1024) {
|
|
|
+ ERR("Too big job");
|
|
|
+ dev->status = USB_ST_CRC_ERR;
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
if (isp116x->disabled) {
|
|
|
ERR("EPIPE");
|
|
|
dev->status = USB_ST_CRC_ERR;
|
|
@@ -653,29 +671,15 @@ static int isp116x_submit_job(struct usb_device *dev, unsigned long pipe,
|
|
|
isp116x_write_reg32(isp116x, HCINTSTAT, 0xff);
|
|
|
|
|
|
/* Prepare the PTD data */
|
|
|
- done = 0;
|
|
|
- i = 0;
|
|
|
- do {
|
|
|
- ptd[i].count = PTD_CC_MSK | PTD_ACTIVE_MSK |
|
|
|
- PTD_TOGGLE(usb_gettoggle(dev, epnum, dir_out));
|
|
|
- ptd[i].mps = PTD_MPS(max) | PTD_SPD(speed_low) | PTD_EP(epnum);
|
|
|
- ptd[i].len = PTD_LEN(max > len - done ? len - done : max) |
|
|
|
- PTD_DIR(dir);
|
|
|
- ptd[i].faddr = PTD_FA(usb_pipedevice(pipe));
|
|
|
-
|
|
|
- usb_dotoggle(dev, epnum, dir_out);
|
|
|
- done += PTD_GET_LEN(&ptd[i]);
|
|
|
- i++;
|
|
|
- if (i >= PTD_NUM) {
|
|
|
- ERR("****** Cannot pack buffer! ******");
|
|
|
- dev->status = USB_ST_BUF_ERR;
|
|
|
- return -1;
|
|
|
- }
|
|
|
- } while (done < len);
|
|
|
- ptd[i - 1].mps |= PTD_LAST_MSK;
|
|
|
+ ptd->count = PTD_CC_MSK | PTD_ACTIVE_MSK |
|
|
|
+ PTD_TOGGLE(usb_gettoggle(dev, epnum, dir_out));
|
|
|
+ ptd->mps = PTD_MPS(max) | PTD_SPD(speed_low) | PTD_EP(epnum) | PTD_LAST_MSK;
|
|
|
+ ptd->len = PTD_LEN(len) | PTD_DIR(dir);
|
|
|
+ ptd->faddr = PTD_FA(usb_pipedevice(pipe));
|
|
|
|
|
|
+retry_same:
|
|
|
/* Pack data into FIFO ram */
|
|
|
- pack_fifo(isp116x, dev, pipe, ptd, i, buffer, len);
|
|
|
+ pack_fifo(isp116x, dev, pipe, ptd, 1, buffer, len);
|
|
|
#ifdef EXTRA_DELAY
|
|
|
wait_ms(EXTRA_DELAY);
|
|
|
#endif
|
|
@@ -738,17 +742,42 @@ static int isp116x_submit_job(struct usb_device *dev, unsigned long pipe,
|
|
|
}
|
|
|
|
|
|
/* Unpack data from FIFO ram */
|
|
|
- cc = unpack_fifo(isp116x, dev, pipe, ptd, i, buffer, len);
|
|
|
+ cc = unpack_fifo(isp116x, dev, pipe, ptd, 1, buffer, len);
|
|
|
+
|
|
|
+ i = PTD_GET_COUNT(ptd);
|
|
|
+ done += i;
|
|
|
+ buffer += i;
|
|
|
+ len -= i;
|
|
|
|
|
|
- /* Mmm... sometime we get 0x0f as cc which is a non sense!
|
|
|
- * Just retry the transfer...
|
|
|
+ /* There was some kind of real problem; Prepare the PTD again
|
|
|
+ * and retry from the failed transaction on
|
|
|
*/
|
|
|
- if (cc == 0x0f && retries-- > 0) {
|
|
|
- usb_dotoggle(dev, epnum, dir_out);
|
|
|
- goto retry;
|
|
|
+ if (cc && cc != TD_NOTACCESSED && cc != TD_DATAUNDERRUN) {
|
|
|
+ if (retries >= 100) {
|
|
|
+ retries -= 100;
|
|
|
+ /* The chip will have toggled the toggle bit for the failed
|
|
|
+ * transaction too. We have to toggle it back.
|
|
|
+ */
|
|
|
+ usb_settoggle(dev, epnum, dir_out, !PTD_GET_TOGGLE(ptd));
|
|
|
+ goto retry;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /* "Normal" errors; TD_NOTACCESSED would mean in effect that the function have NAKed
|
|
|
+ * the transactions from the first on for the whole frame. It may be busy and we retry
|
|
|
+ * with the same PTD. PTD_ACTIVE (and not TD_NOTACCESSED) would mean that some of the
|
|
|
+ * PTD didn't make it because the function was busy or the frame ended before the PTD
|
|
|
+ * finished. We prepare the rest of the data and try again.
|
|
|
+ */
|
|
|
+ else if (cc == TD_NOTACCESSED || PTD_GET_ACTIVE(ptd) || (cc != TD_DATAUNDERRUN && PTD_GET_COUNT(ptd) < PTD_GET_LEN(ptd))) {
|
|
|
+ if (retries) {
|
|
|
+ --retries;
|
|
|
+ if (cc == TD_NOTACCESSED && PTD_GET_ACTIVE(ptd) && !PTD_GET_COUNT(ptd)) goto retry_same;
|
|
|
+ usb_settoggle(dev, epnum, dir_out, PTD_GET_TOGGLE(ptd));
|
|
|
+ goto retry;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- if (cc != TD_CC_NOERROR) {
|
|
|
+ if (cc != TD_CC_NOERROR && cc != TD_DATAUNDERRUN) {
|
|
|
DBG("****** completition code error %x ******", cc);
|
|
|
switch (cc) {
|
|
|
case TD_CC_BITSTUFFING:
|
|
@@ -766,6 +795,7 @@ static int isp116x_submit_job(struct usb_device *dev, unsigned long pipe,
|
|
|
}
|
|
|
return -cc;
|
|
|
}
|
|
|
+ else usb_settoggle(dev, epnum, dir_out, PTD_GET_TOGGLE(ptd));
|
|
|
|
|
|
dump_msg(dev, pipe, buffer, len, "SUBMIT(ret)");
|
|
|
|
|
@@ -1369,6 +1399,8 @@ int usb_lowlevel_init(void)
|
|
|
|
|
|
DBG("");
|
|
|
|
|
|
+ got_rhsc = rh_devnum = 0;
|
|
|
+
|
|
|
/* Init device registers addr */
|
|
|
isp116x->addr_reg = (u16 *) ISP116X_HCD_ADDR;
|
|
|
isp116x->data_reg = (u16 *) ISP116X_HCD_DATA;
|