aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Richter <stefanr@s5r6.in-berlin.de>2009-03-10 16:02:21 -0400
committerStefan Richter <stefanr@s5r6.in-berlin.de>2009-03-24 15:56:50 -0400
commit18e9b10fcdc090d3a38606958167d5923c7099b7 (patch)
treefd83055d908e8786afc9b3fbc791b57b2ba10c33
parent664d8010b170ae8b3ce9268b4f4da934d27b0491 (diff)
firewire: cdev: add closure to async stream ioctl
This changes the as yet unreleased FW_CDEV_IOC_SEND_STREAM_PACKET ioctl to generate an fw_cdev_event_response event just like the other two ioctls for asynchronous request transmission do. This way, clients get feedback on successful or unsuccessful transmission. This also adds input validation for length, tag, channel, sy, speed. Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
-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 95a207545eb3..7eb6594cc3e5 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 e3da58991960..4a9b37461c26 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 f90f09c05833..d4f42cecbdfa 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 25bc82726ef7..c6b3ca3af6df 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 */