diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c index 2220de3c945e..6274b86eb943 100644 --- a/drivers/firewire/core-cdev.c +++ b/drivers/firewire/core-cdev.c @@ -206,6 +206,7 @@ struct outbound_phy_packet_event { struct fw_packet p; union { struct fw_cdev_event_phy_packet without_tstamp; + struct fw_cdev_event_phy_packet2 with_tstamp; } phy_packet; }; @@ -213,6 +214,7 @@ struct inbound_phy_packet_event { struct event event; union { struct fw_cdev_event_phy_packet without_tstamp; + struct fw_cdev_event_phy_packet2 with_tstamp; } phy_packet; }; @@ -1555,7 +1557,6 @@ static void outbound_phy_packet_callback(struct fw_packet *packet, container_of(packet, struct outbound_phy_packet_event, p); struct client *e_client = e->client; u32 rcode; - struct fw_cdev_event_phy_packet *pp; switch (status) { // expected: @@ -1583,10 +1584,31 @@ static void outbound_phy_packet_callback(struct fw_packet *packet, break; } - pp = &e->phy_packet.without_tstamp; - pp->rcode = rcode; - pp->data[0] = packet->timestamp; - queue_event(e->client, &e->event, &e->phy_packet, sizeof(*pp) + pp->length, NULL, 0); + switch (e->phy_packet.without_tstamp.type) { + case FW_CDEV_EVENT_PHY_PACKET_SENT: + { + struct fw_cdev_event_phy_packet *pp = &e->phy_packet.without_tstamp; + + pp->rcode = rcode; + pp->data[0] = packet->timestamp; + queue_event(e->client, &e->event, &e->phy_packet, sizeof(*pp) + pp->length, + NULL, 0); + break; + } + case FW_CDEV_EVENT_PHY_PACKET_SENT2: + { + struct fw_cdev_event_phy_packet2 *pp = &e->phy_packet.with_tstamp; + + pp->rcode = rcode; + pp->tstamp = packet->timestamp; + queue_event(e->client, &e->event, &e->phy_packet, sizeof(*pp) + pp->length, + NULL, 0); + break; + } + default: + WARN_ON(1); + break; + } client_put(e_client); } @@ -1596,13 +1618,12 @@ static int ioctl_send_phy_packet(struct client *client, union ioctl_arg *arg) struct fw_cdev_send_phy_packet *a = &arg->send_phy_packet; struct fw_card *card = client->device->card; struct outbound_phy_packet_event *e; - struct fw_cdev_event_phy_packet *pp; /* Access policy: Allow this ioctl only on local nodes' device files. */ if (!client->device->is_local) return -ENOSYS; - e = kzalloc(sizeof(*e) + 4, GFP_KERNEL); + e = kzalloc(sizeof(*e) + sizeof(a->data), GFP_KERNEL); if (e == NULL) return -ENOMEM; @@ -1616,11 +1637,23 @@ static int ioctl_send_phy_packet(struct client *client, union ioctl_arg *arg) e->p.header_length = 12; e->p.callback = outbound_phy_packet_callback; - pp = &e->phy_packet.without_tstamp; - pp->closure = a->closure; - pp->type = FW_CDEV_EVENT_PHY_PACKET_SENT; - if (is_ping_packet(a->data)) - pp->length = 4; + if (client->version < FW_CDEV_VERSION_EVENT_ASYNC_TSTAMP) { + struct fw_cdev_event_phy_packet *pp = &e->phy_packet.without_tstamp; + + pp->closure = a->closure; + pp->type = FW_CDEV_EVENT_PHY_PACKET_SENT; + if (is_ping_packet(a->data)) + pp->length = 4; + } else { + struct fw_cdev_event_phy_packet2 *pp = &e->phy_packet.with_tstamp; + + pp->closure = a->closure; + pp->type = FW_CDEV_EVENT_PHY_PACKET_SENT2; + // Keep the data field so that application can match the response event to the + // request. + pp->length = sizeof(a->data); + memcpy(pp->data, a->data, sizeof(a->data)); + } card->driver->send_request(card, &e->p); @@ -1655,20 +1688,33 @@ void fw_cdev_handle_phy_packet(struct fw_card *card, struct fw_packet *p) spin_lock_irqsave(&card->lock, flags); list_for_each_entry(client, &card->phy_receiver_list, phy_receiver_link) { - struct fw_cdev_event_phy_packet *pp; - e = kmalloc(sizeof(*e) + 8, GFP_ATOMIC); if (e == NULL) break; - pp = &e->phy_packet.without_tstamp; - pp->closure = client->phy_receiver_closure; - pp->type = FW_CDEV_EVENT_PHY_PACKET_RECEIVED; - pp->rcode = RCODE_COMPLETE; - pp->length = 8; - pp->data[0] = p->header[1]; - pp->data[1] = p->header[2]; - queue_event(client, &e->event, &e->phy_packet, sizeof(*pp) + 8, NULL, 0); + if (client->version < FW_CDEV_VERSION_EVENT_ASYNC_TSTAMP) { + struct fw_cdev_event_phy_packet *pp = &e->phy_packet.without_tstamp; + + pp->closure = client->phy_receiver_closure; + pp->type = FW_CDEV_EVENT_PHY_PACKET_RECEIVED; + pp->rcode = RCODE_COMPLETE; + pp->length = 8; + pp->data[0] = p->header[1]; + pp->data[1] = p->header[2]; + queue_event(client, &e->event, &e->phy_packet, sizeof(*pp) + 8, NULL, 0); + } else { + struct fw_cdev_event_phy_packet2 *pp = &e->phy_packet.with_tstamp; + + pp = &e->phy_packet.with_tstamp; + pp->closure = client->phy_receiver_closure; + pp->type = FW_CDEV_EVENT_PHY_PACKET_RECEIVED2; + pp->rcode = RCODE_COMPLETE; + pp->length = 8; + pp->tstamp = p->timestamp; + pp->data[0] = p->header[1]; + pp->data[1] = p->header[2]; + queue_event(client, &e->event, &e->phy_packet, sizeof(*pp) + 8, NULL, 0); + } } spin_unlock_irqrestore(&card->lock, flags);