aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firewire
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 /drivers/firewire
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>
Diffstat (limited to 'drivers/firewire')
-rw-r--r--drivers/firewire/fw-cdev.c46
-rw-r--r--drivers/firewire/fw-transaction.c42
-rw-r--r--drivers/firewire/fw-transaction.h9
3 files changed, 40 insertions, 57 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.