aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKristian Høgsberg <krh@redhat.com>2007-02-16 17:34:44 -0500
committerStefan Richter <stefanr@s5r6.in-berlin.de>2007-03-09 16:03:00 -0500
commit9b32d5f3074e9b1afaa39a360a59fd77a2214783 (patch)
tree441cde033cc8a55b7bc9715684c42554fa259cc4
parent500be7251a4af1a87aa48285a23a741f74a97a89 (diff)
firewire: Acummulate received iso headers and send them back to user space.
Signed-off-by: Kristian Høgsberg <krh@redhat.com> Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
-rw-r--r--drivers/firewire/fw-device-cdev.c25
-rw-r--r--drivers/firewire/fw-device-cdev.h2
-rw-r--r--drivers/firewire/fw-ohci.c49
-rw-r--r--drivers/firewire/fw-transaction.h5
4 files changed, 57 insertions, 24 deletions
diff --git a/drivers/firewire/fw-device-cdev.c b/drivers/firewire/fw-device-cdev.c
index 1ce33d4f91a3..6545fb8214d8 100644
--- a/drivers/firewire/fw-device-cdev.c
+++ b/drivers/firewire/fw-device-cdev.c
@@ -383,20 +383,24 @@ static int ioctl_send_response(struct client *client, void __user *arg)
383} 383}
384 384
385static void 385static void
386iso_callback(struct fw_iso_context *context, int status, u32 cycle, void *data) 386iso_callback(struct fw_iso_context *context, u32 cycle,
387 size_t header_length, void *header, void *data)
387{ 388{
388 struct client *client = data; 389 struct client *client = data;
389 struct iso_interrupt *interrupt; 390 struct iso_interrupt *interrupt;
390 391
391 interrupt = kzalloc(sizeof *interrupt, GFP_ATOMIC); 392 interrupt = kzalloc(sizeof *interrupt + header_length, GFP_ATOMIC);
392 if (interrupt == NULL) 393 if (interrupt == NULL)
393 return; 394 return;
394 395
395 interrupt->interrupt.type = FW_CDEV_EVENT_ISO_INTERRUPT; 396 interrupt->interrupt.type = FW_CDEV_EVENT_ISO_INTERRUPT;
396 interrupt->interrupt.closure = 0; 397 interrupt->interrupt.closure = 0;
397 interrupt->interrupt.cycle = cycle; 398 interrupt->interrupt.cycle = cycle;
399 interrupt->interrupt.header_length = header_length;
400 memcpy(interrupt->interrupt.header, header, header_length);
398 queue_event(client, &interrupt->event, 401 queue_event(client, &interrupt->event,
399 &interrupt->interrupt, sizeof interrupt->interrupt, NULL, 0); 402 &interrupt->interrupt,
403 sizeof interrupt->interrupt + header_length, NULL, 0);
400} 404}
401 405
402static int ioctl_create_iso_context(struct client *client, void __user *arg) 406static int ioctl_create_iso_context(struct client *client, void __user *arg)
@@ -423,6 +427,7 @@ static int ioctl_queue_iso(struct client *client, void __user *arg)
423{ 427{
424 struct fw_cdev_queue_iso request; 428 struct fw_cdev_queue_iso request;
425 struct fw_cdev_iso_packet __user *p, *end, *next; 429 struct fw_cdev_iso_packet __user *p, *end, *next;
430 struct fw_iso_context *ctx = client->iso_context;
426 unsigned long payload, payload_end, header_length; 431 unsigned long payload, payload_end, header_length;
427 int count; 432 int count;
428 struct { 433 struct {
@@ -430,7 +435,7 @@ static int ioctl_queue_iso(struct client *client, void __user *arg)
430 u8 header[256]; 435 u8 header[256];
431 } u; 436 } u;
432 437
433 if (client->iso_context == NULL) 438 if (ctx == NULL)
434 return -EINVAL; 439 return -EINVAL;
435 if (copy_from_user(&request, arg, sizeof request)) 440 if (copy_from_user(&request, arg, sizeof request))
436 return -EFAULT; 441 return -EFAULT;
@@ -461,13 +466,17 @@ static int ioctl_queue_iso(struct client *client, void __user *arg)
461 if (__copy_from_user(&u.packet, p, sizeof *p)) 466 if (__copy_from_user(&u.packet, p, sizeof *p))
462 return -EFAULT; 467 return -EFAULT;
463 468
464 if (client->iso_context->type == FW_ISO_CONTEXT_TRANSMIT) { 469 if (ctx->type == FW_ISO_CONTEXT_TRANSMIT) {
465 header_length = u.packet.header_length; 470 header_length = u.packet.header_length;
466 } else { 471 } else {
467 /* We require that header_length is a multiple of 472 /* We require that header_length is a multiple of
468 * the fixed header size, ctx->header_size */ 473 * the fixed header size, ctx->header_size */
469 if (u.packet.header_length % client->iso_context->header_size != 0) 474 if (ctx->header_size == 0) {
475 if (u.packet.header_length > 0)
476 return -EINVAL;
477 } else if (u.packet.header_length % ctx->header_size != 0) {
470 return -EINVAL; 478 return -EINVAL;
479 }
471 header_length = 0; 480 header_length = 0;
472 } 481 }
473 482
@@ -484,8 +493,8 @@ static int ioctl_queue_iso(struct client *client, void __user *arg)
484 if (payload + u.packet.payload_length > payload_end) 493 if (payload + u.packet.payload_length > payload_end)
485 return -EINVAL; 494 return -EINVAL;
486 495
487 if (fw_iso_context_queue(client->iso_context, 496 if (fw_iso_context_queue(ctx, &u.packet,
488 &u.packet, &client->buffer, payload)) 497 &client->buffer, payload))
489 break; 498 break;
490 499
491 p = next; 500 p = next;
diff --git a/drivers/firewire/fw-device-cdev.h b/drivers/firewire/fw-device-cdev.h
index 257dc872f46d..e32b39dc7e74 100644
--- a/drivers/firewire/fw-device-cdev.h
+++ b/drivers/firewire/fw-device-cdev.h
@@ -89,6 +89,8 @@ struct fw_cdev_event_iso_interrupt {
89 __u32 type; 89 __u32 type;
90 __u32 cycle; 90 __u32 cycle;
91 __u64 closure; 91 __u64 closure;
92 __u32 header_length; /* Length in bytes of following headers. */
93 __u32 header[0];
92}; 94};
93 95
94#define FW_CDEV_IOC_GET_CONFIG_ROM _IOR('#', 0x00, struct fw_cdev_get_config_rom) 96#define FW_CDEV_IOC_GET_CONFIG_ROM _IOR('#', 0x00, struct fw_cdev_get_config_rom)
diff --git a/drivers/firewire/fw-ohci.c b/drivers/firewire/fw-ohci.c
index d601ec7ff4d5..b5a154583e0d 100644
--- a/drivers/firewire/fw-ohci.c
+++ b/drivers/firewire/fw-ohci.c
@@ -143,6 +143,8 @@ struct at_context {
143struct iso_context { 143struct iso_context {
144 struct fw_iso_context base; 144 struct fw_iso_context base;
145 struct context context; 145 struct context context;
146 void *header;
147 size_t header_length;
146}; 148};
147 149
148#define CONFIG_ROM_SIZE 1024 150#define CONFIG_ROM_SIZE 1024
@@ -501,7 +503,7 @@ context_init(struct context *ctx, struct fw_ohci *ohci,
501 return 0; 503 return 0;
502} 504}
503 505
504 static void 506static void
505context_release(struct context *ctx) 507context_release(struct context *ctx)
506{ 508{
507 struct fw_card *card = &ctx->ohci->card; 509 struct fw_card *card = &ctx->ohci->card;
@@ -1273,16 +1275,23 @@ static int handle_ir_packet(struct context *context,
1273 struct iso_context *ctx = 1275 struct iso_context *ctx =
1274 container_of(context, struct iso_context, context); 1276 container_of(context, struct iso_context, context);
1275 struct db_descriptor *db = (struct db_descriptor *) d; 1277 struct db_descriptor *db = (struct db_descriptor *) d;
1278 size_t header_length;
1276 1279
1277 if (db->first_res_count > 0 && db->second_res_count > 0) 1280 if (db->first_res_count > 0 && db->second_res_count > 0)
1278 /* This descriptor isn't done yet, stop iteration. */ 1281 /* This descriptor isn't done yet, stop iteration. */
1279 return 0; 1282 return 0;
1280 1283
1281 if (le16_to_cpu(db->control) & descriptor_irq_always) 1284 header_length = db->first_req_count - db->first_res_count;
1282 /* FIXME: we should pass payload address here. */ 1285 if (ctx->header_length + header_length <= PAGE_SIZE)
1283 ctx->base.callback(&ctx->base, 1286 memcpy(ctx->header + ctx->header_length, db + 1, header_length);
1284 0, 0, 1287 ctx->header_length += header_length;
1288
1289 if (le16_to_cpu(db->control) & descriptor_irq_always) {
1290 ctx->base.callback(&ctx->base, 0,
1291 ctx->header_length, ctx->header,
1285 ctx->base.callback_data); 1292 ctx->base.callback_data);
1293 ctx->header_length = 0;
1294 }
1286 1295
1287 return 1; 1296 return 1;
1288} 1297}
@@ -1301,9 +1310,8 @@ static int handle_it_packet(struct context *context,
1301 return 0; 1310 return 0;
1302 1311
1303 if (le16_to_cpu(last->control) & descriptor_irq_always) 1312 if (le16_to_cpu(last->control) & descriptor_irq_always)
1304 ctx->base.callback(&ctx->base, 1313 ctx->base.callback(&ctx->base, le16_to_cpu(last->res_count),
1305 0, le16_to_cpu(last->res_count), 1314 0, NULL, ctx->base.callback_data);
1306 ctx->base.callback_data);
1307 1315
1308 return 1; 1316 return 1;
1309} 1317}
@@ -1316,7 +1324,7 @@ ohci_allocate_iso_context(struct fw_card *card, int type)
1316 descriptor_callback_t callback; 1324 descriptor_callback_t callback;
1317 u32 *mask, regs; 1325 u32 *mask, regs;
1318 unsigned long flags; 1326 unsigned long flags;
1319 int index, retval; 1327 int index, retval = -ENOMEM;
1320 1328
1321 if (type == FW_ISO_CONTEXT_TRANSMIT) { 1329 if (type == FW_ISO_CONTEXT_TRANSMIT) {
1322 mask = &ohci->it_context_mask; 1330 mask = &ohci->it_context_mask;
@@ -1344,16 +1352,26 @@ ohci_allocate_iso_context(struct fw_card *card, int type)
1344 1352
1345 ctx = &list[index]; 1353 ctx = &list[index];
1346 memset(ctx, 0, sizeof *ctx); 1354 memset(ctx, 0, sizeof *ctx);
1355 ctx->header_length = 0;
1356 ctx->header = (void *) __get_free_page(GFP_KERNEL);
1357 if (ctx->header == NULL)
1358 goto out;
1359
1347 retval = context_init(&ctx->context, ohci, ISO_BUFFER_SIZE, 1360 retval = context_init(&ctx->context, ohci, ISO_BUFFER_SIZE,
1348 regs, callback); 1361 regs, callback);
1349 if (retval < 0) { 1362 if (retval < 0)
1350 spin_lock_irqsave(&ohci->lock, flags); 1363 goto out_with_header;
1351 *mask |= 1 << index;
1352 spin_unlock_irqrestore(&ohci->lock, flags);
1353 return ERR_PTR(retval);
1354 }
1355 1364
1356 return &ctx->base; 1365 return &ctx->base;
1366
1367 out_with_header:
1368 free_page((unsigned long)ctx->header);
1369 out:
1370 spin_lock_irqsave(&ohci->lock, flags);
1371 *mask |= 1 << index;
1372 spin_unlock_irqrestore(&ohci->lock, flags);
1373
1374 return ERR_PTR(retval);
1357} 1375}
1358 1376
1359static int ohci_start_iso(struct fw_iso_context *base, s32 cycle) 1377static int ohci_start_iso(struct fw_iso_context *base, s32 cycle)
@@ -1413,6 +1431,7 @@ static void ohci_free_iso_context(struct fw_iso_context *base)
1413 1431
1414 ohci_stop_iso(base); 1432 ohci_stop_iso(base);
1415 context_release(&ctx->context); 1433 context_release(&ctx->context);
1434 free_page((unsigned long)ctx->header);
1416 1435
1417 spin_lock_irqsave(&ohci->lock, flags); 1436 spin_lock_irqsave(&ohci->lock, flags);
1418 1437
diff --git a/drivers/firewire/fw-transaction.h b/drivers/firewire/fw-transaction.h
index b2a0a030c0fd..7942e914b8f1 100644
--- a/drivers/firewire/fw-transaction.h
+++ b/drivers/firewire/fw-transaction.h
@@ -335,7 +335,10 @@ struct fw_iso_packet {
335struct fw_iso_context; 335struct fw_iso_context;
336 336
337typedef void (*fw_iso_callback_t) (struct fw_iso_context *context, 337typedef void (*fw_iso_callback_t) (struct fw_iso_context *context,
338 int status, u32 cycle, void *data); 338 u32 cycle,
339 size_t header_length,
340 void *header,
341 void *data);
339 342
340/* An iso buffer is just a set of pages mapped for DMA in the 343/* An iso buffer is just a set of pages mapped for DMA in the
341 * specified direction. Since the pages are to be used for DMA, they 344 * specified direction. Since the pages are to be used for DMA, they