aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firewire
diff options
context:
space:
mode:
authorStefan Richter <stefanr@s5r6.in-berlin.de>2010-07-16 16:25:14 -0400
committerStefan Richter <stefanr@s5r6.in-berlin.de>2010-07-23 07:36:28 -0400
commit850bb6f23b93c04ce1e4509a87fa607dc17d97c1 (patch)
tree4ec66cea35e15ff095799bae4aec7c1071d4faa4 /drivers/firewire
parentb9dc61cf404165fb77e80c853e9fec9af258f9ce (diff)
firewire: cdev: add PHY packet transmission
Add an FW_CDEV_IOC_SEND_PHY_PACKET ioctl() for /dev/fw* which can be used to implement bus management related functionality in userspace. This is also half of the functionality (the transmit part) that is needed to support a userspace implementation of a VersaPHY transaction layer. Safety considerations: - PHY packets are generally broadcasts and may have interesting effects on PHYs and the bus, e.g. make asynchronous arbitration impossible due to too low gap count. Hence some kind of elevated privileges should be required of a process to be able to send PHY packets. This implementation assumes that a process that is allowed to open the /dev/fw* of a local node does have this privilege. There was an inconclusive discussion about introducing POSIX capabilities as a means to check for user privileges for these kinds of operations. - The kernel does not check integrity of the supplied packet data. That would be far too much code, considering the many kinds of PHY packets. A process which got the privilege to send these packets is trusted to do it correctly. Just like with the other "send packet" ioctls, a non-blocking API is chosen; i.e. the ioctl may return even before AT DMA started. After transmission, an event for poll()/read() is enqueued. Most users are going to need a blocking API, but a blocking userspace wrapper is easy to implement, and the second of the two existing libraw1394 calls raw1394_phy_packet_write() and raw1394_start_phy_packet_write() can be better supported that way. Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Diffstat (limited to 'drivers/firewire')
-rw-r--r--drivers/firewire/core-cdev.c64
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
197struct 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
197static inline void __user *u64_to_uptr(__u64 value) 204static 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
401static int ioctl_get_info(struct client *client, union ioctl_arg *arg) 409static 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
1395static 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
1420static 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
1387static int (* const ioctl_handlers[])(struct client *, union ioctl_arg *) = { 1450static 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
1411static int dispatch_ioctl(struct client *client, 1475static int dispatch_ioctl(struct client *client,