aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firewire
diff options
context:
space:
mode:
authorJay Fenlason <fenlason@redhat.com>2009-03-05 13:08:40 -0500
committerStefan Richter <stefanr@s5r6.in-berlin.de>2009-03-24 15:56:49 -0400
commitf8c2287c65f8f72000102fc058232669e4540bc4 (patch)
treea82393fbdd3a2b20f8e499537b10eb9e61dae941 /drivers/firewire
parentba27e1f7bf220799cd3d7503f82bda71b8ebe8c5 (diff)
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)
Diffstat (limited to 'drivers/firewire')
-rw-r--r--drivers/firewire/fw-cdev.c33
-rw-r--r--drivers/firewire/fw-ohci.c21
-rw-r--r--drivers/firewire/fw-transaction.c25
-rw-r--r--drivers/firewire/fw-transaction.h4
4 files changed, 81 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
1245struct stream_packet {
1246 struct fw_packet packet;
1247 u8 data[0];
1248};
1249
1250static 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
1256static 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
1245static int (* const ioctl_handlers[])(struct client *client, void *buffer) = { 1277static 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
1267static int dispatch_ioctl(struct client *client, 1300static 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}
294EXPORT_SYMBOL(fw_send_request); 298EXPORT_SYMBOL(fw_send_request);
295 299
300void 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
296struct transaction_callback_data { 321struct 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);
410void 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
410int fw_cancel_transaction(struct fw_card *card, 414int fw_cancel_transaction(struct fw_card *card,
411 struct fw_transaction *transaction); 415 struct fw_transaction *transaction);
412void fw_flush_transactions(struct fw_card *card); 416void fw_flush_transactions(struct fw_card *card);