diff options
| -rw-r--r-- | drivers/firewire/fw-cdev.c | 33 | ||||
| -rw-r--r-- | drivers/firewire/fw-ohci.c | 21 | ||||
| -rw-r--r-- | drivers/firewire/fw-transaction.c | 25 | ||||
| -rw-r--r-- | drivers/firewire/fw-transaction.h | 4 | ||||
| -rw-r--r-- | include/linux/firewire-cdev.h | 27 |
5 files changed, 108 insertions, 2 deletions
diff --git a/drivers/firewire/fw-cdev.c b/drivers/firewire/fw-cdev.c index 214e534efee5..539dae5eb5b2 100644 --- a/drivers/firewire/fw-cdev.c +++ b/drivers/firewire/fw-cdev.c | |||
| @@ -1242,6 +1242,38 @@ static int ioctl_send_broadcast_request(struct client *client, void *buffer) | |||
| 1242 | return init_request(client, request, LOCAL_BUS | 0x3f, SCODE_100); | 1242 | return init_request(client, request, LOCAL_BUS | 0x3f, SCODE_100); |
| 1243 | } | 1243 | } |
| 1244 | 1244 | ||
| 1245 | struct stream_packet { | ||
| 1246 | struct fw_packet packet; | ||
| 1247 | u8 data[0]; | ||
| 1248 | }; | ||
| 1249 | |||
| 1250 | static void send_stream_packet_done(struct fw_packet *packet, | ||
| 1251 | struct fw_card *card, int status) | ||
| 1252 | { | ||
| 1253 | kfree(container_of(packet, struct stream_packet, packet)); | ||
| 1254 | } | ||
| 1255 | |||
| 1256 | static int ioctl_send_stream_packet(struct client *client, void *buffer) | ||
| 1257 | { | ||
| 1258 | struct fw_cdev_send_stream_packet *request = buffer; | ||
| 1259 | struct stream_packet *p; | ||
| 1260 | |||
| 1261 | p = kmalloc(sizeof(*p) + request->size, GFP_KERNEL); | ||
| 1262 | if (p == NULL) | ||
| 1263 | return -ENOMEM; | ||
| 1264 | |||
| 1265 | if (request->data && | ||
| 1266 | copy_from_user(p->data, u64_to_uptr(request->data), request->size)) { | ||
| 1267 | kfree(p); | ||
| 1268 | return -EFAULT; | ||
| 1269 | } | ||
| 1270 | fw_send_stream_packet(client->device->card, &p->packet, | ||
| 1271 | request->generation, request->speed, | ||
| 1272 | request->channel, request->sy, request->tag, | ||
| 1273 | p->data, request->size, send_stream_packet_done); | ||
| 1274 | return 0; | ||
| 1275 | } | ||
| 1276 | |||
| 1245 | static int (* const ioctl_handlers[])(struct client *client, void *buffer) = { | 1277 | static int (* const ioctl_handlers[])(struct client *client, void *buffer) = { |
| 1246 | ioctl_get_info, | 1278 | ioctl_get_info, |
| 1247 | ioctl_send_request, | 1279 | ioctl_send_request, |
| @@ -1262,6 +1294,7 @@ static int (* const ioctl_handlers[])(struct client *client, void *buffer) = { | |||
| 1262 | ioctl_deallocate_iso_resource_once, | 1294 | ioctl_deallocate_iso_resource_once, |
| 1263 | ioctl_get_speed, | 1295 | ioctl_get_speed, |
| 1264 | ioctl_send_broadcast_request, | 1296 | ioctl_send_broadcast_request, |
| 1297 | ioctl_send_stream_packet, | ||
| 1265 | }; | 1298 | }; |
| 1266 | 1299 | ||
| 1267 | static int dispatch_ioctl(struct client *client, | 1300 | static int dispatch_ioctl(struct client *client, |
diff --git a/drivers/firewire/fw-ohci.c b/drivers/firewire/fw-ohci.c index c92278374658..1180d0be0bb4 100644 --- a/drivers/firewire/fw-ohci.c +++ b/drivers/firewire/fw-ohci.c | |||
| @@ -936,7 +936,9 @@ static int at_context_queue_packet(struct context *ctx, | |||
| 936 | */ | 936 | */ |
| 937 | 937 | ||
| 938 | header = (__le32 *) &d[1]; | 938 | header = (__le32 *) &d[1]; |
| 939 | if (packet->header_length > 8) { | 939 | switch (packet->header_length) { |
| 940 | case 16: | ||
| 941 | case 12: | ||
| 940 | header[0] = cpu_to_le32((packet->header[0] & 0xffff) | | 942 | header[0] = cpu_to_le32((packet->header[0] & 0xffff) | |
| 941 | (packet->speed << 16)); | 943 | (packet->speed << 16)); |
| 942 | header[1] = cpu_to_le32((packet->header[1] & 0xffff) | | 944 | header[1] = cpu_to_le32((packet->header[1] & 0xffff) | |
| @@ -950,12 +952,27 @@ static int at_context_queue_packet(struct context *ctx, | |||
| 950 | header[3] = (__force __le32) packet->header[3]; | 952 | header[3] = (__force __le32) packet->header[3]; |
| 951 | 953 | ||
| 952 | d[0].req_count = cpu_to_le16(packet->header_length); | 954 | d[0].req_count = cpu_to_le16(packet->header_length); |
| 953 | } else { | 955 | break; |
| 956 | |||
| 957 | case 8: | ||
| 954 | header[0] = cpu_to_le32((OHCI1394_phy_tcode << 4) | | 958 | header[0] = cpu_to_le32((OHCI1394_phy_tcode << 4) | |
| 955 | (packet->speed << 16)); | 959 | (packet->speed << 16)); |
| 956 | header[1] = cpu_to_le32(packet->header[0]); | 960 | header[1] = cpu_to_le32(packet->header[0]); |
| 957 | header[2] = cpu_to_le32(packet->header[1]); | 961 | header[2] = cpu_to_le32(packet->header[1]); |
| 958 | d[0].req_count = cpu_to_le16(12); | 962 | d[0].req_count = cpu_to_le16(12); |
| 963 | break; | ||
| 964 | |||
| 965 | case 4: | ||
| 966 | header[0] = cpu_to_le32((packet->header[0] & 0xffff) | | ||
| 967 | (packet->speed << 16)); | ||
| 968 | header[1] = cpu_to_le32(packet->header[0] & 0xffff0000); | ||
| 969 | d[0].req_count = cpu_to_le16(8); | ||
| 970 | break; | ||
| 971 | |||
| 972 | default: | ||
| 973 | /* BUG(); */ | ||
| 974 | packet->ack = RCODE_SEND_ERROR; | ||
| 975 | return -1; | ||
| 959 | } | 976 | } |
| 960 | 977 | ||
| 961 | driver_data = (struct driver_data *) &d[3]; | 978 | driver_data = (struct driver_data *) &d[3]; |
diff --git a/drivers/firewire/fw-transaction.c b/drivers/firewire/fw-transaction.c index 76938fe432a0..e3da58991960 100644 --- a/drivers/firewire/fw-transaction.c +++ b/drivers/firewire/fw-transaction.c | |||
| @@ -37,6 +37,10 @@ | |||
| 37 | #include "fw-topology.h" | 37 | #include "fw-topology.h" |
| 38 | #include "fw-device.h" | 38 | #include "fw-device.h" |
| 39 | 39 | ||
| 40 | #define HEADER_TAG(tag) ((tag) << 14) | ||
| 41 | #define HEADER_CHANNEL(ch) ((ch) << 8) | ||
| 42 | #define HEADER_SY(sy) ((sy) << 0) | ||
| 43 | |||
| 40 | #define HEADER_PRI(pri) ((pri) << 0) | 44 | #define HEADER_PRI(pri) ((pri) << 0) |
| 41 | #define HEADER_TCODE(tcode) ((tcode) << 4) | 45 | #define HEADER_TCODE(tcode) ((tcode) << 4) |
| 42 | #define HEADER_RETRY(retry) ((retry) << 8) | 46 | #define HEADER_RETRY(retry) ((retry) << 8) |
| @@ -293,6 +297,27 @@ void fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode, | |||
| 293 | } | 297 | } |
| 294 | EXPORT_SYMBOL(fw_send_request); | 298 | EXPORT_SYMBOL(fw_send_request); |
| 295 | 299 | ||
| 300 | void fw_send_stream_packet(struct fw_card *card, struct fw_packet *p, | ||
| 301 | int generation, int speed, int channel, int sy, int tag, | ||
| 302 | void *payload, size_t length, fw_packet_callback_t callback) | ||
| 303 | { | ||
| 304 | p->callback = callback; | ||
| 305 | p->header[0] = | ||
| 306 | HEADER_DATA_LENGTH(length) | ||
| 307 | | HEADER_TAG(tag) | ||
| 308 | | HEADER_CHANNEL(channel) | ||
| 309 | | HEADER_TCODE(TCODE_STREAM_DATA) | ||
| 310 | | HEADER_SY(sy); | ||
| 311 | p->header_length = 4; | ||
| 312 | p->payload = payload; | ||
| 313 | p->payload_length = length; | ||
| 314 | p->speed = speed; | ||
| 315 | p->generation = generation; | ||
| 316 | p->ack = 0; | ||
| 317 | |||
| 318 | card->driver->send_request(card, p); | ||
| 319 | } | ||
| 320 | |||
| 296 | struct transaction_callback_data { | 321 | struct transaction_callback_data { |
| 297 | struct completion done; | 322 | struct completion done; |
| 298 | void *payload; | 323 | void *payload; |
diff --git a/drivers/firewire/fw-transaction.h b/drivers/firewire/fw-transaction.h index 35d0a4bb6d5c..eed2e295eb3c 100644 --- a/drivers/firewire/fw-transaction.h +++ b/drivers/firewire/fw-transaction.h | |||
| @@ -407,6 +407,10 @@ void fw_send_request(struct fw_card *card, struct fw_transaction *t, | |||
| 407 | int tcode, int destination_id, int generation, int speed, | 407 | int tcode, int destination_id, int generation, int speed, |
| 408 | unsigned long long offset, void *payload, size_t length, | 408 | unsigned long long offset, void *payload, size_t length, |
| 409 | fw_transaction_callback_t callback, void *callback_data); | 409 | fw_transaction_callback_t callback, void *callback_data); |
| 410 | void fw_send_stream_packet(struct fw_card *card, struct fw_packet *p, | ||
| 411 | int generation, int speed, int channel, int sy, int tag, | ||
| 412 | void *payload, size_t length, fw_packet_callback_t callback); | ||
| 413 | |||
| 410 | int fw_cancel_transaction(struct fw_card *card, | 414 | int fw_cancel_transaction(struct fw_card *card, |
| 411 | struct fw_transaction *transaction); | 415 | struct fw_transaction *transaction); |
| 412 | void fw_flush_transactions(struct fw_card *card); | 416 | void fw_flush_transactions(struct fw_card *card); |
diff --git a/include/linux/firewire-cdev.h b/include/linux/firewire-cdev.h index 2e35379bf96c..4dfc84d0ac76 100644 --- a/include/linux/firewire-cdev.h +++ b/include/linux/firewire-cdev.h | |||
| @@ -246,6 +246,7 @@ union fw_cdev_event { | |||
| 246 | #define FW_CDEV_IOC_DEALLOCATE_ISO_RESOURCE_ONCE _IOW('#', 0x10, struct fw_cdev_allocate_iso_resource) | 246 | #define FW_CDEV_IOC_DEALLOCATE_ISO_RESOURCE_ONCE _IOW('#', 0x10, struct fw_cdev_allocate_iso_resource) |
| 247 | #define FW_CDEV_IOC_GET_SPEED _IOR('#', 0x11, struct fw_cdev_get_speed) | 247 | #define FW_CDEV_IOC_GET_SPEED _IOR('#', 0x11, struct fw_cdev_get_speed) |
| 248 | #define FW_CDEV_IOC_SEND_BROADCAST_REQUEST _IOW('#', 0x12, struct fw_cdev_send_request) | 248 | #define FW_CDEV_IOC_SEND_BROADCAST_REQUEST _IOW('#', 0x12, struct fw_cdev_send_request) |
| 249 | #define FW_CDEV_IOC_SEND_STREAM_PACKET _IOW('#', 0x13, struct fw_cdev_send_stream_packet) | ||
| 249 | 250 | ||
| 250 | /* | 251 | /* |
| 251 | * FW_CDEV_VERSION History | 252 | * FW_CDEV_VERSION History |
| @@ -609,4 +610,30 @@ struct fw_cdev_get_speed { | |||
| 609 | __u32 max_speed; | 610 | __u32 max_speed; |
| 610 | }; | 611 | }; |
| 611 | 612 | ||
| 613 | /** | ||
| 614 | * struct fw_cdev_send_stream_packet - send an asynchronous stream packet | ||
| 615 | * @generation: Bus generation where the packet is valid | ||
| 616 | * @speed: Speed code to send the packet at | ||
| 617 | * @channel: Channel to send the packet on | ||
| 618 | * @sy: Four-bit sy code for the packet | ||
| 619 | * @tag: Two-bit tag field to use for the packet | ||
| 620 | * @size: Size of the packet's data payload | ||
| 621 | * @data: Userspace pointer to the payload | ||
| 622 | * | ||
| 623 | * The %FW_CDEV_IOC_SEND_STREAM_PACKET ioctl sends an asynchronous stream packet | ||
| 624 | * to every device (that is listening to the specified channel) on the | ||
| 625 | * firewire bus. It is the applications's job to ensure | ||
| 626 | * that the intended device(s) will be able to receive the packet at the chosen | ||
| 627 | * transmit speed. | ||
| 628 | */ | ||
| 629 | struct fw_cdev_send_stream_packet { | ||
| 630 | __u32 generation; | ||
| 631 | __u32 speed; | ||
| 632 | __u32 channel; | ||
| 633 | __u32 sy; | ||
| 634 | __u32 tag; | ||
| 635 | __u32 size; | ||
| 636 | __u64 data; | ||
| 637 | }; | ||
| 638 | |||
| 612 | #endif /* _LINUX_FIREWIRE_CDEV_H */ | 639 | #endif /* _LINUX_FIREWIRE_CDEV_H */ |
