diff options
Diffstat (limited to 'drivers/firewire/core-cdev.c')
-rw-r--r-- | drivers/firewire/core-cdev.c | 64 |
1 files changed, 64 insertions, 0 deletions
diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c index acf4fa1f3f8c..f95719926487 100644 --- a/drivers/firewire/core-cdev.c +++ b/drivers/firewire/core-cdev.c | |||
@@ -194,6 +194,13 @@ struct iso_resource_event { | |||
194 | struct fw_cdev_event_iso_resource iso_resource; | 194 | struct fw_cdev_event_iso_resource iso_resource; |
195 | }; | 195 | }; |
196 | 196 | ||
197 | struct outbound_phy_packet_event { | ||
198 | struct event event; | ||
199 | struct client *client; | ||
200 | struct fw_packet p; | ||
201 | struct fw_cdev_event_phy_packet phy_packet; | ||
202 | }; | ||
203 | |||
197 | static inline void __user *u64_to_uptr(__u64 value) | 204 | static inline void __user *u64_to_uptr(__u64 value) |
198 | { | 205 | { |
199 | return (void __user *)(unsigned long)value; | 206 | return (void __user *)(unsigned long)value; |
@@ -396,6 +403,7 @@ union ioctl_arg { | |||
396 | struct fw_cdev_allocate_iso_resource allocate_iso_resource; | 403 | struct fw_cdev_allocate_iso_resource allocate_iso_resource; |
397 | struct fw_cdev_send_stream_packet send_stream_packet; | 404 | struct fw_cdev_send_stream_packet send_stream_packet; |
398 | struct fw_cdev_get_cycle_timer2 get_cycle_timer2; | 405 | struct fw_cdev_get_cycle_timer2 get_cycle_timer2; |
406 | struct fw_cdev_send_phy_packet send_phy_packet; | ||
399 | }; | 407 | }; |
400 | 408 | ||
401 | static int ioctl_get_info(struct client *client, union ioctl_arg *arg) | 409 | static int ioctl_get_info(struct client *client, union ioctl_arg *arg) |
@@ -1384,6 +1392,61 @@ static int ioctl_send_stream_packet(struct client *client, union ioctl_arg *arg) | |||
1384 | return init_request(client, &request, dest, a->speed); | 1392 | return init_request(client, &request, dest, a->speed); |
1385 | } | 1393 | } |
1386 | 1394 | ||
1395 | static void outbound_phy_packet_callback(struct fw_packet *packet, | ||
1396 | struct fw_card *card, int status) | ||
1397 | { | ||
1398 | struct outbound_phy_packet_event *e = | ||
1399 | container_of(packet, struct outbound_phy_packet_event, p); | ||
1400 | |||
1401 | switch (status) { | ||
1402 | /* expected: */ | ||
1403 | case ACK_COMPLETE: e->phy_packet.rcode = RCODE_COMPLETE; break; | ||
1404 | /* should never happen with PHY packets: */ | ||
1405 | case ACK_PENDING: e->phy_packet.rcode = RCODE_COMPLETE; break; | ||
1406 | case ACK_BUSY_X: | ||
1407 | case ACK_BUSY_A: | ||
1408 | case ACK_BUSY_B: e->phy_packet.rcode = RCODE_BUSY; break; | ||
1409 | case ACK_DATA_ERROR: e->phy_packet.rcode = RCODE_DATA_ERROR; break; | ||
1410 | case ACK_TYPE_ERROR: e->phy_packet.rcode = RCODE_TYPE_ERROR; break; | ||
1411 | /* stale generation; cancelled; on certain controllers: no ack */ | ||
1412 | default: e->phy_packet.rcode = status; break; | ||
1413 | } | ||
1414 | |||
1415 | queue_event(e->client, &e->event, | ||
1416 | &e->phy_packet, sizeof(e->phy_packet), NULL, 0); | ||
1417 | client_put(e->client); | ||
1418 | } | ||
1419 | |||
1420 | static int ioctl_send_phy_packet(struct client *client, union ioctl_arg *arg) | ||
1421 | { | ||
1422 | struct fw_cdev_send_phy_packet *a = &arg->send_phy_packet; | ||
1423 | struct fw_card *card = client->device->card; | ||
1424 | struct outbound_phy_packet_event *e; | ||
1425 | |||
1426 | /* Access policy: Allow this ioctl only on local nodes' device files. */ | ||
1427 | if (!client->device->is_local) | ||
1428 | return -ENOSYS; | ||
1429 | |||
1430 | e = kzalloc(sizeof(*e), GFP_KERNEL); | ||
1431 | if (e == NULL) | ||
1432 | return -ENOMEM; | ||
1433 | |||
1434 | client_get(client); | ||
1435 | e->client = client; | ||
1436 | e->p.speed = SCODE_100; | ||
1437 | e->p.generation = a->generation; | ||
1438 | e->p.header[0] = a->data[0]; | ||
1439 | e->p.header[1] = a->data[1]; | ||
1440 | e->p.header_length = 8; | ||
1441 | e->p.callback = outbound_phy_packet_callback; | ||
1442 | e->phy_packet.closure = a->closure; | ||
1443 | e->phy_packet.type = FW_CDEV_EVENT_PHY_PACKET_SENT; | ||
1444 | |||
1445 | card->driver->send_request(card, &e->p); | ||
1446 | |||
1447 | return 0; | ||
1448 | } | ||
1449 | |||
1387 | static int (* const ioctl_handlers[])(struct client *, union ioctl_arg *) = { | 1450 | static int (* const ioctl_handlers[])(struct client *, union ioctl_arg *) = { |
1388 | [0x00] = ioctl_get_info, | 1451 | [0x00] = ioctl_get_info, |
1389 | [0x01] = ioctl_send_request, | 1452 | [0x01] = ioctl_send_request, |
@@ -1406,6 +1469,7 @@ static int (* const ioctl_handlers[])(struct client *, union ioctl_arg *) = { | |||
1406 | [0x12] = ioctl_send_broadcast_request, | 1469 | [0x12] = ioctl_send_broadcast_request, |
1407 | [0x13] = ioctl_send_stream_packet, | 1470 | [0x13] = ioctl_send_stream_packet, |
1408 | [0x14] = ioctl_get_cycle_timer2, | 1471 | [0x14] = ioctl_get_cycle_timer2, |
1472 | [0x15] = ioctl_send_phy_packet, | ||
1409 | }; | 1473 | }; |
1410 | 1474 | ||
1411 | static int dispatch_ioctl(struct client *client, | 1475 | static int dispatch_ioctl(struct client *client, |