diff options
-rw-r--r-- | drivers/firewire/core-card.c | 1 | ||||
-rw-r--r-- | drivers/firewire/core-cdev.c | 73 | ||||
-rw-r--r-- | drivers/firewire/core-transaction.c | 5 | ||||
-rw-r--r-- | drivers/firewire/core.h | 2 | ||||
-rw-r--r-- | drivers/firewire/ohci.c | 3 | ||||
-rw-r--r-- | include/linux/firewire-cdev.h | 39 | ||||
-rw-r--r-- | include/linux/firewire.h | 3 |
7 files changed, 111 insertions, 15 deletions
diff --git a/drivers/firewire/core-card.c b/drivers/firewire/core-card.c index 0c312c4bb4b..6d1cfae6aad 100644 --- a/drivers/firewire/core-card.c +++ b/drivers/firewire/core-card.c | |||
@@ -500,6 +500,7 @@ void fw_card_initialize(struct fw_card *card, | |||
500 | kref_init(&card->kref); | 500 | kref_init(&card->kref); |
501 | init_completion(&card->done); | 501 | init_completion(&card->done); |
502 | INIT_LIST_HEAD(&card->transaction_list); | 502 | INIT_LIST_HEAD(&card->transaction_list); |
503 | INIT_LIST_HEAD(&card->phy_receiver_list); | ||
503 | spin_lock_init(&card->lock); | 504 | spin_lock_init(&card->lock); |
504 | 505 | ||
505 | card->local_node = NULL; | 506 | card->local_node = NULL; |
diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c index f9571992648..0425dd5dfcd 100644 --- a/drivers/firewire/core-cdev.c +++ b/drivers/firewire/core-cdev.c | |||
@@ -69,6 +69,9 @@ struct client { | |||
69 | struct fw_iso_buffer buffer; | 69 | struct fw_iso_buffer buffer; |
70 | unsigned long vm_start; | 70 | unsigned long vm_start; |
71 | 71 | ||
72 | struct list_head phy_receiver_link; | ||
73 | u64 phy_receiver_closure; | ||
74 | |||
72 | struct list_head link; | 75 | struct list_head link; |
73 | struct kref kref; | 76 | struct kref kref; |
74 | }; | 77 | }; |
@@ -201,6 +204,11 @@ struct outbound_phy_packet_event { | |||
201 | struct fw_cdev_event_phy_packet phy_packet; | 204 | struct fw_cdev_event_phy_packet phy_packet; |
202 | }; | 205 | }; |
203 | 206 | ||
207 | struct inbound_phy_packet_event { | ||
208 | struct event event; | ||
209 | struct fw_cdev_event_phy_packet phy_packet; | ||
210 | }; | ||
211 | |||
204 | static inline void __user *u64_to_uptr(__u64 value) | 212 | static inline void __user *u64_to_uptr(__u64 value) |
205 | { | 213 | { |
206 | return (void __user *)(unsigned long)value; | 214 | return (void __user *)(unsigned long)value; |
@@ -236,6 +244,7 @@ static int fw_device_op_open(struct inode *inode, struct file *file) | |||
236 | idr_init(&client->resource_idr); | 244 | idr_init(&client->resource_idr); |
237 | INIT_LIST_HEAD(&client->event_list); | 245 | INIT_LIST_HEAD(&client->event_list); |
238 | init_waitqueue_head(&client->wait); | 246 | init_waitqueue_head(&client->wait); |
247 | INIT_LIST_HEAD(&client->phy_receiver_link); | ||
239 | kref_init(&client->kref); | 248 | kref_init(&client->kref); |
240 | 249 | ||
241 | file->private_data = client; | 250 | file->private_data = client; |
@@ -357,7 +366,7 @@ static void queue_bus_reset_event(struct client *client) | |||
357 | 366 | ||
358 | e = kzalloc(sizeof(*e), GFP_KERNEL); | 367 | e = kzalloc(sizeof(*e), GFP_KERNEL); |
359 | if (e == NULL) { | 368 | if (e == NULL) { |
360 | fw_notify("Out of memory when allocating bus reset event\n"); | 369 | fw_notify("Out of memory when allocating event\n"); |
361 | return; | 370 | return; |
362 | } | 371 | } |
363 | 372 | ||
@@ -404,6 +413,7 @@ union ioctl_arg { | |||
404 | struct fw_cdev_send_stream_packet send_stream_packet; | 413 | struct fw_cdev_send_stream_packet send_stream_packet; |
405 | struct fw_cdev_get_cycle_timer2 get_cycle_timer2; | 414 | struct fw_cdev_get_cycle_timer2 get_cycle_timer2; |
406 | struct fw_cdev_send_phy_packet send_phy_packet; | 415 | struct fw_cdev_send_phy_packet send_phy_packet; |
416 | struct fw_cdev_receive_phy_packets receive_phy_packets; | ||
407 | }; | 417 | }; |
408 | 418 | ||
409 | static int ioctl_get_info(struct client *client, union ioctl_arg *arg) | 419 | static int ioctl_get_info(struct client *client, union ioctl_arg *arg) |
@@ -671,9 +681,10 @@ static void handle_request(struct fw_card *card, struct fw_request *request, | |||
671 | 681 | ||
672 | r = kmalloc(sizeof(*r), GFP_ATOMIC); | 682 | r = kmalloc(sizeof(*r), GFP_ATOMIC); |
673 | e = kmalloc(sizeof(*e), GFP_ATOMIC); | 683 | e = kmalloc(sizeof(*e), GFP_ATOMIC); |
674 | if (r == NULL || e == NULL) | 684 | if (r == NULL || e == NULL) { |
685 | fw_notify("Out of memory when allocating event\n"); | ||
675 | goto failed; | 686 | goto failed; |
676 | 687 | } | |
677 | r->card = card; | 688 | r->card = card; |
678 | r->request = request; | 689 | r->request = request; |
679 | r->data = payload; | 690 | r->data = payload; |
@@ -902,9 +913,10 @@ static void iso_callback(struct fw_iso_context *context, u32 cycle, | |||
902 | struct iso_interrupt_event *e; | 913 | struct iso_interrupt_event *e; |
903 | 914 | ||
904 | e = kmalloc(sizeof(*e) + header_length, GFP_ATOMIC); | 915 | e = kmalloc(sizeof(*e) + header_length, GFP_ATOMIC); |
905 | if (e == NULL) | 916 | if (e == NULL) { |
917 | fw_notify("Out of memory when allocating event\n"); | ||
906 | return; | 918 | return; |
907 | 919 | } | |
908 | e->interrupt.type = FW_CDEV_EVENT_ISO_INTERRUPT; | 920 | e->interrupt.type = FW_CDEV_EVENT_ISO_INTERRUPT; |
909 | e->interrupt.closure = client->iso_closure; | 921 | e->interrupt.closure = client->iso_closure; |
910 | e->interrupt.cycle = cycle; | 922 | e->interrupt.cycle = cycle; |
@@ -1447,6 +1459,52 @@ static int ioctl_send_phy_packet(struct client *client, union ioctl_arg *arg) | |||
1447 | return 0; | 1459 | return 0; |
1448 | } | 1460 | } |
1449 | 1461 | ||
1462 | static int ioctl_receive_phy_packets(struct client *client, union ioctl_arg *arg) | ||
1463 | { | ||
1464 | struct fw_cdev_receive_phy_packets *a = &arg->receive_phy_packets; | ||
1465 | struct fw_card *card = client->device->card; | ||
1466 | |||
1467 | /* Access policy: Allow this ioctl only on local nodes' device files. */ | ||
1468 | if (!client->device->is_local) | ||
1469 | return -ENOSYS; | ||
1470 | |||
1471 | spin_lock_irq(&card->lock); | ||
1472 | |||
1473 | list_move_tail(&client->phy_receiver_link, &card->phy_receiver_list); | ||
1474 | client->phy_receiver_closure = a->closure; | ||
1475 | |||
1476 | spin_unlock_irq(&card->lock); | ||
1477 | |||
1478 | return 0; | ||
1479 | } | ||
1480 | |||
1481 | void fw_cdev_handle_phy_packet(struct fw_card *card, struct fw_packet *p) | ||
1482 | { | ||
1483 | struct client *client; | ||
1484 | struct inbound_phy_packet_event *e; | ||
1485 | unsigned long flags; | ||
1486 | |||
1487 | spin_lock_irqsave(&card->lock, flags); | ||
1488 | |||
1489 | list_for_each_entry(client, &card->phy_receiver_list, phy_receiver_link) { | ||
1490 | e = kmalloc(sizeof(*e) + 8, GFP_ATOMIC); | ||
1491 | if (e == NULL) { | ||
1492 | fw_notify("Out of memory when allocating event\n"); | ||
1493 | break; | ||
1494 | } | ||
1495 | e->phy_packet.closure = client->phy_receiver_closure; | ||
1496 | e->phy_packet.type = FW_CDEV_EVENT_PHY_PACKET_RECEIVED; | ||
1497 | e->phy_packet.rcode = RCODE_COMPLETE; | ||
1498 | e->phy_packet.length = 8; | ||
1499 | e->phy_packet.data[0] = p->header[1]; | ||
1500 | e->phy_packet.data[1] = p->header[2]; | ||
1501 | queue_event(client, &e->event, | ||
1502 | &e->phy_packet, sizeof(e->phy_packet) + 8, NULL, 0); | ||
1503 | } | ||
1504 | |||
1505 | spin_unlock_irqrestore(&card->lock, flags); | ||
1506 | } | ||
1507 | |||
1450 | static int (* const ioctl_handlers[])(struct client *, union ioctl_arg *) = { | 1508 | static int (* const ioctl_handlers[])(struct client *, union ioctl_arg *) = { |
1451 | [0x00] = ioctl_get_info, | 1509 | [0x00] = ioctl_get_info, |
1452 | [0x01] = ioctl_send_request, | 1510 | [0x01] = ioctl_send_request, |
@@ -1470,6 +1528,7 @@ static int (* const ioctl_handlers[])(struct client *, union ioctl_arg *) = { | |||
1470 | [0x13] = ioctl_send_stream_packet, | 1528 | [0x13] = ioctl_send_stream_packet, |
1471 | [0x14] = ioctl_get_cycle_timer2, | 1529 | [0x14] = ioctl_get_cycle_timer2, |
1472 | [0x15] = ioctl_send_phy_packet, | 1530 | [0x15] = ioctl_send_phy_packet, |
1531 | [0x16] = ioctl_receive_phy_packets, | ||
1473 | }; | 1532 | }; |
1474 | 1533 | ||
1475 | static int dispatch_ioctl(struct client *client, | 1534 | static int dispatch_ioctl(struct client *client, |
@@ -1577,6 +1636,10 @@ static int fw_device_op_release(struct inode *inode, struct file *file) | |||
1577 | struct client *client = file->private_data; | 1636 | struct client *client = file->private_data; |
1578 | struct event *event, *next_event; | 1637 | struct event *event, *next_event; |
1579 | 1638 | ||
1639 | spin_lock_irq(&client->device->card->lock); | ||
1640 | list_del(&client->phy_receiver_link); | ||
1641 | spin_unlock_irq(&client->device->card->lock); | ||
1642 | |||
1580 | mutex_lock(&client->device->client_list_mutex); | 1643 | mutex_lock(&client->device->client_list_mutex); |
1581 | list_del(&client->link); | 1644 | list_del(&client->link); |
1582 | mutex_unlock(&client->device->client_list_mutex); | 1645 | mutex_unlock(&client->device->client_list_mutex); |
diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c index e2e4dc624fb..6f225cacbc3 100644 --- a/drivers/firewire/core-transaction.c +++ b/drivers/firewire/core-transaction.c | |||
@@ -883,6 +883,11 @@ void fw_core_handle_request(struct fw_card *card, struct fw_packet *p) | |||
883 | if (p->ack != ACK_PENDING && p->ack != ACK_COMPLETE) | 883 | if (p->ack != ACK_PENDING && p->ack != ACK_COMPLETE) |
884 | return; | 884 | return; |
885 | 885 | ||
886 | if (TCODE_IS_LINK_INTERNAL(HEADER_GET_TCODE(p->header[0]))) { | ||
887 | fw_cdev_handle_phy_packet(card, p); | ||
888 | return; | ||
889 | } | ||
890 | |||
886 | request = allocate_request(card, p); | 891 | request = allocate_request(card, p); |
887 | if (request == NULL) { | 892 | if (request == NULL) { |
888 | /* FIXME: send statically allocated busy packet. */ | 893 | /* FIXME: send statically allocated busy packet. */ |
diff --git a/drivers/firewire/core.h b/drivers/firewire/core.h index ff6c9092200..3102b6b6343 100644 --- a/drivers/firewire/core.h +++ b/drivers/firewire/core.h | |||
@@ -128,6 +128,7 @@ extern const struct file_operations fw_device_ops; | |||
128 | 128 | ||
129 | void fw_device_cdev_update(struct fw_device *device); | 129 | void fw_device_cdev_update(struct fw_device *device); |
130 | void fw_device_cdev_remove(struct fw_device *device); | 130 | void fw_device_cdev_remove(struct fw_device *device); |
131 | void fw_cdev_handle_phy_packet(struct fw_card *card, struct fw_packet *p); | ||
131 | 132 | ||
132 | 133 | ||
133 | /* -device */ | 134 | /* -device */ |
@@ -214,6 +215,7 @@ static inline bool is_next_generation(int new_generation, int old_generation) | |||
214 | 215 | ||
215 | #define TCODE_IS_READ_REQUEST(tcode) (((tcode) & ~1) == 4) | 216 | #define TCODE_IS_READ_REQUEST(tcode) (((tcode) & ~1) == 4) |
216 | #define TCODE_IS_BLOCK_PACKET(tcode) (((tcode) & 1) != 0) | 217 | #define TCODE_IS_BLOCK_PACKET(tcode) (((tcode) & 1) != 0) |
218 | #define TCODE_IS_LINK_INTERNAL(tcode) ((tcode) == 0xe) | ||
217 | #define TCODE_IS_REQUEST(tcode) (((tcode) & 2) == 0) | 219 | #define TCODE_IS_REQUEST(tcode) (((tcode) & 2) == 0) |
218 | #define TCODE_IS_RESPONSE(tcode) (((tcode) & 2) != 0) | 220 | #define TCODE_IS_RESPONSE(tcode) (((tcode) & 2) != 0) |
219 | #define TCODE_HAS_REQUEST_DATA(tcode) (((tcode) & 12) != 4) | 221 | #define TCODE_HAS_REQUEST_DATA(tcode) (((tcode) & 12) != 4) |
diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index bb6a92bc9e6..08afccc6633 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c | |||
@@ -1759,10 +1759,9 @@ static int ohci_enable(struct fw_card *card, | |||
1759 | OHCI1394_HCControl_noByteSwapData); | 1759 | OHCI1394_HCControl_noByteSwapData); |
1760 | 1760 | ||
1761 | reg_write(ohci, OHCI1394_SelfIDBuffer, ohci->self_id_bus); | 1761 | reg_write(ohci, OHCI1394_SelfIDBuffer, ohci->self_id_bus); |
1762 | reg_write(ohci, OHCI1394_LinkControlClear, | ||
1763 | OHCI1394_LinkControl_rcvPhyPkt); | ||
1764 | reg_write(ohci, OHCI1394_LinkControlSet, | 1762 | reg_write(ohci, OHCI1394_LinkControlSet, |
1765 | OHCI1394_LinkControl_rcvSelfID | | 1763 | OHCI1394_LinkControl_rcvSelfID | |
1764 | OHCI1394_LinkControl_rcvPhyPkt | | ||
1766 | OHCI1394_LinkControl_cycleTimerEnable | | 1765 | OHCI1394_LinkControl_cycleTimerEnable | |
1767 | OHCI1394_LinkControl_cycleMaster); | 1766 | OHCI1394_LinkControl_cycleMaster); |
1768 | 1767 | ||
diff --git a/include/linux/firewire-cdev.h b/include/linux/firewire-cdev.h index 5bc051b9a01..b8740916079 100644 --- a/include/linux/firewire-cdev.h +++ b/include/linux/firewire-cdev.h | |||
@@ -35,6 +35,7 @@ | |||
35 | /* available since kernel version 2.6.36 */ | 35 | /* available since kernel version 2.6.36 */ |
36 | #define FW_CDEV_EVENT_REQUEST2 0x06 | 36 | #define FW_CDEV_EVENT_REQUEST2 0x06 |
37 | #define FW_CDEV_EVENT_PHY_PACKET_SENT 0x07 | 37 | #define FW_CDEV_EVENT_PHY_PACKET_SENT 0x07 |
38 | #define FW_CDEV_EVENT_PHY_PACKET_RECEIVED 0x08 | ||
38 | 39 | ||
39 | /** | 40 | /** |
40 | * struct fw_cdev_event_common - Common part of all fw_cdev_event_ types | 41 | * struct fw_cdev_event_common - Common part of all fw_cdev_event_ types |
@@ -285,16 +286,24 @@ struct fw_cdev_event_iso_resource { | |||
285 | }; | 286 | }; |
286 | 287 | ||
287 | /** | 288 | /** |
288 | * struct fw_cdev_event_phy_packet - A PHY packet was transmitted | 289 | * struct fw_cdev_event_phy_packet - A PHY packet was transmitted or received |
289 | * @closure: See &fw_cdev_event_common; | 290 | * @closure: See &fw_cdev_event_common; set by %FW_CDEV_IOC_SEND_PHY_PACKET |
290 | * set by %FW_CDEV_IOC_SEND_PHY_PACKET ioctl | 291 | * or %FW_CDEV_IOC_RECEIVE_PHY_PACKETS ioctl |
291 | * @type: %FW_CDEV_EVENT_PHY_PACKET_SENT | 292 | * @type: %FW_CDEV_EVENT_PHY_PACKET_SENT or %..._RECEIVED |
292 | * @rcode: %RCODE_..., indicates success or failure of transmission | 293 | * @rcode: %RCODE_..., indicates success or failure of transmission |
294 | * @length: Data length in bytes | ||
295 | * @data: Incoming data | ||
296 | * | ||
297 | * If @type is %FW_CDEV_EVENT_PHY_PACKET_SENT, @length is 0 and @data empty. | ||
298 | * If @type is %FW_CDEV_EVENT_PHY_PACKET_RECEIVED, @length is 8 and @data | ||
299 | * consists of the two PHY packet quadlets, in host byte order. | ||
293 | */ | 300 | */ |
294 | struct fw_cdev_event_phy_packet { | 301 | struct fw_cdev_event_phy_packet { |
295 | __u64 closure; | 302 | __u64 closure; |
296 | __u32 type; | 303 | __u32 type; |
297 | __u32 rcode; | 304 | __u32 rcode; |
305 | __u32 length; | ||
306 | __u32 data[0]; | ||
298 | }; | 307 | }; |
299 | 308 | ||
300 | /** | 309 | /** |
@@ -308,7 +317,9 @@ struct fw_cdev_event_phy_packet { | |||
308 | * @iso_resource: Valid if @common.type == | 317 | * @iso_resource: Valid if @common.type == |
309 | * %FW_CDEV_EVENT_ISO_RESOURCE_ALLOCATED or | 318 | * %FW_CDEV_EVENT_ISO_RESOURCE_ALLOCATED or |
310 | * %FW_CDEV_EVENT_ISO_RESOURCE_DEALLOCATED | 319 | * %FW_CDEV_EVENT_ISO_RESOURCE_DEALLOCATED |
311 | * @phy_packet: Valid if @common.type == %FW_CDEV_EVENT_PHY_PACKET_SENT | 320 | * @phy_packet: Valid if @common.type == |
321 | * %FW_CDEV_EVENT_PHY_PACKET_SENT or | ||
322 | * %FW_CDEV_EVENT_PHY_PACKET_RECEIVED | ||
312 | * | 323 | * |
313 | * Convenience union for userspace use. Events could be read(2) into an | 324 | * Convenience union for userspace use. Events could be read(2) into an |
314 | * appropriately aligned char buffer and then cast to this union for further | 325 | * appropriately aligned char buffer and then cast to this union for further |
@@ -360,6 +371,7 @@ union fw_cdev_event { | |||
360 | 371 | ||
361 | /* available since kernel version 2.6.36 */ | 372 | /* available since kernel version 2.6.36 */ |
362 | #define FW_CDEV_IOC_SEND_PHY_PACKET _IOWR('#', 0x15, struct fw_cdev_send_phy_packet) | 373 | #define FW_CDEV_IOC_SEND_PHY_PACKET _IOWR('#', 0x15, struct fw_cdev_send_phy_packet) |
374 | #define FW_CDEV_IOC_RECEIVE_PHY_PACKETS _IOW('#', 0x16, struct fw_cdev_receive_phy_packets) | ||
363 | 375 | ||
364 | /* | 376 | /* |
365 | * ABI version history | 377 | * ABI version history |
@@ -376,9 +388,9 @@ union fw_cdev_event { | |||
376 | * - shared use and auto-response for FCP registers | 388 | * - shared use and auto-response for FCP registers |
377 | * 3 (2.6.34) - made &fw_cdev_get_cycle_timer reliable | 389 | * 3 (2.6.34) - made &fw_cdev_get_cycle_timer reliable |
378 | * - added %FW_CDEV_IOC_GET_CYCLE_TIMER2 | 390 | * - added %FW_CDEV_IOC_GET_CYCLE_TIMER2 |
379 | * 4 (2.6.36) - added %FW_CDEV_EVENT_REQUEST2, %FW_CDEV_EVENT_PHY_PACKET_SENT | 391 | * 4 (2.6.36) - added %FW_CDEV_EVENT_REQUEST2, %FW_CDEV_EVENT_PHY_PACKET_* |
380 | * - implemented &fw_cdev_event_bus_reset.bm_node_id | 392 | * - implemented &fw_cdev_event_bus_reset.bm_node_id |
381 | * - added %FW_CDEV_IOC_SEND_PHY_PACKET | 393 | * - added %FW_CDEV_IOC_SEND_PHY_PACKET, _RECEIVE_PHY_PACKETS |
382 | */ | 394 | */ |
383 | #define FW_CDEV_VERSION 3 /* Meaningless; don't use this macro. */ | 395 | #define FW_CDEV_VERSION 3 /* Meaningless; don't use this macro. */ |
384 | 396 | ||
@@ -850,4 +862,17 @@ struct fw_cdev_send_phy_packet { | |||
850 | __u32 generation; | 862 | __u32 generation; |
851 | }; | 863 | }; |
852 | 864 | ||
865 | /** | ||
866 | * struct fw_cdev_receive_phy_packets - start reception of PHY packets | ||
867 | * @closure: Passed back to userspace in phy packet events | ||
868 | * | ||
869 | * This ioctl activates issuing of %FW_CDEV_EVENT_PHY_PACKET_RECEIVED due to | ||
870 | * incoming PHY packets from any node on the same bus as the device. | ||
871 | * | ||
872 | * The ioctl is only permitted on device files which represent a local node. | ||
873 | */ | ||
874 | struct fw_cdev_receive_phy_packets { | ||
875 | __u64 closure; | ||
876 | }; | ||
877 | |||
853 | #endif /* _LINUX_FIREWIRE_CDEV_H */ | 878 | #endif /* _LINUX_FIREWIRE_CDEV_H */ |
diff --git a/include/linux/firewire.h b/include/linux/firewire.h index 0c38b8e9772..d974aa4a24c 100644 --- a/include/linux/firewire.h +++ b/include/linux/firewire.h | |||
@@ -111,9 +111,10 @@ struct fw_card { | |||
111 | bool beta_repeaters_present; | 111 | bool beta_repeaters_present; |
112 | 112 | ||
113 | int index; | 113 | int index; |
114 | |||
115 | struct list_head link; | 114 | struct list_head link; |
116 | 115 | ||
116 | struct list_head phy_receiver_list; | ||
117 | |||
117 | struct delayed_work br_work; /* bus reset job */ | 118 | struct delayed_work br_work; /* bus reset job */ |
118 | bool br_short; | 119 | bool br_short; |
119 | 120 | ||