diff options
Diffstat (limited to 'drivers/firewire/fw-ohci.c')
-rw-r--r-- | drivers/firewire/fw-ohci.c | 107 |
1 files changed, 92 insertions, 15 deletions
diff --git a/drivers/firewire/fw-ohci.c b/drivers/firewire/fw-ohci.c index 76ac70a38545..9b9ea0f3c416 100644 --- a/drivers/firewire/fw-ohci.c +++ b/drivers/firewire/fw-ohci.c | |||
@@ -1267,16 +1267,34 @@ ohci_enable_phys_dma(struct fw_card *card, int node_id, int generation) | |||
1267 | spin_unlock_irqrestore(&ohci->lock, flags); | 1267 | spin_unlock_irqrestore(&ohci->lock, flags); |
1268 | return retval; | 1268 | return retval; |
1269 | } | 1269 | } |
1270 | |||
1271 | static int handle_ir_bufferfill_packet(struct context *context, | ||
1272 | struct descriptor *d, | ||
1273 | struct descriptor *last) | ||
1274 | { | ||
1275 | struct iso_context *ctx = | ||
1276 | container_of(context, struct iso_context, context); | ||
1270 | 1277 | ||
1271 | static int handle_ir_packet(struct context *context, | 1278 | if (d->res_count > 0) |
1272 | struct descriptor *d, | 1279 | return 0; |
1273 | struct descriptor *last) | 1280 | |
1281 | if (le16_to_cpu(last->control) & descriptor_irq_always) | ||
1282 | ctx->base.callback(&ctx->base, | ||
1283 | le16_to_cpu(last->res_count), | ||
1284 | 0, NULL, ctx->base.callback_data); | ||
1285 | |||
1286 | return 1; | ||
1287 | } | ||
1288 | |||
1289 | static int handle_ir_dualbuffer_packet(struct context *context, | ||
1290 | struct descriptor *d, | ||
1291 | struct descriptor *last) | ||
1274 | { | 1292 | { |
1275 | struct iso_context *ctx = | 1293 | struct iso_context *ctx = |
1276 | container_of(context, struct iso_context, context); | 1294 | container_of(context, struct iso_context, context); |
1277 | struct db_descriptor *db = (struct db_descriptor *) d; | 1295 | struct db_descriptor *db = (struct db_descriptor *) d; |
1278 | size_t header_length; | 1296 | size_t header_length; |
1279 | 1297 | ||
1280 | if (db->first_res_count > 0 && db->second_res_count > 0) | 1298 | if (db->first_res_count > 0 && db->second_res_count > 0) |
1281 | /* This descriptor isn't done yet, stop iteration. */ | 1299 | /* This descriptor isn't done yet, stop iteration. */ |
1282 | return 0; | 1300 | return 0; |
@@ -1317,7 +1335,7 @@ static int handle_it_packet(struct context *context, | |||
1317 | } | 1335 | } |
1318 | 1336 | ||
1319 | static struct fw_iso_context * | 1337 | static struct fw_iso_context * |
1320 | ohci_allocate_iso_context(struct fw_card *card, int type) | 1338 | ohci_allocate_iso_context(struct fw_card *card, int type, size_t header_size) |
1321 | { | 1339 | { |
1322 | struct fw_ohci *ohci = fw_ohci(card); | 1340 | struct fw_ohci *ohci = fw_ohci(card); |
1323 | struct iso_context *ctx, *list; | 1341 | struct iso_context *ctx, *list; |
@@ -1333,7 +1351,10 @@ ohci_allocate_iso_context(struct fw_card *card, int type) | |||
1333 | } else { | 1351 | } else { |
1334 | mask = &ohci->ir_context_mask; | 1352 | mask = &ohci->ir_context_mask; |
1335 | list = ohci->ir_context_list; | 1353 | list = ohci->ir_context_list; |
1336 | callback = handle_ir_packet; | 1354 | if (header_size > 0) |
1355 | callback = handle_ir_dualbuffer_packet; | ||
1356 | else | ||
1357 | callback = handle_ir_bufferfill_packet; | ||
1337 | } | 1358 | } |
1338 | 1359 | ||
1339 | spin_lock_irqsave(&ohci->lock, flags); | 1360 | spin_lock_irqsave(&ohci->lock, flags); |
@@ -1378,7 +1399,7 @@ static int ohci_start_iso(struct fw_iso_context *base, s32 cycle) | |||
1378 | { | 1399 | { |
1379 | struct iso_context *ctx = container_of(base, struct iso_context, base); | 1400 | struct iso_context *ctx = container_of(base, struct iso_context, base); |
1380 | struct fw_ohci *ohci = ctx->context.ohci; | 1401 | struct fw_ohci *ohci = ctx->context.ohci; |
1381 | u32 cycle_match = 0; | 1402 | u32 cycle_match = 0, mode; |
1382 | int index; | 1403 | int index; |
1383 | 1404 | ||
1384 | if (ctx->base.type == FW_ISO_CONTEXT_TRANSMIT) { | 1405 | if (ctx->base.type == FW_ISO_CONTEXT_TRANSMIT) { |
@@ -1393,11 +1414,15 @@ static int ohci_start_iso(struct fw_iso_context *base, s32 cycle) | |||
1393 | } else { | 1414 | } else { |
1394 | index = ctx - ohci->ir_context_list; | 1415 | index = ctx - ohci->ir_context_list; |
1395 | 1416 | ||
1417 | if (ctx->base.header_size > 0) | ||
1418 | mode = IR_CONTEXT_DUAL_BUFFER_MODE; | ||
1419 | else | ||
1420 | mode = IR_CONTEXT_BUFFER_FILL; | ||
1396 | reg_write(ohci, OHCI1394_IsoRecvIntEventClear, 1 << index); | 1421 | reg_write(ohci, OHCI1394_IsoRecvIntEventClear, 1 << index); |
1397 | reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 1 << index); | 1422 | reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 1 << index); |
1398 | reg_write(ohci, context_match(ctx->context.regs), | 1423 | reg_write(ohci, context_match(ctx->context.regs), |
1399 | 0xf0000000 | ctx->base.channel); | 1424 | 0xf0000000 | ctx->base.channel); |
1400 | context_run(&ctx->context, IR_CONTEXT_DUAL_BUFFER_MODE); | 1425 | context_run(&ctx->context, mode); |
1401 | } | 1426 | } |
1402 | 1427 | ||
1403 | return 0; | 1428 | return 0; |
@@ -1544,10 +1569,10 @@ ohci_queue_iso_transmit(struct fw_iso_context *base, | |||
1544 | } | 1569 | } |
1545 | 1570 | ||
1546 | static int | 1571 | static int |
1547 | ohci_queue_iso_receive(struct fw_iso_context *base, | 1572 | ohci_queue_iso_receive_dualbuffer(struct fw_iso_context *base, |
1548 | struct fw_iso_packet *packet, | 1573 | struct fw_iso_packet *packet, |
1549 | struct fw_iso_buffer *buffer, | 1574 | struct fw_iso_buffer *buffer, |
1550 | unsigned long payload) | 1575 | unsigned long payload) |
1551 | { | 1576 | { |
1552 | struct iso_context *ctx = container_of(base, struct iso_context, base); | 1577 | struct iso_context *ctx = container_of(base, struct iso_context, base); |
1553 | struct db_descriptor *db = NULL; | 1578 | struct db_descriptor *db = NULL; |
@@ -1604,10 +1629,58 @@ ohci_queue_iso_receive(struct fw_iso_context *base, | |||
1604 | 1629 | ||
1605 | if (p->interrupt) | 1630 | if (p->interrupt) |
1606 | db->control |= cpu_to_le16(descriptor_irq_always); | 1631 | db->control |= cpu_to_le16(descriptor_irq_always); |
1632 | |||
1633 | return 0; | ||
1634 | } | ||
1607 | 1635 | ||
1608 | return 0; | 1636 | static int |
1609 | } | 1637 | ohci_queue_iso_receive_bufferfill(struct fw_iso_context *base, |
1638 | struct fw_iso_packet *packet, | ||
1639 | struct fw_iso_buffer *buffer, | ||
1640 | unsigned long payload) | ||
1641 | { | ||
1642 | struct iso_context *ctx = container_of(base, struct iso_context, base); | ||
1643 | struct descriptor *d = NULL; | ||
1644 | dma_addr_t d_bus, page_bus; | ||
1645 | u32 length, rest; | ||
1646 | int page, offset; | ||
1610 | 1647 | ||
1648 | page = payload >> PAGE_SHIFT; | ||
1649 | offset = payload & ~PAGE_MASK; | ||
1650 | rest = packet->payload_length; | ||
1651 | |||
1652 | while (rest > 0) { | ||
1653 | d = context_get_descriptors(&ctx->context, 1, &d_bus); | ||
1654 | if (d == NULL) | ||
1655 | return -ENOMEM; | ||
1656 | |||
1657 | d->control = cpu_to_le16(descriptor_input_more | | ||
1658 | descriptor_status | | ||
1659 | descriptor_branch_always); | ||
1660 | |||
1661 | if (offset + rest < PAGE_SIZE) | ||
1662 | length = rest; | ||
1663 | else | ||
1664 | length = PAGE_SIZE - offset; | ||
1665 | |||
1666 | page_bus = page_private(buffer->pages[page]); | ||
1667 | d->data_address = cpu_to_le32(page_bus + offset); | ||
1668 | d->req_count = cpu_to_le16(length); | ||
1669 | d->res_count = cpu_to_le16(length); | ||
1670 | |||
1671 | context_append(&ctx->context, d, 1, 0); | ||
1672 | |||
1673 | offset = (offset + length) & ~PAGE_MASK; | ||
1674 | rest -= length; | ||
1675 | page++; | ||
1676 | } | ||
1677 | |||
1678 | if (packet->interrupt) | ||
1679 | d->control |= cpu_to_le16(descriptor_irq_always); | ||
1680 | |||
1681 | return 0; | ||
1682 | } | ||
1683 | |||
1611 | static int | 1684 | static int |
1612 | ohci_queue_iso(struct fw_iso_context *base, | 1685 | ohci_queue_iso(struct fw_iso_context *base, |
1613 | struct fw_iso_packet *packet, | 1686 | struct fw_iso_packet *packet, |
@@ -1616,8 +1689,12 @@ ohci_queue_iso(struct fw_iso_context *base, | |||
1616 | { | 1689 | { |
1617 | if (base->type == FW_ISO_CONTEXT_TRANSMIT) | 1690 | if (base->type == FW_ISO_CONTEXT_TRANSMIT) |
1618 | return ohci_queue_iso_transmit(base, packet, buffer, payload); | 1691 | return ohci_queue_iso_transmit(base, packet, buffer, payload); |
1692 | else if (base->header_size == 0) | ||
1693 | return ohci_queue_iso_receive_bufferfill(base, packet, | ||
1694 | buffer, payload); | ||
1619 | else | 1695 | else |
1620 | return ohci_queue_iso_receive(base, packet, buffer, payload); | 1696 | return ohci_queue_iso_receive_dualbuffer(base, packet, |
1697 | buffer, payload); | ||
1621 | } | 1698 | } |
1622 | 1699 | ||
1623 | static const struct fw_card_driver ohci_driver = { | 1700 | static const struct fw_card_driver ohci_driver = { |