diff options
-rw-r--r-- | drivers/firewire/fw-cdev.c | 46 | ||||
-rw-r--r-- | drivers/firewire/fw-transaction.c | 42 | ||||
-rw-r--r-- | drivers/firewire/fw-transaction.h | 9 | ||||
-rw-r--r-- | include/linux/firewire-cdev.h | 31 |
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 | ||
1250 | struct stream_packet { | ||
1251 | struct fw_packet packet; | ||
1252 | u8 data[0]; | ||
1253 | }; | ||
1254 | |||
1255 | static 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 | |||
1261 | static int ioctl_send_stream_packet(struct client *client, void *buffer) | 1251 | static 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 | ||
1282 | static int (* const ioctl_handlers[])(struct client *client, void *buffer) = { | 1274 | static 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 | */ |
250 | void fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode, | 261 | void 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 | } |
298 | EXPORT_SYMBOL(fw_send_request); | 309 | EXPORT_SYMBOL(fw_send_request); |
299 | 310 | ||
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 | } | ||
320 | |||
321 | struct transaction_callback_data { | 311 | struct 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); |
415 | void 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 | |||
419 | int fw_cancel_transaction(struct fw_card *card, | 415 | int fw_cancel_transaction(struct fw_card *card, |
420 | struct fw_transaction *transaction); | 416 | struct fw_transaction *transaction); |
421 | void fw_flush_transactions(struct fw_card *card); | 417 | void fw_flush_transactions(struct fw_card *card); |
@@ -425,6 +421,11 @@ int fw_run_transaction(struct fw_card *card, int tcode, int destination_id, | |||
425 | void fw_send_phy_config(struct fw_card *card, | 421 | void 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 | ||
424 | static 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 | */ |
623 | struct fw_cdev_send_stream_packet { | 623 | struct 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 */ |