Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 206847
b: refs/heads/master
c: bf54e14
h: refs/heads/master
i:
  206845: ee42056
  206843: 852aea8
  206839: f6abfde
  206831: 43bbef6
  206815: b77f95a
  206783: 0226ca6
  206719: a3e4717
  206591: 4b2a770
  206335: 441ebf9
  205823: 300cd0e
  204799: 77a3bfc
v: v3
  • Loading branch information
Stefan Richter committed Jul 23, 2010
1 parent a646dcf commit 29db891
Show file tree
Hide file tree
Showing 8 changed files with 112 additions and 16 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 850bb6f23b93c04ce1e4509a87fa607dc17d97c1
refs/heads/master: bf54e1462b9192fdef7ea9e2bc44fdc16a4b87bc
1 change: 1 addition & 0 deletions trunk/drivers/firewire/core-card.c
Original file line number Diff line number Diff line change
Expand Up @@ -500,6 +500,7 @@ void fw_card_initialize(struct fw_card *card,
kref_init(&card->kref);
init_completion(&card->done);
INIT_LIST_HEAD(&card->transaction_list);
INIT_LIST_HEAD(&card->phy_receiver_list);
spin_lock_init(&card->lock);

card->local_node = NULL;
Expand Down
73 changes: 68 additions & 5 deletions trunk/drivers/firewire/core-cdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ struct client {
struct fw_iso_buffer buffer;
unsigned long vm_start;

struct list_head phy_receiver_link;
u64 phy_receiver_closure;

struct list_head link;
struct kref kref;
};
Expand Down Expand Up @@ -201,6 +204,11 @@ struct outbound_phy_packet_event {
struct fw_cdev_event_phy_packet phy_packet;
};

struct inbound_phy_packet_event {
struct event event;
struct fw_cdev_event_phy_packet phy_packet;
};

static inline void __user *u64_to_uptr(__u64 value)
{
return (void __user *)(unsigned long)value;
Expand Down Expand Up @@ -236,6 +244,7 @@ static int fw_device_op_open(struct inode *inode, struct file *file)
idr_init(&client->resource_idr);
INIT_LIST_HEAD(&client->event_list);
init_waitqueue_head(&client->wait);
INIT_LIST_HEAD(&client->phy_receiver_link);
kref_init(&client->kref);

file->private_data = client;
Expand Down Expand Up @@ -357,7 +366,7 @@ static void queue_bus_reset_event(struct client *client)

e = kzalloc(sizeof(*e), GFP_KERNEL);
if (e == NULL) {
fw_notify("Out of memory when allocating bus reset event\n");
fw_notify("Out of memory when allocating event\n");
return;
}

Expand Down Expand Up @@ -404,6 +413,7 @@ union ioctl_arg {
struct fw_cdev_send_stream_packet send_stream_packet;
struct fw_cdev_get_cycle_timer2 get_cycle_timer2;
struct fw_cdev_send_phy_packet send_phy_packet;
struct fw_cdev_receive_phy_packets receive_phy_packets;
};

static int ioctl_get_info(struct client *client, union ioctl_arg *arg)
Expand Down Expand Up @@ -671,9 +681,10 @@ static void handle_request(struct fw_card *card, struct fw_request *request,

r = kmalloc(sizeof(*r), GFP_ATOMIC);
e = kmalloc(sizeof(*e), GFP_ATOMIC);
if (r == NULL || e == NULL)
if (r == NULL || e == NULL) {
fw_notify("Out of memory when allocating event\n");
goto failed;

}
r->card = card;
r->request = request;
r->data = payload;
Expand Down Expand Up @@ -902,9 +913,10 @@ static void iso_callback(struct fw_iso_context *context, u32 cycle,
struct iso_interrupt_event *e;

e = kmalloc(sizeof(*e) + header_length, GFP_ATOMIC);
if (e == NULL)
if (e == NULL) {
fw_notify("Out of memory when allocating event\n");
return;

}
e->interrupt.type = FW_CDEV_EVENT_ISO_INTERRUPT;
e->interrupt.closure = client->iso_closure;
e->interrupt.cycle = cycle;
Expand Down Expand Up @@ -1447,6 +1459,52 @@ static int ioctl_send_phy_packet(struct client *client, union ioctl_arg *arg)
return 0;
}

static int ioctl_receive_phy_packets(struct client *client, union ioctl_arg *arg)
{
struct fw_cdev_receive_phy_packets *a = &arg->receive_phy_packets;
struct fw_card *card = client->device->card;

/* Access policy: Allow this ioctl only on local nodes' device files. */
if (!client->device->is_local)
return -ENOSYS;

spin_lock_irq(&card->lock);

list_move_tail(&client->phy_receiver_link, &card->phy_receiver_list);
client->phy_receiver_closure = a->closure;

spin_unlock_irq(&card->lock);

return 0;
}

void fw_cdev_handle_phy_packet(struct fw_card *card, struct fw_packet *p)
{
struct client *client;
struct inbound_phy_packet_event *e;
unsigned long flags;

spin_lock_irqsave(&card->lock, flags);

list_for_each_entry(client, &card->phy_receiver_list, phy_receiver_link) {
e = kmalloc(sizeof(*e) + 8, GFP_ATOMIC);
if (e == NULL) {
fw_notify("Out of memory when allocating event\n");
break;
}
e->phy_packet.closure = client->phy_receiver_closure;
e->phy_packet.type = FW_CDEV_EVENT_PHY_PACKET_RECEIVED;
e->phy_packet.rcode = RCODE_COMPLETE;
e->phy_packet.length = 8;
e->phy_packet.data[0] = p->header[1];
e->phy_packet.data[1] = p->header[2];
queue_event(client, &e->event,
&e->phy_packet, sizeof(e->phy_packet) + 8, NULL, 0);
}

spin_unlock_irqrestore(&card->lock, flags);
}

static int (* const ioctl_handlers[])(struct client *, union ioctl_arg *) = {
[0x00] = ioctl_get_info,
[0x01] = ioctl_send_request,
Expand All @@ -1470,6 +1528,7 @@ static int (* const ioctl_handlers[])(struct client *, union ioctl_arg *) = {
[0x13] = ioctl_send_stream_packet,
[0x14] = ioctl_get_cycle_timer2,
[0x15] = ioctl_send_phy_packet,
[0x16] = ioctl_receive_phy_packets,
};

static int dispatch_ioctl(struct client *client,
Expand Down Expand Up @@ -1577,6 +1636,10 @@ static int fw_device_op_release(struct inode *inode, struct file *file)
struct client *client = file->private_data;
struct event *event, *next_event;

spin_lock_irq(&client->device->card->lock);
list_del(&client->phy_receiver_link);
spin_unlock_irq(&client->device->card->lock);

mutex_lock(&client->device->client_list_mutex);
list_del(&client->link);
mutex_unlock(&client->device->client_list_mutex);
Expand Down
5 changes: 5 additions & 0 deletions trunk/drivers/firewire/core-transaction.c
Original file line number Diff line number Diff line change
Expand Up @@ -883,6 +883,11 @@ void fw_core_handle_request(struct fw_card *card, struct fw_packet *p)
if (p->ack != ACK_PENDING && p->ack != ACK_COMPLETE)
return;

if (TCODE_IS_LINK_INTERNAL(HEADER_GET_TCODE(p->header[0]))) {
fw_cdev_handle_phy_packet(card, p);
return;
}

request = allocate_request(card, p);
if (request == NULL) {
/* FIXME: send statically allocated busy packet. */
Expand Down
2 changes: 2 additions & 0 deletions trunk/drivers/firewire/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ extern const struct file_operations fw_device_ops;

void fw_device_cdev_update(struct fw_device *device);
void fw_device_cdev_remove(struct fw_device *device);
void fw_cdev_handle_phy_packet(struct fw_card *card, struct fw_packet *p);


/* -device */
Expand Down Expand Up @@ -214,6 +215,7 @@ static inline bool is_next_generation(int new_generation, int old_generation)

#define TCODE_IS_READ_REQUEST(tcode) (((tcode) & ~1) == 4)
#define TCODE_IS_BLOCK_PACKET(tcode) (((tcode) & 1) != 0)
#define TCODE_IS_LINK_INTERNAL(tcode) ((tcode) == 0xe)
#define TCODE_IS_REQUEST(tcode) (((tcode) & 2) == 0)
#define TCODE_IS_RESPONSE(tcode) (((tcode) & 2) != 0)
#define TCODE_HAS_REQUEST_DATA(tcode) (((tcode) & 12) != 4)
Expand Down
3 changes: 1 addition & 2 deletions trunk/drivers/firewire/ohci.c
Original file line number Diff line number Diff line change
Expand Up @@ -1759,10 +1759,9 @@ static int ohci_enable(struct fw_card *card,
OHCI1394_HCControl_noByteSwapData);

reg_write(ohci, OHCI1394_SelfIDBuffer, ohci->self_id_bus);
reg_write(ohci, OHCI1394_LinkControlClear,
OHCI1394_LinkControl_rcvPhyPkt);
reg_write(ohci, OHCI1394_LinkControlSet,
OHCI1394_LinkControl_rcvSelfID |
OHCI1394_LinkControl_rcvPhyPkt |
OHCI1394_LinkControl_cycleTimerEnable |
OHCI1394_LinkControl_cycleMaster);

Expand Down
39 changes: 32 additions & 7 deletions trunk/include/linux/firewire-cdev.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
/* available since kernel version 2.6.36 */
#define FW_CDEV_EVENT_REQUEST2 0x06
#define FW_CDEV_EVENT_PHY_PACKET_SENT 0x07
#define FW_CDEV_EVENT_PHY_PACKET_RECEIVED 0x08

/**
* struct fw_cdev_event_common - Common part of all fw_cdev_event_ types
Expand Down Expand Up @@ -285,16 +286,24 @@ struct fw_cdev_event_iso_resource {
};

/**
* struct fw_cdev_event_phy_packet - A PHY packet was transmitted
* @closure: See &fw_cdev_event_common;
* set by %FW_CDEV_IOC_SEND_PHY_PACKET ioctl
* @type: %FW_CDEV_EVENT_PHY_PACKET_SENT
* struct fw_cdev_event_phy_packet - A PHY packet was transmitted or received
* @closure: See &fw_cdev_event_common; set by %FW_CDEV_IOC_SEND_PHY_PACKET
* or %FW_CDEV_IOC_RECEIVE_PHY_PACKETS ioctl
* @type: %FW_CDEV_EVENT_PHY_PACKET_SENT or %..._RECEIVED
* @rcode: %RCODE_..., indicates success or failure of transmission
* @length: Data length in bytes
* @data: Incoming data
*
* If @type is %FW_CDEV_EVENT_PHY_PACKET_SENT, @length is 0 and @data empty.
* If @type is %FW_CDEV_EVENT_PHY_PACKET_RECEIVED, @length is 8 and @data
* consists of the two PHY packet quadlets, in host byte order.
*/
struct fw_cdev_event_phy_packet {
__u64 closure;
__u32 type;
__u32 rcode;
__u32 length;
__u32 data[0];
};

/**
Expand All @@ -308,7 +317,9 @@ struct fw_cdev_event_phy_packet {
* @iso_resource: Valid if @common.type ==
* %FW_CDEV_EVENT_ISO_RESOURCE_ALLOCATED or
* %FW_CDEV_EVENT_ISO_RESOURCE_DEALLOCATED
* @phy_packet: Valid if @common.type == %FW_CDEV_EVENT_PHY_PACKET_SENT
* @phy_packet: Valid if @common.type ==
* %FW_CDEV_EVENT_PHY_PACKET_SENT or
* %FW_CDEV_EVENT_PHY_PACKET_RECEIVED
*
* Convenience union for userspace use. Events could be read(2) into an
* appropriately aligned char buffer and then cast to this union for further
Expand Down Expand Up @@ -360,6 +371,7 @@ union fw_cdev_event {

/* available since kernel version 2.6.36 */
#define FW_CDEV_IOC_SEND_PHY_PACKET _IOWR('#', 0x15, struct fw_cdev_send_phy_packet)
#define FW_CDEV_IOC_RECEIVE_PHY_PACKETS _IOW('#', 0x16, struct fw_cdev_receive_phy_packets)

/*
* ABI version history
Expand All @@ -376,9 +388,9 @@ union fw_cdev_event {
* - shared use and auto-response for FCP registers
* 3 (2.6.34) - made &fw_cdev_get_cycle_timer reliable
* - added %FW_CDEV_IOC_GET_CYCLE_TIMER2
* 4 (2.6.36) - added %FW_CDEV_EVENT_REQUEST2, %FW_CDEV_EVENT_PHY_PACKET_SENT
* 4 (2.6.36) - added %FW_CDEV_EVENT_REQUEST2, %FW_CDEV_EVENT_PHY_PACKET_*
* - implemented &fw_cdev_event_bus_reset.bm_node_id
* - added %FW_CDEV_IOC_SEND_PHY_PACKET
* - added %FW_CDEV_IOC_SEND_PHY_PACKET, _RECEIVE_PHY_PACKETS
*/
#define FW_CDEV_VERSION 3 /* Meaningless; don't use this macro. */

Expand Down Expand Up @@ -850,4 +862,17 @@ struct fw_cdev_send_phy_packet {
__u32 generation;
};

/**
* struct fw_cdev_receive_phy_packets - start reception of PHY packets
* @closure: Passed back to userspace in phy packet events
*
* This ioctl activates issuing of %FW_CDEV_EVENT_PHY_PACKET_RECEIVED due to
* incoming PHY packets from any node on the same bus as the device.
*
* The ioctl is only permitted on device files which represent a local node.
*/
struct fw_cdev_receive_phy_packets {
__u64 closure;
};

#endif /* _LINUX_FIREWIRE_CDEV_H */
3 changes: 2 additions & 1 deletion trunk/include/linux/firewire.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,10 @@ struct fw_card {
bool beta_repeaters_present;

int index;

struct list_head link;

struct list_head phy_receiver_list;

struct delayed_work br_work; /* bus reset job */
bool br_short;

Expand Down

0 comments on commit 29db891

Please sign in to comment.