|
@@ -1220,6 +1220,30 @@ static int ehci_endpoint_message ( struct usb_endpoint *ep,
|
1220
|
1220
|
return 0;
|
1221
|
1221
|
}
|
1222
|
1222
|
|
|
1223
|
+/**
|
|
1224
|
+ * Calculate number of transfer descriptors
|
|
1225
|
+ *
|
|
1226
|
+ * @v len Length of data
|
|
1227
|
+ * @v zlp Append a zero-length packet
|
|
1228
|
+ * @ret count Number of transfer descriptors
|
|
1229
|
+ */
|
|
1230
|
+static unsigned int ehci_endpoint_count ( size_t len, int zlp ) {
|
|
1231
|
+ unsigned int count;
|
|
1232
|
+
|
|
1233
|
+ /* Split into 16kB transfers. A single transfer can handle up
|
|
1234
|
+ * to 20kB if it happens to be page-aligned, or up to 16kB
|
|
1235
|
+ * with arbitrary alignment. We simplify the code by assuming
|
|
1236
|
+ * that we can fit only 16kB into each transfer.
|
|
1237
|
+ */
|
|
1238
|
+ count = ( ( len + EHCI_MTU - 1 ) / EHCI_MTU );
|
|
1239
|
+
|
|
1240
|
+ /* Append a zero-length transfer if applicable */
|
|
1241
|
+ if ( zlp || ( count == 0 ) )
|
|
1242
|
+ count++;
|
|
1243
|
+
|
|
1244
|
+ return count;
|
|
1245
|
+}
|
|
1246
|
+
|
1223
|
1247
|
/**
|
1224
|
1248
|
* Enqueue stream transfer
|
1225
|
1249
|
*
|
|
@@ -1232,29 +1256,40 @@ static int ehci_endpoint_stream ( struct usb_endpoint *ep,
|
1232
|
1256
|
struct io_buffer *iobuf, int zlp ) {
|
1233
|
1257
|
struct ehci_endpoint *endpoint = usb_endpoint_get_hostdata ( ep );
|
1234
|
1258
|
struct ehci_device *ehci = endpoint->ehci;
|
|
1259
|
+ void *data = iobuf->data;
|
|
1260
|
+ size_t len = iob_len ( iobuf );
|
|
1261
|
+ unsigned int count = ehci_endpoint_count ( len, zlp );
|
1235
|
1262
|
unsigned int input = ( ep->address & USB_DIR_IN );
|
1236
|
|
- struct ehci_transfer xfers[2];
|
|
1263
|
+ unsigned int flags = ( input ? EHCI_FL_PID_IN : EHCI_FL_PID_OUT );
|
|
1264
|
+ struct ehci_transfer xfers[count];
|
1237
|
1265
|
struct ehci_transfer *xfer = xfers;
|
1238
|
|
- size_t len = iob_len ( iobuf );
|
|
1266
|
+ size_t xfer_len;
|
|
1267
|
+ unsigned int i;
|
1239
|
1268
|
int rc;
|
1240
|
1269
|
|
1241
|
|
- /* Create transfer */
|
1242
|
|
- xfer->data = iobuf->data;
|
1243
|
|
- xfer->len = len;
|
1244
|
|
- xfer->flags = ( EHCI_FL_IOC |
|
1245
|
|
- ( input ? EHCI_FL_PID_IN : EHCI_FL_PID_OUT ) );
|
1246
|
|
- xfer++;
|
1247
|
|
- if ( zlp ) {
|
1248
|
|
- xfer->data = NULL;
|
1249
|
|
- xfer->len = 0;
|
1250
|
|
- assert ( ! input );
|
1251
|
|
- xfer->flags = ( EHCI_FL_IOC | EHCI_FL_PID_OUT );
|
|
1270
|
+ /* Create transfers */
|
|
1271
|
+ for ( i = 0 ; i < count ; i++ ) {
|
|
1272
|
+
|
|
1273
|
+ /* Calculate transfer length */
|
|
1274
|
+ xfer_len = EHCI_MTU;
|
|
1275
|
+ if ( xfer_len > len )
|
|
1276
|
+ xfer_len = len;
|
|
1277
|
+
|
|
1278
|
+ /* Create transfer */
|
|
1279
|
+ xfer->data = data;
|
|
1280
|
+ xfer->len = xfer_len;
|
|
1281
|
+ xfer->flags = flags;
|
|
1282
|
+
|
|
1283
|
+ /* Move to next transfer */
|
|
1284
|
+ data += xfer_len;
|
|
1285
|
+ len -= xfer_len;
|
1252
|
1286
|
xfer++;
|
1253
|
1287
|
}
|
|
1288
|
+ xfer[-1].flags |= EHCI_FL_IOC;
|
1254
|
1289
|
|
1255
|
1290
|
/* Enqueue transfer */
|
1256
|
1291
|
if ( ( rc = ehci_enqueue ( ehci, &endpoint->ring, iobuf, xfers,
|
1257
|
|
- ( xfer - xfers ) ) ) != 0 )
|
|
1292
|
+ count ) ) != 0 )
|
1258
|
1293
|
return rc;
|
1259
|
1294
|
|
1260
|
1295
|
return 0;
|