Commit f8c2287c65f8f72000102fc058232669e4540bc4

Authored by Jay Fenlason
Committed by Stefan Richter
1 parent ba27e1f7bf

firewire: implement asynchronous stream transmission

Allow userspace and other firewire drivers (fw-ipv4 I'm looking at
you!) to send Asynchronous Transmit Streams as described in 7.8.3 of
release 1.1 of the 1394 Open Host Controller Interface Specification.

Signed-off-by: Jay Fenlason <fenlason@redhat.com>
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de> (tweaks)

Showing 5 changed files with 108 additions and 2 deletions Side-by-side Diff

drivers/firewire/fw-cdev.c
... ... @@ -1242,6 +1242,38 @@
1242 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 1277 static int (* const ioctl_handlers[])(struct client *client, void *buffer) = {
1246 1278 ioctl_get_info,
1247 1279 ioctl_send_request,
... ... @@ -1262,6 +1294,7 @@
1262 1294 ioctl_deallocate_iso_resource_once,
1263 1295 ioctl_get_speed,
1264 1296 ioctl_send_broadcast_request,
  1297 + ioctl_send_stream_packet,
1265 1298 };
1266 1299  
1267 1300 static int dispatch_ioctl(struct client *client,
drivers/firewire/fw-ohci.c
... ... @@ -936,7 +936,9 @@
936 936 */
937 937  
938 938 header = (__le32 *) &d[1];
939   - if (packet->header_length > 8) {
  939 + switch (packet->header_length) {
  940 + case 16:
  941 + case 12:
940 942 header[0] = cpu_to_le32((packet->header[0] & 0xffff) |
941 943 (packet->speed << 16));
942 944 header[1] = cpu_to_le32((packet->header[1] & 0xffff) |
943 945  
... ... @@ -950,12 +952,27 @@
950 952 header[3] = (__force __le32) packet->header[3];
951 953  
952 954 d[0].req_count = cpu_to_le16(packet->header_length);
953   - } else {
  955 + break;
  956 +
  957 + case 8:
954 958 header[0] = cpu_to_le32((OHCI1394_phy_tcode << 4) |
955 959 (packet->speed << 16));
956 960 header[1] = cpu_to_le32(packet->header[0]);
957 961 header[2] = cpu_to_le32(packet->header[1]);
958 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 978 driver_data = (struct driver_data *) &d[3];
drivers/firewire/fw-transaction.c
... ... @@ -37,6 +37,10 @@
37 37 #include "fw-topology.h"
38 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 44 #define HEADER_PRI(pri) ((pri) << 0)
41 45 #define HEADER_TCODE(tcode) ((tcode) << 4)
42 46 #define HEADER_RETRY(retry) ((retry) << 8)
... ... @@ -292,6 +296,27 @@
292 296 card->driver->send_request(card, &t->packet);
293 297 }
294 298 EXPORT_SYMBOL(fw_send_request);
  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 +}
295 320  
296 321 struct transaction_callback_data {
297 322 struct completion done;
drivers/firewire/fw-transaction.h
... ... @@ -407,6 +407,10 @@
407 407 int tcode, int destination_id, int generation, int speed,
408 408 unsigned long long offset, void *payload, size_t length,
409 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 414 int fw_cancel_transaction(struct fw_card *card,
411 415 struct fw_transaction *transaction);
412 416 void fw_flush_transactions(struct fw_card *card);
include/linux/firewire-cdev.h
... ... @@ -246,6 +246,7 @@
246 246 #define FW_CDEV_IOC_DEALLOCATE_ISO_RESOURCE_ONCE _IOW('#', 0x10, struct fw_cdev_allocate_iso_resource)
247 247 #define FW_CDEV_IOC_GET_SPEED _IOR('#', 0x11, struct fw_cdev_get_speed)
248 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 252 * FW_CDEV_VERSION History
... ... @@ -607,6 +608,32 @@
607 608 */
608 609 struct fw_cdev_get_speed {
609 610 __u32 max_speed;
  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;
610 637 };
611 638  
612 639 #endif /* _LINUX_FIREWIRE_CDEV_H */