aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/firewire/fw-cdev.c46
-rw-r--r--drivers/firewire/fw-transaction.c42
-rw-r--r--drivers/firewire/fw-transaction.h9
-rw-r--r--include/linux/firewire-cdev.h31
4 files changed, 56 insertions, 72 deletions
diff --git a/drivers/firewire/fw-cdev.c b/drivers/firewire/fw-cdev.c
index 95a207545eb..7eb6594cc3e 100644
--- a/drivers/firewire/fw-cdev.c
+++ b/drivers/firewire/fw-cdev.c
@@ -522,7 +522,8 @@ static int init_request(struct client *client,
522 struct outbound_transaction_event *e; 522 struct outbound_transaction_event *e;
523 int ret; 523 int ret;
524 524
525 if (request->length > 4096 || request->length > 512 << speed) 525 if (request->tcode != TCODE_STREAM_DATA &&
526 (request->length > 4096 || request->length > 512 << speed))
526 return -EIO; 527 return -EIO;
527 528
528 e = kmalloc(sizeof(*e) + request->length, GFP_KERNEL); 529 e = kmalloc(sizeof(*e) + request->length, GFP_KERNEL);
@@ -1247,36 +1248,27 @@ static int ioctl_send_broadcast_request(struct client *client, void *buffer)
1247 return init_request(client, request, LOCAL_BUS | 0x3f, SCODE_100); 1248 return init_request(client, request, LOCAL_BUS | 0x3f, SCODE_100);
1248} 1249}
1249 1250
1250struct stream_packet {
1251 struct fw_packet packet;
1252 u8 data[0];
1253};
1254
1255static void send_stream_packet_done(struct fw_packet *packet,
1256 struct fw_card *card, int status)
1257{
1258 kfree(container_of(packet, struct stream_packet, packet));
1259}
1260
1261static int ioctl_send_stream_packet(struct client *client, void *buffer) 1251static int ioctl_send_stream_packet(struct client *client, void *buffer)
1262{ 1252{
1263 struct fw_cdev_send_stream_packet *request = buffer; 1253 struct fw_cdev_send_stream_packet *p = buffer;
1264 struct stream_packet *p; 1254 struct fw_cdev_send_request request;
1255 int dest;
1265 1256
1266 p = kmalloc(sizeof(*p) + request->size, GFP_KERNEL); 1257 if (p->speed > client->device->card->link_speed ||
1267 if (p == NULL) 1258 p->length > 1024 << p->speed)
1268 return -ENOMEM; 1259 return -EIO;
1269 1260
1270 if (request->data && 1261 if (p->tag > 3 || p->channel > 63 || p->sy > 15)
1271 copy_from_user(p->data, u64_to_uptr(request->data), request->size)) { 1262 return -EINVAL;
1272 kfree(p); 1263
1273 return -EFAULT; 1264 dest = fw_stream_packet_destination_id(p->tag, p->channel, p->sy);
1274 } 1265 request.tcode = TCODE_STREAM_DATA;
1275 fw_send_stream_packet(client->device->card, &p->packet, 1266 request.length = p->length;
1276 request->generation, request->speed, 1267 request.closure = p->closure;
1277 request->channel, request->sy, request->tag, 1268 request.data = p->data;
1278 p->data, request->size, send_stream_packet_done); 1269 request.generation = p->generation;
1279 return 0; 1270
1271 return init_request(client, &request, dest, p->speed);
1280} 1272}
1281 1273
1282static int (* const ioctl_handlers[])(struct client *client, void *buffer) = { 1274static int (* const ioctl_handlers[])(struct client *client, void *buffer) = {
diff --git a/drivers/firewire/fw-transaction.c b/drivers/firewire/fw-transaction.c
index e3da5899196..4a9b37461c2 100644
--- a/drivers/firewire/fw-transaction.c
+++ b/drivers/firewire/fw-transaction.c
@@ -37,10 +37,6 @@
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
44#define HEADER_PRI(pri) ((pri) << 0) 40#define HEADER_PRI(pri) ((pri) << 0)
45#define HEADER_TCODE(tcode) ((tcode) << 4) 41#define HEADER_TCODE(tcode) ((tcode) << 4)
46#define HEADER_RETRY(retry) ((retry) << 8) 42#define HEADER_RETRY(retry) ((retry) << 8)
@@ -158,6 +154,18 @@ static void fw_fill_request(struct fw_packet *packet, int tcode, int tlabel,
158{ 154{
159 int ext_tcode; 155 int ext_tcode;
160 156
157 if (tcode == TCODE_STREAM_DATA) {
158 packet->header[0] =
159 HEADER_DATA_LENGTH(length) |
160 destination_id |
161 HEADER_TCODE(TCODE_STREAM_DATA);
162 packet->header_length = 4;
163 packet->payload = payload;
164 packet->payload_length = length;
165
166 goto common;
167 }
168
161 if (tcode > 0x10) { 169 if (tcode > 0x10) {
162 ext_tcode = tcode & ~0x10; 170 ext_tcode = tcode & ~0x10;
163 tcode = TCODE_LOCK_REQUEST; 171 tcode = TCODE_LOCK_REQUEST;
@@ -204,7 +212,7 @@ static void fw_fill_request(struct fw_packet *packet, int tcode, int tlabel,
204 packet->payload_length = 0; 212 packet->payload_length = 0;
205 break; 213 break;
206 } 214 }
207 215 common:
208 packet->speed = speed; 216 packet->speed = speed;
209 packet->generation = generation; 217 packet->generation = generation;
210 packet->ack = 0; 218 packet->ack = 0;
@@ -246,6 +254,9 @@ static void fw_fill_request(struct fw_packet *packet, int tcode, int tlabel,
246 * @param callback function to be called when the transaction is completed 254 * @param callback function to be called when the transaction is completed
247 * @param callback_data pointer to arbitrary data, which will be 255 * @param callback_data pointer to arbitrary data, which will be
248 * passed to the callback 256 * passed to the callback
257 *
258 * In case of asynchronous stream packets i.e. TCODE_STREAM_DATA, the caller
259 * needs to synthesize @destination_id with fw_stream_packet_destination_id().
249 */ 260 */
250void fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode, 261void fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode,
251 int destination_id, int generation, int speed, 262 int destination_id, int generation, int speed,
@@ -297,27 +308,6 @@ void fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode,
297} 308}
298EXPORT_SYMBOL(fw_send_request); 309EXPORT_SYMBOL(fw_send_request);
299 310
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
321struct transaction_callback_data { 311struct transaction_callback_data {
322 struct completion done; 312 struct completion done;
323 void *payload; 313 void *payload;
diff --git a/drivers/firewire/fw-transaction.h b/drivers/firewire/fw-transaction.h
index f90f09c0583..d4f42cecbdf 100644
--- a/drivers/firewire/fw-transaction.h
+++ b/drivers/firewire/fw-transaction.h
@@ -412,10 +412,6 @@ void fw_send_request(struct fw_card *card, struct fw_transaction *t,
412 int tcode, int destination_id, int generation, int speed, 412 int tcode, int destination_id, int generation, int speed,
413 unsigned long long offset, void *payload, size_t length, 413 unsigned long long offset, void *payload, size_t length,
414 fw_transaction_callback_t callback, void *callback_data); 414 fw_transaction_callback_t callback, void *callback_data);
415void fw_send_stream_packet(struct fw_card *card, struct fw_packet *p,
416 int generation, int speed, int channel, int sy, int tag,
417 void *payload, size_t length, fw_packet_callback_t callback);
418
419int fw_cancel_transaction(struct fw_card *card, 415int fw_cancel_transaction(struct fw_card *card,
420 struct fw_transaction *transaction); 416 struct fw_transaction *transaction);
421void fw_flush_transactions(struct fw_card *card); 417void fw_flush_transactions(struct fw_card *card);
@@ -425,6 +421,11 @@ int fw_run_transaction(struct fw_card *card, int tcode, int destination_id,
425void fw_send_phy_config(struct fw_card *card, 421void fw_send_phy_config(struct fw_card *card,
426 int node_id, int generation, int gap_count); 422 int node_id, int generation, int gap_count);
427 423
424static inline int fw_stream_packet_destination_id(int tag, int channel, int sy)
425{
426 return tag << 14 | channel << 8 | sy;
427}
428
428/* 429/*
429 * Called by the topology code to inform the device code of node 430 * Called by the topology code to inform the device code of node
430 * activity; found, lost, or updated nodes. 431 * activity; found, lost, or updated nodes.
diff --git a/include/linux/firewire-cdev.h b/include/linux/firewire-cdev.h
index 25bc82726ef..c6b3ca3af6d 100644
--- a/include/linux/firewire-cdev.h
+++ b/include/linux/firewire-cdev.h
@@ -606,28 +606,29 @@ struct fw_cdev_allocate_iso_resource {
606 606
607/** 607/**
608 * struct fw_cdev_send_stream_packet - send an asynchronous stream packet 608 * struct fw_cdev_send_stream_packet - send an asynchronous stream packet
609 * @generation: Bus generation where the packet is valid 609 * @length: Length of outgoing payload, in bytes
610 * @speed: Speed code to send the packet at 610 * @tag: Data format tag
611 * @channel: Channel to send the packet on 611 * @channel: Isochronous channel to transmit to
612 * @sy: Four-bit sy code for the packet 612 * @sy: Synchronization code
613 * @tag: Two-bit tag field to use for the packet 613 * @closure: Passed back to userspace in the response event
614 * @size: Size of the packet's data payload 614 * @data: Userspace pointer to payload
615 * @data: Userspace pointer to the payload 615 * @generation: The bus generation where packet is valid
616 * @speed: Speed to transmit at
616 * 617 *
617 * The %FW_CDEV_IOC_SEND_STREAM_PACKET ioctl sends an asynchronous stream packet 618 * The %FW_CDEV_IOC_SEND_STREAM_PACKET ioctl sends an asynchronous stream packet
618 * to every device (that is listening to the specified channel) on the 619 * to every device which is listening to the specified channel. The kernel
619 * firewire bus. It is the applications's job to ensure 620 * writes an &fw_cdev_event_response event which indicates success or failure of
620 * that the intended device(s) will be able to receive the packet at the chosen 621 * the transmission.
621 * transmit speed.
622 */ 622 */
623struct fw_cdev_send_stream_packet { 623struct fw_cdev_send_stream_packet {
624 __u32 generation; 624 __u32 length;
625 __u32 speed; 625 __u32 tag;
626 __u32 channel; 626 __u32 channel;
627 __u32 sy; 627 __u32 sy;
628 __u32 tag; 628 __u64 closure;
629 __u32 size;
630 __u64 data; 629 __u64 data;
630 __u32 generation;
631 __u32 speed;
631}; 632};
632 633
633#endif /* _LINUX_FIREWIRE_CDEV_H */ 634#endif /* _LINUX_FIREWIRE_CDEV_H */