diff options
author | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2010-07-29 12:19:22 -0400 |
---|---|---|
committer | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2010-07-29 17:09:18 -0400 |
commit | 872e330e38806d835bd6c311c93ab998e2fb9058 (patch) | |
tree | 92497ce79b1157761b1aebdb63b8d74f68d42c15 | |
parent | ae2a97661482c1d0f1aa41b837da95054d0e9a1b (diff) |
firewire: add isochronous multichannel reception
This adds the DMA context programming and userspace ABI for multichannel
reception, i.e. for listening on multiple channel numbers by means of a
single DMA context.
The use case is reception of more streams than there are IR DMA units
offered by the link layer. This is already implemented by the older
ohci1394 + ieee1394 + raw1394 stack. And as discussed recently on
linux1394-devel, this feature is occasionally used in practice.
The big drawbacks of this mode are that buffer layout and interrupt
generation necessarily differ from single-channel reception: Headers
and trailers are not stripped from packets, packets are not aligned with
buffer chunks, interrupts are per buffer chunk, not per packet.
These drawbacks also cause a rather hefty code footprint to support this
rarely used OHCI-1394 feature. (367 lines added, among them 94 lines of
added userspace ABI documentation.)
This implementation enforces that a multichannel reception context may
only listen to channels to which no single-channel context on the same
link layer is presently listening to. OHCI-1394 would allow to overlay
single-channel contexts by the multi-channel context, but this would be
a departure from the present first-come-first-served policy of IR
context creation.
The implementation is heavily based on an earlier one by Jay Fenlason.
Thanks Jay.
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
-rw-r--r-- | drivers/firewire/core-cdev.c | 93 | ||||
-rw-r--r-- | drivers/firewire/core-iso.c | 32 | ||||
-rw-r--r-- | drivers/firewire/core.h | 2 | ||||
-rw-r--r-- | drivers/firewire/ohci.c | 316 | ||||
-rw-r--r-- | include/linux/firewire-cdev.h | 281 | ||||
-rw-r--r-- | include/linux/firewire.h | 29 |
6 files changed, 560 insertions, 193 deletions
diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c index cf989e1635e1..ba23646bb108 100644 --- a/drivers/firewire/core-cdev.c +++ b/drivers/firewire/core-cdev.c | |||
@@ -193,6 +193,11 @@ struct iso_interrupt_event { | |||
193 | struct fw_cdev_event_iso_interrupt interrupt; | 193 | struct fw_cdev_event_iso_interrupt interrupt; |
194 | }; | 194 | }; |
195 | 195 | ||
196 | struct iso_interrupt_mc_event { | ||
197 | struct event event; | ||
198 | struct fw_cdev_event_iso_interrupt_mc interrupt; | ||
199 | }; | ||
200 | |||
196 | struct iso_resource_event { | 201 | struct iso_resource_event { |
197 | struct event event; | 202 | struct event event; |
198 | struct fw_cdev_event_iso_resource iso_resource; | 203 | struct fw_cdev_event_iso_resource iso_resource; |
@@ -415,6 +420,7 @@ union ioctl_arg { | |||
415 | struct fw_cdev_get_cycle_timer2 get_cycle_timer2; | 420 | struct fw_cdev_get_cycle_timer2 get_cycle_timer2; |
416 | struct fw_cdev_send_phy_packet send_phy_packet; | 421 | struct fw_cdev_send_phy_packet send_phy_packet; |
417 | struct fw_cdev_receive_phy_packets receive_phy_packets; | 422 | struct fw_cdev_receive_phy_packets receive_phy_packets; |
423 | struct fw_cdev_set_iso_channels set_iso_channels; | ||
418 | }; | 424 | }; |
419 | 425 | ||
420 | static int ioctl_get_info(struct client *client, union ioctl_arg *arg) | 426 | static int ioctl_get_info(struct client *client, union ioctl_arg *arg) |
@@ -932,26 +938,54 @@ static void iso_callback(struct fw_iso_context *context, u32 cycle, | |||
932 | sizeof(e->interrupt) + header_length, NULL, 0); | 938 | sizeof(e->interrupt) + header_length, NULL, 0); |
933 | } | 939 | } |
934 | 940 | ||
941 | static void iso_mc_callback(struct fw_iso_context *context, | ||
942 | dma_addr_t completed, void *data) | ||
943 | { | ||
944 | struct client *client = data; | ||
945 | struct iso_interrupt_mc_event *e; | ||
946 | |||
947 | e = kmalloc(sizeof(*e), GFP_ATOMIC); | ||
948 | if (e == NULL) { | ||
949 | fw_notify("Out of memory when allocating event\n"); | ||
950 | return; | ||
951 | } | ||
952 | e->interrupt.type = FW_CDEV_EVENT_ISO_INTERRUPT_MULTICHANNEL; | ||
953 | e->interrupt.closure = client->iso_closure; | ||
954 | e->interrupt.completed = fw_iso_buffer_lookup(&client->buffer, | ||
955 | completed); | ||
956 | queue_event(client, &e->event, &e->interrupt, | ||
957 | sizeof(e->interrupt), NULL, 0); | ||
958 | } | ||
959 | |||
935 | static int ioctl_create_iso_context(struct client *client, union ioctl_arg *arg) | 960 | static int ioctl_create_iso_context(struct client *client, union ioctl_arg *arg) |
936 | { | 961 | { |
937 | struct fw_cdev_create_iso_context *a = &arg->create_iso_context; | 962 | struct fw_cdev_create_iso_context *a = &arg->create_iso_context; |
938 | struct fw_iso_context *context; | 963 | struct fw_iso_context *context; |
964 | fw_iso_callback_t cb; | ||
939 | 965 | ||
940 | BUILD_BUG_ON(FW_CDEV_ISO_CONTEXT_TRANSMIT != FW_ISO_CONTEXT_TRANSMIT || | 966 | BUILD_BUG_ON(FW_CDEV_ISO_CONTEXT_TRANSMIT != FW_ISO_CONTEXT_TRANSMIT || |
941 | FW_CDEV_ISO_CONTEXT_RECEIVE != FW_ISO_CONTEXT_RECEIVE); | 967 | FW_CDEV_ISO_CONTEXT_RECEIVE != FW_ISO_CONTEXT_RECEIVE || |
942 | 968 | FW_CDEV_ISO_CONTEXT_RECEIVE_MULTICHANNEL != | |
943 | if (a->channel > 63) | 969 | FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL); |
944 | return -EINVAL; | ||
945 | 970 | ||
946 | switch (a->type) { | 971 | switch (a->type) { |
947 | case FW_ISO_CONTEXT_RECEIVE: | 972 | case FW_ISO_CONTEXT_TRANSMIT: |
948 | if (a->header_size < 4 || (a->header_size & 3)) | 973 | if (a->speed > SCODE_3200 || a->channel > 63) |
949 | return -EINVAL; | 974 | return -EINVAL; |
975 | |||
976 | cb = iso_callback; | ||
950 | break; | 977 | break; |
951 | 978 | ||
952 | case FW_ISO_CONTEXT_TRANSMIT: | 979 | case FW_ISO_CONTEXT_RECEIVE: |
953 | if (a->speed > SCODE_3200) | 980 | if (a->header_size < 4 || (a->header_size & 3) || |
981 | a->channel > 63) | ||
954 | return -EINVAL; | 982 | return -EINVAL; |
983 | |||
984 | cb = iso_callback; | ||
985 | break; | ||
986 | |||
987 | case FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL: | ||
988 | cb = (fw_iso_callback_t)iso_mc_callback; | ||
955 | break; | 989 | break; |
956 | 990 | ||
957 | default: | 991 | default: |
@@ -959,8 +993,7 @@ static int ioctl_create_iso_context(struct client *client, union ioctl_arg *arg) | |||
959 | } | 993 | } |
960 | 994 | ||
961 | context = fw_iso_context_create(client->device->card, a->type, | 995 | context = fw_iso_context_create(client->device->card, a->type, |
962 | a->channel, a->speed, a->header_size, | 996 | a->channel, a->speed, a->header_size, cb, client); |
963 | iso_callback, client); | ||
964 | if (IS_ERR(context)) | 997 | if (IS_ERR(context)) |
965 | return PTR_ERR(context); | 998 | return PTR_ERR(context); |
966 | 999 | ||
@@ -980,6 +1013,17 @@ static int ioctl_create_iso_context(struct client *client, union ioctl_arg *arg) | |||
980 | return 0; | 1013 | return 0; |
981 | } | 1014 | } |
982 | 1015 | ||
1016 | static int ioctl_set_iso_channels(struct client *client, union ioctl_arg *arg) | ||
1017 | { | ||
1018 | struct fw_cdev_set_iso_channels *a = &arg->set_iso_channels; | ||
1019 | struct fw_iso_context *ctx = client->iso_context; | ||
1020 | |||
1021 | if (ctx == NULL || a->handle != 0) | ||
1022 | return -EINVAL; | ||
1023 | |||
1024 | return fw_iso_context_set_channels(ctx, &a->channels); | ||
1025 | } | ||
1026 | |||
983 | /* Macros for decoding the iso packet control header. */ | 1027 | /* Macros for decoding the iso packet control header. */ |
984 | #define GET_PAYLOAD_LENGTH(v) ((v) & 0xffff) | 1028 | #define GET_PAYLOAD_LENGTH(v) ((v) & 0xffff) |
985 | #define GET_INTERRUPT(v) (((v) >> 16) & 0x01) | 1029 | #define GET_INTERRUPT(v) (((v) >> 16) & 0x01) |
@@ -993,7 +1037,7 @@ static int ioctl_queue_iso(struct client *client, union ioctl_arg *arg) | |||
993 | struct fw_cdev_queue_iso *a = &arg->queue_iso; | 1037 | struct fw_cdev_queue_iso *a = &arg->queue_iso; |
994 | struct fw_cdev_iso_packet __user *p, *end, *next; | 1038 | struct fw_cdev_iso_packet __user *p, *end, *next; |
995 | struct fw_iso_context *ctx = client->iso_context; | 1039 | struct fw_iso_context *ctx = client->iso_context; |
996 | unsigned long payload, buffer_end, transmit_header_bytes; | 1040 | unsigned long payload, buffer_end, transmit_header_bytes = 0; |
997 | u32 control; | 1041 | u32 control; |
998 | int count; | 1042 | int count; |
999 | struct { | 1043 | struct { |
@@ -1013,7 +1057,6 @@ static int ioctl_queue_iso(struct client *client, union ioctl_arg *arg) | |||
1013 | * use the indirect payload, the iso buffer need not be mapped | 1057 | * use the indirect payload, the iso buffer need not be mapped |
1014 | * and the a->data pointer is ignored. | 1058 | * and the a->data pointer is ignored. |
1015 | */ | 1059 | */ |
1016 | |||
1017 | payload = (unsigned long)a->data - client->vm_start; | 1060 | payload = (unsigned long)a->data - client->vm_start; |
1018 | buffer_end = client->buffer.page_count << PAGE_SHIFT; | 1061 | buffer_end = client->buffer.page_count << PAGE_SHIFT; |
1019 | if (a->data == 0 || client->buffer.pages == NULL || | 1062 | if (a->data == 0 || client->buffer.pages == NULL || |
@@ -1022,8 +1065,10 @@ static int ioctl_queue_iso(struct client *client, union ioctl_arg *arg) | |||
1022 | buffer_end = 0; | 1065 | buffer_end = 0; |
1023 | } | 1066 | } |
1024 | 1067 | ||
1025 | p = (struct fw_cdev_iso_packet __user *)u64_to_uptr(a->packets); | 1068 | if (ctx->type == FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL && payload & 3) |
1069 | return -EINVAL; | ||
1026 | 1070 | ||
1071 | p = (struct fw_cdev_iso_packet __user *)u64_to_uptr(a->packets); | ||
1027 | if (!access_ok(VERIFY_READ, p, a->size)) | 1072 | if (!access_ok(VERIFY_READ, p, a->size)) |
1028 | return -EFAULT; | 1073 | return -EFAULT; |
1029 | 1074 | ||
@@ -1039,19 +1084,24 @@ static int ioctl_queue_iso(struct client *client, union ioctl_arg *arg) | |||
1039 | u.packet.sy = GET_SY(control); | 1084 | u.packet.sy = GET_SY(control); |
1040 | u.packet.header_length = GET_HEADER_LENGTH(control); | 1085 | u.packet.header_length = GET_HEADER_LENGTH(control); |
1041 | 1086 | ||
1042 | if (ctx->type == FW_ISO_CONTEXT_TRANSMIT) { | 1087 | switch (ctx->type) { |
1043 | if (u.packet.header_length % 4 != 0) | 1088 | case FW_ISO_CONTEXT_TRANSMIT: |
1089 | if (u.packet.header_length & 3) | ||
1044 | return -EINVAL; | 1090 | return -EINVAL; |
1045 | transmit_header_bytes = u.packet.header_length; | 1091 | transmit_header_bytes = u.packet.header_length; |
1046 | } else { | 1092 | break; |
1047 | /* | 1093 | |
1048 | * We require that header_length is a multiple of | 1094 | case FW_ISO_CONTEXT_RECEIVE: |
1049 | * the fixed header size, ctx->header_size. | ||
1050 | */ | ||
1051 | if (u.packet.header_length == 0 || | 1095 | if (u.packet.header_length == 0 || |
1052 | u.packet.header_length % ctx->header_size != 0) | 1096 | u.packet.header_length % ctx->header_size != 0) |
1053 | return -EINVAL; | 1097 | return -EINVAL; |
1054 | transmit_header_bytes = 0; | 1098 | break; |
1099 | |||
1100 | case FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL: | ||
1101 | if (u.packet.payload_length == 0 || | ||
1102 | u.packet.payload_length & 3) | ||
1103 | return -EINVAL; | ||
1104 | break; | ||
1055 | } | 1105 | } |
1056 | 1106 | ||
1057 | next = (struct fw_cdev_iso_packet __user *) | 1107 | next = (struct fw_cdev_iso_packet __user *) |
@@ -1534,6 +1584,7 @@ static int (* const ioctl_handlers[])(struct client *, union ioctl_arg *) = { | |||
1534 | [0x14] = ioctl_get_cycle_timer2, | 1584 | [0x14] = ioctl_get_cycle_timer2, |
1535 | [0x15] = ioctl_send_phy_packet, | 1585 | [0x15] = ioctl_send_phy_packet, |
1536 | [0x16] = ioctl_receive_phy_packets, | 1586 | [0x16] = ioctl_receive_phy_packets, |
1587 | [0x17] = ioctl_set_iso_channels, | ||
1537 | }; | 1588 | }; |
1538 | 1589 | ||
1539 | static int dispatch_ioctl(struct client *client, | 1590 | static int dispatch_ioctl(struct client *client, |
diff --git a/drivers/firewire/core-iso.c b/drivers/firewire/core-iso.c index 4fe932e60fb8..0c8e662a5daf 100644 --- a/drivers/firewire/core-iso.c +++ b/drivers/firewire/core-iso.c | |||
@@ -117,6 +117,23 @@ void fw_iso_buffer_destroy(struct fw_iso_buffer *buffer, | |||
117 | } | 117 | } |
118 | EXPORT_SYMBOL(fw_iso_buffer_destroy); | 118 | EXPORT_SYMBOL(fw_iso_buffer_destroy); |
119 | 119 | ||
120 | /* Convert DMA address to offset into virtually contiguous buffer. */ | ||
121 | size_t fw_iso_buffer_lookup(struct fw_iso_buffer *buffer, dma_addr_t completed) | ||
122 | { | ||
123 | int i; | ||
124 | dma_addr_t address; | ||
125 | ssize_t offset; | ||
126 | |||
127 | for (i = 0; i < buffer->page_count; i++) { | ||
128 | address = page_private(buffer->pages[i]); | ||
129 | offset = (ssize_t)completed - (ssize_t)address; | ||
130 | if (offset > 0 && offset <= PAGE_SIZE) | ||
131 | return (i << PAGE_SHIFT) + offset; | ||
132 | } | ||
133 | |||
134 | return 0; | ||
135 | } | ||
136 | |||
120 | struct fw_iso_context *fw_iso_context_create(struct fw_card *card, | 137 | struct fw_iso_context *fw_iso_context_create(struct fw_card *card, |
121 | int type, int channel, int speed, size_t header_size, | 138 | int type, int channel, int speed, size_t header_size, |
122 | fw_iso_callback_t callback, void *callback_data) | 139 | fw_iso_callback_t callback, void *callback_data) |
@@ -133,7 +150,7 @@ struct fw_iso_context *fw_iso_context_create(struct fw_card *card, | |||
133 | ctx->channel = channel; | 150 | ctx->channel = channel; |
134 | ctx->speed = speed; | 151 | ctx->speed = speed; |
135 | ctx->header_size = header_size; | 152 | ctx->header_size = header_size; |
136 | ctx->callback = callback; | 153 | ctx->callback.sc = callback; |
137 | ctx->callback_data = callback_data; | 154 | ctx->callback_data = callback_data; |
138 | 155 | ||
139 | return ctx; | 156 | return ctx; |
@@ -142,9 +159,7 @@ EXPORT_SYMBOL(fw_iso_context_create); | |||
142 | 159 | ||
143 | void fw_iso_context_destroy(struct fw_iso_context *ctx) | 160 | void fw_iso_context_destroy(struct fw_iso_context *ctx) |
144 | { | 161 | { |
145 | struct fw_card *card = ctx->card; | 162 | ctx->card->driver->free_iso_context(ctx); |
146 | |||
147 | card->driver->free_iso_context(ctx); | ||
148 | } | 163 | } |
149 | EXPORT_SYMBOL(fw_iso_context_destroy); | 164 | EXPORT_SYMBOL(fw_iso_context_destroy); |
150 | 165 | ||
@@ -155,14 +170,17 @@ int fw_iso_context_start(struct fw_iso_context *ctx, | |||
155 | } | 170 | } |
156 | EXPORT_SYMBOL(fw_iso_context_start); | 171 | EXPORT_SYMBOL(fw_iso_context_start); |
157 | 172 | ||
173 | int fw_iso_context_set_channels(struct fw_iso_context *ctx, u64 *channels) | ||
174 | { | ||
175 | return ctx->card->driver->set_iso_channels(ctx, channels); | ||
176 | } | ||
177 | |||
158 | int fw_iso_context_queue(struct fw_iso_context *ctx, | 178 | int fw_iso_context_queue(struct fw_iso_context *ctx, |
159 | struct fw_iso_packet *packet, | 179 | struct fw_iso_packet *packet, |
160 | struct fw_iso_buffer *buffer, | 180 | struct fw_iso_buffer *buffer, |
161 | unsigned long payload) | 181 | unsigned long payload) |
162 | { | 182 | { |
163 | struct fw_card *card = ctx->card; | 183 | return ctx->card->driver->queue_iso(ctx, packet, buffer, payload); |
164 | |||
165 | return card->driver->queue_iso(ctx, packet, buffer, payload); | ||
166 | } | 184 | } |
167 | EXPORT_SYMBOL(fw_iso_context_queue); | 185 | EXPORT_SYMBOL(fw_iso_context_queue); |
168 | 186 | ||
diff --git a/drivers/firewire/core.h b/drivers/firewire/core.h index 28621e44b111..e6239f971be6 100644 --- a/drivers/firewire/core.h +++ b/drivers/firewire/core.h | |||
@@ -90,6 +90,8 @@ struct fw_card_driver { | |||
90 | int (*start_iso)(struct fw_iso_context *ctx, | 90 | int (*start_iso)(struct fw_iso_context *ctx, |
91 | s32 cycle, u32 sync, u32 tags); | 91 | s32 cycle, u32 sync, u32 tags); |
92 | 92 | ||
93 | int (*set_iso_channels)(struct fw_iso_context *ctx, u64 *channels); | ||
94 | |||
93 | int (*queue_iso)(struct fw_iso_context *ctx, | 95 | int (*queue_iso)(struct fw_iso_context *ctx, |
94 | struct fw_iso_packet *packet, | 96 | struct fw_iso_packet *packet, |
95 | struct fw_iso_buffer *buffer, | 97 | struct fw_iso_buffer *buffer, |
diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index 2e4b425847a7..4bda1c1b74ba 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c | |||
@@ -190,11 +190,13 @@ struct fw_ohci { | |||
190 | struct context at_request_ctx; | 190 | struct context at_request_ctx; |
191 | struct context at_response_ctx; | 191 | struct context at_response_ctx; |
192 | 192 | ||
193 | u32 it_context_mask; | 193 | u32 it_context_mask; /* unoccupied IT contexts */ |
194 | struct iso_context *it_context_list; | 194 | struct iso_context *it_context_list; |
195 | u64 ir_context_channels; | 195 | u64 ir_context_channels; /* unoccupied channels */ |
196 | u32 ir_context_mask; | 196 | u32 ir_context_mask; /* unoccupied IR contexts */ |
197 | struct iso_context *ir_context_list; | 197 | struct iso_context *ir_context_list; |
198 | u64 mc_channels; /* channels in use by the multichannel IR context */ | ||
199 | bool mc_allocated; | ||
198 | 200 | ||
199 | __be32 *config_rom; | 201 | __be32 *config_rom; |
200 | dma_addr_t config_rom_bus; | 202 | dma_addr_t config_rom_bus; |
@@ -2197,10 +2199,9 @@ static int handle_ir_packet_per_buffer(struct context *context, | |||
2197 | __le32 *ir_header; | 2199 | __le32 *ir_header; |
2198 | void *p; | 2200 | void *p; |
2199 | 2201 | ||
2200 | for (pd = d; pd <= last; pd++) { | 2202 | for (pd = d; pd <= last; pd++) |
2201 | if (pd->transfer_status) | 2203 | if (pd->transfer_status) |
2202 | break; | 2204 | break; |
2203 | } | ||
2204 | if (pd > last) | 2205 | if (pd > last) |
2205 | /* Descriptor(s) not done yet, stop iteration */ | 2206 | /* Descriptor(s) not done yet, stop iteration */ |
2206 | return 0; | 2207 | return 0; |
@@ -2210,16 +2211,38 @@ static int handle_ir_packet_per_buffer(struct context *context, | |||
2210 | 2211 | ||
2211 | if (le16_to_cpu(last->control) & DESCRIPTOR_IRQ_ALWAYS) { | 2212 | if (le16_to_cpu(last->control) & DESCRIPTOR_IRQ_ALWAYS) { |
2212 | ir_header = (__le32 *) p; | 2213 | ir_header = (__le32 *) p; |
2213 | ctx->base.callback(&ctx->base, | 2214 | ctx->base.callback.sc(&ctx->base, |
2214 | le32_to_cpu(ir_header[0]) & 0xffff, | 2215 | le32_to_cpu(ir_header[0]) & 0xffff, |
2215 | ctx->header_length, ctx->header, | 2216 | ctx->header_length, ctx->header, |
2216 | ctx->base.callback_data); | 2217 | ctx->base.callback_data); |
2217 | ctx->header_length = 0; | 2218 | ctx->header_length = 0; |
2218 | } | 2219 | } |
2219 | 2220 | ||
2220 | return 1; | 2221 | return 1; |
2221 | } | 2222 | } |
2222 | 2223 | ||
2224 | /* d == last because each descriptor block is only a single descriptor. */ | ||
2225 | static int handle_ir_buffer_fill(struct context *context, | ||
2226 | struct descriptor *d, | ||
2227 | struct descriptor *last) | ||
2228 | { | ||
2229 | struct iso_context *ctx = | ||
2230 | container_of(context, struct iso_context, context); | ||
2231 | |||
2232 | if (!last->transfer_status) | ||
2233 | /* Descriptor(s) not done yet, stop iteration */ | ||
2234 | return 0; | ||
2235 | |||
2236 | if (le16_to_cpu(last->control) & DESCRIPTOR_IRQ_ALWAYS) | ||
2237 | ctx->base.callback.mc(&ctx->base, | ||
2238 | le32_to_cpu(last->data_address) + | ||
2239 | le16_to_cpu(last->req_count) - | ||
2240 | le16_to_cpu(last->res_count), | ||
2241 | ctx->base.callback_data); | ||
2242 | |||
2243 | return 1; | ||
2244 | } | ||
2245 | |||
2223 | static int handle_it_packet(struct context *context, | 2246 | static int handle_it_packet(struct context *context, |
2224 | struct descriptor *d, | 2247 | struct descriptor *d, |
2225 | struct descriptor *last) | 2248 | struct descriptor *last) |
@@ -2245,72 +2268,118 @@ static int handle_it_packet(struct context *context, | |||
2245 | ctx->header_length += 4; | 2268 | ctx->header_length += 4; |
2246 | } | 2269 | } |
2247 | if (le16_to_cpu(last->control) & DESCRIPTOR_IRQ_ALWAYS) { | 2270 | if (le16_to_cpu(last->control) & DESCRIPTOR_IRQ_ALWAYS) { |
2248 | ctx->base.callback(&ctx->base, le16_to_cpu(last->res_count), | 2271 | ctx->base.callback.sc(&ctx->base, le16_to_cpu(last->res_count), |
2249 | ctx->header_length, ctx->header, | 2272 | ctx->header_length, ctx->header, |
2250 | ctx->base.callback_data); | 2273 | ctx->base.callback_data); |
2251 | ctx->header_length = 0; | 2274 | ctx->header_length = 0; |
2252 | } | 2275 | } |
2253 | return 1; | 2276 | return 1; |
2254 | } | 2277 | } |
2255 | 2278 | ||
2279 | static void set_multichannel_mask(struct fw_ohci *ohci, u64 channels) | ||
2280 | { | ||
2281 | u32 hi = channels >> 32, lo = channels; | ||
2282 | |||
2283 | reg_write(ohci, OHCI1394_IRMultiChanMaskHiClear, ~hi); | ||
2284 | reg_write(ohci, OHCI1394_IRMultiChanMaskLoClear, ~lo); | ||
2285 | reg_write(ohci, OHCI1394_IRMultiChanMaskHiSet, hi); | ||
2286 | reg_write(ohci, OHCI1394_IRMultiChanMaskLoSet, lo); | ||
2287 | mmiowb(); | ||
2288 | ohci->mc_channels = channels; | ||
2289 | } | ||
2290 | |||
2256 | static struct fw_iso_context *ohci_allocate_iso_context(struct fw_card *card, | 2291 | static struct fw_iso_context *ohci_allocate_iso_context(struct fw_card *card, |
2257 | int type, int channel, size_t header_size) | 2292 | int type, int channel, size_t header_size) |
2258 | { | 2293 | { |
2259 | struct fw_ohci *ohci = fw_ohci(card); | 2294 | struct fw_ohci *ohci = fw_ohci(card); |
2260 | struct iso_context *ctx, *list; | 2295 | struct iso_context *uninitialized_var(ctx); |
2261 | descriptor_callback_t callback; | 2296 | descriptor_callback_t uninitialized_var(callback); |
2262 | u64 *channels, dont_care = ~0ULL; | 2297 | u64 *uninitialized_var(channels); |
2263 | u32 *mask, regs; | 2298 | u32 *uninitialized_var(mask), uninitialized_var(regs); |
2264 | unsigned long flags; | 2299 | unsigned long flags; |
2265 | int index, ret = -ENOMEM; | 2300 | int index, ret = -EBUSY; |
2266 | 2301 | ||
2267 | if (type == FW_ISO_CONTEXT_TRANSMIT) { | 2302 | spin_lock_irqsave(&ohci->lock, flags); |
2268 | channels = &dont_care; | 2303 | |
2269 | mask = &ohci->it_context_mask; | 2304 | switch (type) { |
2270 | list = ohci->it_context_list; | 2305 | case FW_ISO_CONTEXT_TRANSMIT: |
2306 | mask = &ohci->it_context_mask; | ||
2271 | callback = handle_it_packet; | 2307 | callback = handle_it_packet; |
2272 | } else { | 2308 | index = ffs(*mask) - 1; |
2309 | if (index >= 0) { | ||
2310 | *mask &= ~(1 << index); | ||
2311 | regs = OHCI1394_IsoXmitContextBase(index); | ||
2312 | ctx = &ohci->it_context_list[index]; | ||
2313 | } | ||
2314 | break; | ||
2315 | |||
2316 | case FW_ISO_CONTEXT_RECEIVE: | ||
2273 | channels = &ohci->ir_context_channels; | 2317 | channels = &ohci->ir_context_channels; |
2274 | mask = &ohci->ir_context_mask; | 2318 | mask = &ohci->ir_context_mask; |
2275 | list = ohci->ir_context_list; | ||
2276 | callback = handle_ir_packet_per_buffer; | 2319 | callback = handle_ir_packet_per_buffer; |
2277 | } | 2320 | index = *channels & 1ULL << channel ? ffs(*mask) - 1 : -1; |
2321 | if (index >= 0) { | ||
2322 | *channels &= ~(1ULL << channel); | ||
2323 | *mask &= ~(1 << index); | ||
2324 | regs = OHCI1394_IsoRcvContextBase(index); | ||
2325 | ctx = &ohci->ir_context_list[index]; | ||
2326 | } | ||
2327 | break; | ||
2278 | 2328 | ||
2279 | spin_lock_irqsave(&ohci->lock, flags); | 2329 | case FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL: |
2280 | index = *channels & 1ULL << channel ? ffs(*mask) - 1 : -1; | 2330 | mask = &ohci->ir_context_mask; |
2281 | if (index >= 0) { | 2331 | callback = handle_ir_buffer_fill; |
2282 | *channels &= ~(1ULL << channel); | 2332 | index = !ohci->mc_allocated ? ffs(*mask) - 1 : -1; |
2283 | *mask &= ~(1 << index); | 2333 | if (index >= 0) { |
2334 | ohci->mc_allocated = true; | ||
2335 | *mask &= ~(1 << index); | ||
2336 | regs = OHCI1394_IsoRcvContextBase(index); | ||
2337 | ctx = &ohci->ir_context_list[index]; | ||
2338 | } | ||
2339 | break; | ||
2340 | |||
2341 | default: | ||
2342 | index = -1; | ||
2343 | ret = -ENOSYS; | ||
2284 | } | 2344 | } |
2345 | |||
2285 | spin_unlock_irqrestore(&ohci->lock, flags); | 2346 | spin_unlock_irqrestore(&ohci->lock, flags); |
2286 | 2347 | ||
2287 | if (index < 0) | 2348 | if (index < 0) |
2288 | return ERR_PTR(-EBUSY); | 2349 | return ERR_PTR(ret); |
2289 | |||
2290 | if (type == FW_ISO_CONTEXT_TRANSMIT) | ||
2291 | regs = OHCI1394_IsoXmitContextBase(index); | ||
2292 | else | ||
2293 | regs = OHCI1394_IsoRcvContextBase(index); | ||
2294 | 2350 | ||
2295 | ctx = &list[index]; | ||
2296 | memset(ctx, 0, sizeof(*ctx)); | 2351 | memset(ctx, 0, sizeof(*ctx)); |
2297 | ctx->header_length = 0; | 2352 | ctx->header_length = 0; |
2298 | ctx->header = (void *) __get_free_page(GFP_KERNEL); | 2353 | ctx->header = (void *) __get_free_page(GFP_KERNEL); |
2299 | if (ctx->header == NULL) | 2354 | if (ctx->header == NULL) { |
2355 | ret = -ENOMEM; | ||
2300 | goto out; | 2356 | goto out; |
2301 | 2357 | } | |
2302 | ret = context_init(&ctx->context, ohci, regs, callback); | 2358 | ret = context_init(&ctx->context, ohci, regs, callback); |
2303 | if (ret < 0) | 2359 | if (ret < 0) |
2304 | goto out_with_header; | 2360 | goto out_with_header; |
2305 | 2361 | ||
2362 | if (type == FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL) | ||
2363 | set_multichannel_mask(ohci, 0); | ||
2364 | |||
2306 | return &ctx->base; | 2365 | return &ctx->base; |
2307 | 2366 | ||
2308 | out_with_header: | 2367 | out_with_header: |
2309 | free_page((unsigned long)ctx->header); | 2368 | free_page((unsigned long)ctx->header); |
2310 | out: | 2369 | out: |
2311 | spin_lock_irqsave(&ohci->lock, flags); | 2370 | spin_lock_irqsave(&ohci->lock, flags); |
2312 | *channels |= 1ULL << channel; | 2371 | |
2372 | switch (type) { | ||
2373 | case FW_ISO_CONTEXT_RECEIVE: | ||
2374 | *channels |= 1ULL << channel; | ||
2375 | break; | ||
2376 | |||
2377 | case FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL: | ||
2378 | ohci->mc_allocated = false; | ||
2379 | break; | ||
2380 | } | ||
2313 | *mask |= 1 << index; | 2381 | *mask |= 1 << index; |
2382 | |||
2314 | spin_unlock_irqrestore(&ohci->lock, flags); | 2383 | spin_unlock_irqrestore(&ohci->lock, flags); |
2315 | 2384 | ||
2316 | return ERR_PTR(ret); | 2385 | return ERR_PTR(ret); |
@@ -2321,10 +2390,11 @@ static int ohci_start_iso(struct fw_iso_context *base, | |||
2321 | { | 2390 | { |
2322 | struct iso_context *ctx = container_of(base, struct iso_context, base); | 2391 | struct iso_context *ctx = container_of(base, struct iso_context, base); |
2323 | struct fw_ohci *ohci = ctx->context.ohci; | 2392 | struct fw_ohci *ohci = ctx->context.ohci; |
2324 | u32 control, match; | 2393 | u32 control = IR_CONTEXT_ISOCH_HEADER, match; |
2325 | int index; | 2394 | int index; |
2326 | 2395 | ||
2327 | if (ctx->base.type == FW_ISO_CONTEXT_TRANSMIT) { | 2396 | switch (ctx->base.type) { |
2397 | case FW_ISO_CONTEXT_TRANSMIT: | ||
2328 | index = ctx - ohci->it_context_list; | 2398 | index = ctx - ohci->it_context_list; |
2329 | match = 0; | 2399 | match = 0; |
2330 | if (cycle >= 0) | 2400 | if (cycle >= 0) |
@@ -2334,9 +2404,13 @@ static int ohci_start_iso(struct fw_iso_context *base, | |||
2334 | reg_write(ohci, OHCI1394_IsoXmitIntEventClear, 1 << index); | 2404 | reg_write(ohci, OHCI1394_IsoXmitIntEventClear, 1 << index); |
2335 | reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, 1 << index); | 2405 | reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, 1 << index); |
2336 | context_run(&ctx->context, match); | 2406 | context_run(&ctx->context, match); |
2337 | } else { | 2407 | break; |
2408 | |||
2409 | case FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL: | ||
2410 | control |= IR_CONTEXT_BUFFER_FILL|IR_CONTEXT_MULTI_CHANNEL_MODE; | ||
2411 | /* fall through */ | ||
2412 | case FW_ISO_CONTEXT_RECEIVE: | ||
2338 | index = ctx - ohci->ir_context_list; | 2413 | index = ctx - ohci->ir_context_list; |
2339 | control = IR_CONTEXT_ISOCH_HEADER; | ||
2340 | match = (tags << 28) | (sync << 8) | ctx->base.channel; | 2414 | match = (tags << 28) | (sync << 8) | ctx->base.channel; |
2341 | if (cycle >= 0) { | 2415 | if (cycle >= 0) { |
2342 | match |= (cycle & 0x07fff) << 12; | 2416 | match |= (cycle & 0x07fff) << 12; |
@@ -2347,6 +2421,7 @@ static int ohci_start_iso(struct fw_iso_context *base, | |||
2347 | reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 1 << index); | 2421 | reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 1 << index); |
2348 | reg_write(ohci, CONTEXT_MATCH(ctx->context.regs), match); | 2422 | reg_write(ohci, CONTEXT_MATCH(ctx->context.regs), match); |
2349 | context_run(&ctx->context, control); | 2423 | context_run(&ctx->context, control); |
2424 | break; | ||
2350 | } | 2425 | } |
2351 | 2426 | ||
2352 | return 0; | 2427 | return 0; |
@@ -2358,12 +2433,17 @@ static int ohci_stop_iso(struct fw_iso_context *base) | |||
2358 | struct iso_context *ctx = container_of(base, struct iso_context, base); | 2433 | struct iso_context *ctx = container_of(base, struct iso_context, base); |
2359 | int index; | 2434 | int index; |
2360 | 2435 | ||
2361 | if (ctx->base.type == FW_ISO_CONTEXT_TRANSMIT) { | 2436 | switch (ctx->base.type) { |
2437 | case FW_ISO_CONTEXT_TRANSMIT: | ||
2362 | index = ctx - ohci->it_context_list; | 2438 | index = ctx - ohci->it_context_list; |
2363 | reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, 1 << index); | 2439 | reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, 1 << index); |
2364 | } else { | 2440 | break; |
2441 | |||
2442 | case FW_ISO_CONTEXT_RECEIVE: | ||
2443 | case FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL: | ||
2365 | index = ctx - ohci->ir_context_list; | 2444 | index = ctx - ohci->ir_context_list; |
2366 | reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 1 << index); | 2445 | reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 1 << index); |
2446 | break; | ||
2367 | } | 2447 | } |
2368 | flush_writes(ohci); | 2448 | flush_writes(ohci); |
2369 | context_stop(&ctx->context); | 2449 | context_stop(&ctx->context); |
@@ -2384,24 +2464,65 @@ static void ohci_free_iso_context(struct fw_iso_context *base) | |||
2384 | 2464 | ||
2385 | spin_lock_irqsave(&ohci->lock, flags); | 2465 | spin_lock_irqsave(&ohci->lock, flags); |
2386 | 2466 | ||
2387 | if (ctx->base.type == FW_ISO_CONTEXT_TRANSMIT) { | 2467 | switch (base->type) { |
2468 | case FW_ISO_CONTEXT_TRANSMIT: | ||
2388 | index = ctx - ohci->it_context_list; | 2469 | index = ctx - ohci->it_context_list; |
2389 | ohci->it_context_mask |= 1 << index; | 2470 | ohci->it_context_mask |= 1 << index; |
2390 | } else { | 2471 | break; |
2472 | |||
2473 | case FW_ISO_CONTEXT_RECEIVE: | ||
2391 | index = ctx - ohci->ir_context_list; | 2474 | index = ctx - ohci->ir_context_list; |
2392 | ohci->ir_context_mask |= 1 << index; | 2475 | ohci->ir_context_mask |= 1 << index; |
2393 | ohci->ir_context_channels |= 1ULL << base->channel; | 2476 | ohci->ir_context_channels |= 1ULL << base->channel; |
2477 | break; | ||
2478 | |||
2479 | case FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL: | ||
2480 | index = ctx - ohci->ir_context_list; | ||
2481 | ohci->ir_context_mask |= 1 << index; | ||
2482 | ohci->ir_context_channels |= ohci->mc_channels; | ||
2483 | ohci->mc_channels = 0; | ||
2484 | ohci->mc_allocated = false; | ||
2485 | break; | ||
2394 | } | 2486 | } |
2395 | 2487 | ||
2396 | spin_unlock_irqrestore(&ohci->lock, flags); | 2488 | spin_unlock_irqrestore(&ohci->lock, flags); |
2397 | } | 2489 | } |
2398 | 2490 | ||
2399 | static int ohci_queue_iso_transmit(struct fw_iso_context *base, | 2491 | static int ohci_set_iso_channels(struct fw_iso_context *base, u64 *channels) |
2400 | struct fw_iso_packet *packet, | 2492 | { |
2401 | struct fw_iso_buffer *buffer, | 2493 | struct fw_ohci *ohci = fw_ohci(base->card); |
2402 | unsigned long payload) | 2494 | unsigned long flags; |
2495 | int ret; | ||
2496 | |||
2497 | switch (base->type) { | ||
2498 | case FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL: | ||
2499 | |||
2500 | spin_lock_irqsave(&ohci->lock, flags); | ||
2501 | |||
2502 | /* Don't allow multichannel to grab other contexts' channels. */ | ||
2503 | if (~ohci->ir_context_channels & ~ohci->mc_channels & *channels) { | ||
2504 | *channels = ohci->ir_context_channels; | ||
2505 | ret = -EBUSY; | ||
2506 | } else { | ||
2507 | set_multichannel_mask(ohci, *channels); | ||
2508 | ret = 0; | ||
2509 | } | ||
2510 | |||
2511 | spin_unlock_irqrestore(&ohci->lock, flags); | ||
2512 | |||
2513 | break; | ||
2514 | default: | ||
2515 | ret = -EINVAL; | ||
2516 | } | ||
2517 | |||
2518 | return ret; | ||
2519 | } | ||
2520 | |||
2521 | static int queue_iso_transmit(struct iso_context *ctx, | ||
2522 | struct fw_iso_packet *packet, | ||
2523 | struct fw_iso_buffer *buffer, | ||
2524 | unsigned long payload) | ||
2403 | { | 2525 | { |
2404 | struct iso_context *ctx = container_of(base, struct iso_context, base); | ||
2405 | struct descriptor *d, *last, *pd; | 2526 | struct descriptor *d, *last, *pd; |
2406 | struct fw_iso_packet *p; | 2527 | struct fw_iso_packet *p; |
2407 | __le32 *header; | 2528 | __le32 *header; |
@@ -2497,14 +2618,12 @@ static int ohci_queue_iso_transmit(struct fw_iso_context *base, | |||
2497 | return 0; | 2618 | return 0; |
2498 | } | 2619 | } |
2499 | 2620 | ||
2500 | static int ohci_queue_iso_receive_packet_per_buffer(struct fw_iso_context *base, | 2621 | static int queue_iso_packet_per_buffer(struct iso_context *ctx, |
2501 | struct fw_iso_packet *packet, | 2622 | struct fw_iso_packet *packet, |
2502 | struct fw_iso_buffer *buffer, | 2623 | struct fw_iso_buffer *buffer, |
2503 | unsigned long payload) | 2624 | unsigned long payload) |
2504 | { | 2625 | { |
2505 | struct iso_context *ctx = container_of(base, struct iso_context, base); | ||
2506 | struct descriptor *d, *pd; | 2626 | struct descriptor *d, *pd; |
2507 | struct fw_iso_packet *p = packet; | ||
2508 | dma_addr_t d_bus, page_bus; | 2627 | dma_addr_t d_bus, page_bus; |
2509 | u32 z, header_z, rest; | 2628 | u32 z, header_z, rest; |
2510 | int i, j, length; | 2629 | int i, j, length; |
@@ -2514,14 +2633,14 @@ static int ohci_queue_iso_receive_packet_per_buffer(struct fw_iso_context *base, | |||
2514 | * The OHCI controller puts the isochronous header and trailer in the | 2633 | * The OHCI controller puts the isochronous header and trailer in the |
2515 | * buffer, so we need at least 8 bytes. | 2634 | * buffer, so we need at least 8 bytes. |
2516 | */ | 2635 | */ |
2517 | packet_count = p->header_length / ctx->base.header_size; | 2636 | packet_count = packet->header_length / ctx->base.header_size; |
2518 | header_size = max(ctx->base.header_size, (size_t)8); | 2637 | header_size = max(ctx->base.header_size, (size_t)8); |
2519 | 2638 | ||
2520 | /* Get header size in number of descriptors. */ | 2639 | /* Get header size in number of descriptors. */ |
2521 | header_z = DIV_ROUND_UP(header_size, sizeof(*d)); | 2640 | header_z = DIV_ROUND_UP(header_size, sizeof(*d)); |
2522 | page = payload >> PAGE_SHIFT; | 2641 | page = payload >> PAGE_SHIFT; |
2523 | offset = payload & ~PAGE_MASK; | 2642 | offset = payload & ~PAGE_MASK; |
2524 | payload_per_buffer = p->payload_length / packet_count; | 2643 | payload_per_buffer = packet->payload_length / packet_count; |
2525 | 2644 | ||
2526 | for (i = 0; i < packet_count; i++) { | 2645 | for (i = 0; i < packet_count; i++) { |
2527 | /* d points to the header descriptor */ | 2646 | /* d points to the header descriptor */ |
@@ -2533,7 +2652,7 @@ static int ohci_queue_iso_receive_packet_per_buffer(struct fw_iso_context *base, | |||
2533 | 2652 | ||
2534 | d->control = cpu_to_le16(DESCRIPTOR_STATUS | | 2653 | d->control = cpu_to_le16(DESCRIPTOR_STATUS | |
2535 | DESCRIPTOR_INPUT_MORE); | 2654 | DESCRIPTOR_INPUT_MORE); |
2536 | if (p->skip && i == 0) | 2655 | if (packet->skip && i == 0) |
2537 | d->control |= cpu_to_le16(DESCRIPTOR_WAIT); | 2656 | d->control |= cpu_to_le16(DESCRIPTOR_WAIT); |
2538 | d->req_count = cpu_to_le16(header_size); | 2657 | d->req_count = cpu_to_le16(header_size); |
2539 | d->res_count = d->req_count; | 2658 | d->res_count = d->req_count; |
@@ -2566,7 +2685,7 @@ static int ohci_queue_iso_receive_packet_per_buffer(struct fw_iso_context *base, | |||
2566 | pd->control = cpu_to_le16(DESCRIPTOR_STATUS | | 2685 | pd->control = cpu_to_le16(DESCRIPTOR_STATUS | |
2567 | DESCRIPTOR_INPUT_LAST | | 2686 | DESCRIPTOR_INPUT_LAST | |
2568 | DESCRIPTOR_BRANCH_ALWAYS); | 2687 | DESCRIPTOR_BRANCH_ALWAYS); |
2569 | if (p->interrupt && i == packet_count - 1) | 2688 | if (packet->interrupt && i == packet_count - 1) |
2570 | pd->control |= cpu_to_le16(DESCRIPTOR_IRQ_ALWAYS); | 2689 | pd->control |= cpu_to_le16(DESCRIPTOR_IRQ_ALWAYS); |
2571 | 2690 | ||
2572 | context_append(&ctx->context, d, z, header_z); | 2691 | context_append(&ctx->context, d, z, header_z); |
@@ -2575,6 +2694,58 @@ static int ohci_queue_iso_receive_packet_per_buffer(struct fw_iso_context *base, | |||
2575 | return 0; | 2694 | return 0; |
2576 | } | 2695 | } |
2577 | 2696 | ||
2697 | static int queue_iso_buffer_fill(struct iso_context *ctx, | ||
2698 | struct fw_iso_packet *packet, | ||
2699 | struct fw_iso_buffer *buffer, | ||
2700 | unsigned long payload) | ||
2701 | { | ||
2702 | struct descriptor *d; | ||
2703 | dma_addr_t d_bus, page_bus; | ||
2704 | int page, offset, rest, z, i, length; | ||
2705 | |||
2706 | page = payload >> PAGE_SHIFT; | ||
2707 | offset = payload & ~PAGE_MASK; | ||
2708 | rest = packet->payload_length; | ||
2709 | |||
2710 | /* We need one descriptor for each page in the buffer. */ | ||
2711 | z = DIV_ROUND_UP(offset + rest, PAGE_SIZE); | ||
2712 | |||
2713 | if (WARN_ON(offset & 3 || rest & 3 || page + z > buffer->page_count)) | ||
2714 | return -EFAULT; | ||
2715 | |||
2716 | for (i = 0; i < z; i++) { | ||
2717 | d = context_get_descriptors(&ctx->context, 1, &d_bus); | ||
2718 | if (d == NULL) | ||
2719 | return -ENOMEM; | ||
2720 | |||
2721 | d->control = cpu_to_le16(DESCRIPTOR_INPUT_MORE | | ||
2722 | DESCRIPTOR_BRANCH_ALWAYS); | ||
2723 | if (packet->skip && i == 0) | ||
2724 | d->control |= cpu_to_le16(DESCRIPTOR_WAIT); | ||
2725 | if (packet->interrupt && i == z - 1) | ||
2726 | d->control |= cpu_to_le16(DESCRIPTOR_IRQ_ALWAYS); | ||
2727 | |||
2728 | if (offset + rest < PAGE_SIZE) | ||
2729 | length = rest; | ||
2730 | else | ||
2731 | length = PAGE_SIZE - offset; | ||
2732 | d->req_count = cpu_to_le16(length); | ||
2733 | d->res_count = d->req_count; | ||
2734 | d->transfer_status = 0; | ||
2735 | |||
2736 | page_bus = page_private(buffer->pages[page]); | ||
2737 | d->data_address = cpu_to_le32(page_bus + offset); | ||
2738 | |||
2739 | rest -= length; | ||
2740 | offset = 0; | ||
2741 | page++; | ||
2742 | |||
2743 | context_append(&ctx->context, d, 1, 0); | ||
2744 | } | ||
2745 | |||
2746 | return 0; | ||
2747 | } | ||
2748 | |||
2578 | static int ohci_queue_iso(struct fw_iso_context *base, | 2749 | static int ohci_queue_iso(struct fw_iso_context *base, |
2579 | struct fw_iso_packet *packet, | 2750 | struct fw_iso_packet *packet, |
2580 | struct fw_iso_buffer *buffer, | 2751 | struct fw_iso_buffer *buffer, |
@@ -2582,14 +2753,20 @@ static int ohci_queue_iso(struct fw_iso_context *base, | |||
2582 | { | 2753 | { |
2583 | struct iso_context *ctx = container_of(base, struct iso_context, base); | 2754 | struct iso_context *ctx = container_of(base, struct iso_context, base); |
2584 | unsigned long flags; | 2755 | unsigned long flags; |
2585 | int ret; | 2756 | int ret = -ENOSYS; |
2586 | 2757 | ||
2587 | spin_lock_irqsave(&ctx->context.ohci->lock, flags); | 2758 | spin_lock_irqsave(&ctx->context.ohci->lock, flags); |
2588 | if (base->type == FW_ISO_CONTEXT_TRANSMIT) | 2759 | switch (base->type) { |
2589 | ret = ohci_queue_iso_transmit(base, packet, buffer, payload); | 2760 | case FW_ISO_CONTEXT_TRANSMIT: |
2590 | else | 2761 | ret = queue_iso_transmit(ctx, packet, buffer, payload); |
2591 | ret = ohci_queue_iso_receive_packet_per_buffer(base, packet, | 2762 | break; |
2592 | buffer, payload); | 2763 | case FW_ISO_CONTEXT_RECEIVE: |
2764 | ret = queue_iso_packet_per_buffer(ctx, packet, buffer, payload); | ||
2765 | break; | ||
2766 | case FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL: | ||
2767 | ret = queue_iso_buffer_fill(ctx, packet, buffer, payload); | ||
2768 | break; | ||
2769 | } | ||
2593 | spin_unlock_irqrestore(&ctx->context.ohci->lock, flags); | 2770 | spin_unlock_irqrestore(&ctx->context.ohci->lock, flags); |
2594 | 2771 | ||
2595 | return ret; | 2772 | return ret; |
@@ -2609,6 +2786,7 @@ static const struct fw_card_driver ohci_driver = { | |||
2609 | 2786 | ||
2610 | .allocate_iso_context = ohci_allocate_iso_context, | 2787 | .allocate_iso_context = ohci_allocate_iso_context, |
2611 | .free_iso_context = ohci_free_iso_context, | 2788 | .free_iso_context = ohci_free_iso_context, |
2789 | .set_iso_channels = ohci_set_iso_channels, | ||
2612 | .queue_iso = ohci_queue_iso, | 2790 | .queue_iso = ohci_queue_iso, |
2613 | .start_iso = ohci_start_iso, | 2791 | .start_iso = ohci_start_iso, |
2614 | .stop_iso = ohci_stop_iso, | 2792 | .stop_iso = ohci_stop_iso, |
diff --git a/include/linux/firewire-cdev.h b/include/linux/firewire-cdev.h index 14831119ff71..bc5c26fc1c64 100644 --- a/include/linux/firewire-cdev.h +++ b/include/linux/firewire-cdev.h | |||
@@ -25,17 +25,18 @@ | |||
25 | #include <linux/types.h> | 25 | #include <linux/types.h> |
26 | #include <linux/firewire-constants.h> | 26 | #include <linux/firewire-constants.h> |
27 | 27 | ||
28 | #define FW_CDEV_EVENT_BUS_RESET 0x00 | 28 | #define FW_CDEV_EVENT_BUS_RESET 0x00 |
29 | #define FW_CDEV_EVENT_RESPONSE 0x01 | 29 | #define FW_CDEV_EVENT_RESPONSE 0x01 |
30 | #define FW_CDEV_EVENT_REQUEST 0x02 | 30 | #define FW_CDEV_EVENT_REQUEST 0x02 |
31 | #define FW_CDEV_EVENT_ISO_INTERRUPT 0x03 | 31 | #define FW_CDEV_EVENT_ISO_INTERRUPT 0x03 |
32 | #define FW_CDEV_EVENT_ISO_RESOURCE_ALLOCATED 0x04 | 32 | #define FW_CDEV_EVENT_ISO_RESOURCE_ALLOCATED 0x04 |
33 | #define FW_CDEV_EVENT_ISO_RESOURCE_DEALLOCATED 0x05 | 33 | #define FW_CDEV_EVENT_ISO_RESOURCE_DEALLOCATED 0x05 |
34 | 34 | ||
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 | #define FW_CDEV_EVENT_PHY_PACKET_RECEIVED 0x08 |
39 | #define FW_CDEV_EVENT_ISO_INTERRUPT_MULTICHANNEL 0x09 | ||
39 | 40 | ||
40 | /** | 41 | /** |
41 | * struct fw_cdev_event_common - Common part of all fw_cdev_event_ types | 42 | * struct fw_cdev_event_common - Common part of all fw_cdev_event_ types |
@@ -218,35 +219,41 @@ struct fw_cdev_event_request2 { | |||
218 | * This event is sent when the controller has completed an &fw_cdev_iso_packet | 219 | * This event is sent when the controller has completed an &fw_cdev_iso_packet |
219 | * with the %FW_CDEV_ISO_INTERRUPT bit set. | 220 | * with the %FW_CDEV_ISO_INTERRUPT bit set. |
220 | * | 221 | * |
221 | * Isochronous transmit events: | 222 | * Isochronous transmit events (context type %FW_CDEV_ISO_CONTEXT_TRANSMIT): |
222 | * | 223 | * |
223 | * In version 1 of the ABI, &header_length is 0. In version 3 and some | 224 | * In version 3 and some implementations of version 2 of the ABI, &header_length |
224 | * implementations of version 2 of the ABI, &header_length is a multiple of 4 | 225 | * is a multiple of 4 and &header contains timestamps of all packets up until |
225 | * and &header contains timestamps of all packets up until the interrupt packet. | 226 | * the interrupt packet. The format of the timestamps is as described below for |
226 | * The format of the timestamps is as described below for isochronous reception. | 227 | * isochronous reception. In version 1 of the ABI, &header_length was 0. |
227 | * | 228 | * |
228 | * Isochronous receive events: | 229 | * Isochronous receive events (context type %FW_CDEV_ISO_CONTEXT_RECEIVE): |
229 | * | 230 | * |
230 | * The headers stripped of all packets up until and including the interrupt | 231 | * The headers stripped of all packets up until and including the interrupt |
231 | * packet are returned in the @header field. The amount of header data per | 232 | * packet are returned in the @header field. The amount of header data per |
232 | * packet is as specified at iso context creation by | 233 | * packet is as specified at iso context creation by |
233 | * &fw_cdev_create_iso_context.header_size. | 234 | * &fw_cdev_create_iso_context.header_size. |
234 | * | 235 | * |
235 | * In version 1 of this ABI, header data consisted of the 1394 isochronous | 236 | * Hence, _interrupt.header_length / _context.header_size is the number of |
236 | * packet header, followed by quadlets from the packet payload if | 237 | * packets received in this interrupt event. The client can now iterate |
237 | * &fw_cdev_create_iso_context.header_size > 4. | 238 | * through the mmap()'ed DMA buffer according to this number of packets and |
239 | * to the buffer sizes as the client specified in &fw_cdev_queue_iso. | ||
238 | * | 240 | * |
239 | * In version 2 of this ABI, header data consist of the 1394 isochronous | 241 | * Since version 2 of this ABI, the portion for each packet in _interrupt.header |
240 | * packet header, followed by a timestamp quadlet if | 242 | * consists of the 1394 isochronous packet header, followed by a timestamp |
241 | * &fw_cdev_create_iso_context.header_size > 4, followed by quadlets from the | 243 | * quadlet if &fw_cdev_create_iso_context.header_size > 4, followed by quadlets |
242 | * packet payload if &fw_cdev_create_iso_context.header_size > 8. | 244 | * from the packet payload if &fw_cdev_create_iso_context.header_size > 8. |
243 | * | 245 | * |
244 | * Behaviour of ver. 1 of this ABI is no longer available since ABI ver. 2. | 246 | * Format of 1394 iso packet header: 16 bits data_length, 2 bits tag, 6 bits |
247 | * channel, 4 bits tcode, 4 bits sy, in big endian byte order. | ||
248 | * data_length is the actual received size of the packet without the four | ||
249 | * 1394 iso packet header bytes. | ||
250 | * | ||
251 | * Format of timestamp: 16 bits invalid, 3 bits cycleSeconds, 13 bits | ||
252 | * cycleCount, in big endian byte order. | ||
245 | * | 253 | * |
246 | * Format of 1394 iso packet header: 16 bits len, 2 bits tag, 6 bits channel, | 254 | * In version 1 of the ABI, no timestamp quadlet was inserted; instead, payload |
247 | * 4 bits tcode, 4 bits sy, in big endian byte order. Format of timestamp: | 255 | * data followed directly after the 1394 is header if header_size > 4. |
248 | * 16 bits invalid, 3 bits cycleSeconds, 13 bits cycleCount, in big endian byte | 256 | * Behaviour of ver. 1 of this ABI is no longer available since ABI ver. 2. |
249 | * order. | ||
250 | */ | 257 | */ |
251 | struct fw_cdev_event_iso_interrupt { | 258 | struct fw_cdev_event_iso_interrupt { |
252 | __u64 closure; | 259 | __u64 closure; |
@@ -257,6 +264,43 @@ struct fw_cdev_event_iso_interrupt { | |||
257 | }; | 264 | }; |
258 | 265 | ||
259 | /** | 266 | /** |
267 | * struct fw_cdev_event_iso_interrupt_mc - An iso buffer chunk was completed | ||
268 | * @closure: See &fw_cdev_event_common; | ||
269 | * set by %FW_CDEV_CREATE_ISO_CONTEXT ioctl | ||
270 | * @type: %FW_CDEV_EVENT_ISO_INTERRUPT_MULTICHANNEL | ||
271 | * @completed: Offset into the receive buffer; data before this offest is valid | ||
272 | * | ||
273 | * This event is sent in multichannel contexts (context type | ||
274 | * %FW_CDEV_ISO_CONTEXT_RECEIVE_MULTICHANNEL) for &fw_cdev_iso_packet buffer | ||
275 | * chunks that have the %FW_CDEV_ISO_INTERRUPT bit set. Whether this happens | ||
276 | * when a packet is completed and/or when a buffer chunk is completed depends | ||
277 | * on the hardware implementation. | ||
278 | * | ||
279 | * The buffer is continuously filled with the following data, per packet: | ||
280 | * - the 1394 iso packet header as described at &fw_cdev_event_iso_interrupt, | ||
281 | * but in little endian byte order, | ||
282 | * - packet payload (as many bytes as specified in the data_length field of | ||
283 | * the 1394 iso packet header) in big endian byte order, | ||
284 | * - 0...3 padding bytes as needed to align the following trailer quadlet, | ||
285 | * - trailer quadlet, containing the reception timestamp as described at | ||
286 | * &fw_cdev_event_iso_interrupt, but in little endian byte order. | ||
287 | * | ||
288 | * Hence the per-packet size is data_length (rounded up to a multiple of 4) + 8. | ||
289 | * When processing the data, stop before a packet that would cross the | ||
290 | * @completed offset. | ||
291 | * | ||
292 | * A packet near the end of a buffer chunk will typically spill over into the | ||
293 | * next queued buffer chunk. It is the responsibility of the client to check | ||
294 | * for this condition, assemble a broken-up packet from its parts, and not to | ||
295 | * re-queue any buffer chunks in which as yet unread packet parts reside. | ||
296 | */ | ||
297 | struct fw_cdev_event_iso_interrupt_mc { | ||
298 | __u64 closure; | ||
299 | __u32 type; | ||
300 | __u32 completed; | ||
301 | }; | ||
302 | |||
303 | /** | ||
260 | * struct fw_cdev_event_iso_resource - Iso resources were allocated or freed | 304 | * struct fw_cdev_event_iso_resource - Iso resources were allocated or freed |
261 | * @closure: See &fw_cdev_event_common; | 305 | * @closure: See &fw_cdev_event_common; |
262 | * set by %FW_CDEV_IOC_(DE)ALLOCATE_ISO_RESOURCE(_ONCE) ioctl | 306 | * set by %FW_CDEV_IOC_(DE)ALLOCATE_ISO_RESOURCE(_ONCE) ioctl |
@@ -311,16 +355,18 @@ struct fw_cdev_event_phy_packet { | |||
311 | 355 | ||
312 | /** | 356 | /** |
313 | * union fw_cdev_event - Convenience union of fw_cdev_event_ types | 357 | * union fw_cdev_event - Convenience union of fw_cdev_event_ types |
314 | * @common: Valid for all types | 358 | * @common: Valid for all types |
315 | * @bus_reset: Valid if @common.type == %FW_CDEV_EVENT_BUS_RESET | 359 | * @bus_reset: Valid if @common.type == %FW_CDEV_EVENT_BUS_RESET |
316 | * @response: Valid if @common.type == %FW_CDEV_EVENT_RESPONSE | 360 | * @response: Valid if @common.type == %FW_CDEV_EVENT_RESPONSE |
317 | * @request: Valid if @common.type == %FW_CDEV_EVENT_REQUEST | 361 | * @request: Valid if @common.type == %FW_CDEV_EVENT_REQUEST |
318 | * @request2: Valid if @common.type == %FW_CDEV_EVENT_REQUEST2 | 362 | * @request2: Valid if @common.type == %FW_CDEV_EVENT_REQUEST2 |
319 | * @iso_interrupt: Valid if @common.type == %FW_CDEV_EVENT_ISO_INTERRUPT | 363 | * @iso_interrupt: Valid if @common.type == %FW_CDEV_EVENT_ISO_INTERRUPT |
320 | * @iso_resource: Valid if @common.type == | 364 | * @iso_interrupt_mc: Valid if @common.type == |
365 | * %FW_CDEV_EVENT_ISO_INTERRUPT_MULTICHANNEL | ||
366 | * @iso_resource: Valid if @common.type == | ||
321 | * %FW_CDEV_EVENT_ISO_RESOURCE_ALLOCATED or | 367 | * %FW_CDEV_EVENT_ISO_RESOURCE_ALLOCATED or |
322 | * %FW_CDEV_EVENT_ISO_RESOURCE_DEALLOCATED | 368 | * %FW_CDEV_EVENT_ISO_RESOURCE_DEALLOCATED |
323 | * @phy_packet: Valid if @common.type == | 369 | * @phy_packet: Valid if @common.type == |
324 | * %FW_CDEV_EVENT_PHY_PACKET_SENT or | 370 | * %FW_CDEV_EVENT_PHY_PACKET_SENT or |
325 | * %FW_CDEV_EVENT_PHY_PACKET_RECEIVED | 371 | * %FW_CDEV_EVENT_PHY_PACKET_RECEIVED |
326 | * | 372 | * |
@@ -337,10 +383,11 @@ union fw_cdev_event { | |||
337 | struct fw_cdev_event_bus_reset bus_reset; | 383 | struct fw_cdev_event_bus_reset bus_reset; |
338 | struct fw_cdev_event_response response; | 384 | struct fw_cdev_event_response response; |
339 | struct fw_cdev_event_request request; | 385 | struct fw_cdev_event_request request; |
340 | struct fw_cdev_event_request2 request2; /* added in 2.6.36 */ | 386 | struct fw_cdev_event_request2 request2; /* added in 2.6.36 */ |
341 | struct fw_cdev_event_iso_interrupt iso_interrupt; | 387 | struct fw_cdev_event_iso_interrupt iso_interrupt; |
342 | struct fw_cdev_event_iso_resource iso_resource; /* added in 2.6.30 */ | 388 | struct fw_cdev_event_iso_interrupt_mc iso_interrupt_mc; /* added in 2.6.36 */ |
343 | struct fw_cdev_event_phy_packet phy_packet; /* added in 2.6.36 */ | 389 | struct fw_cdev_event_iso_resource iso_resource; /* added in 2.6.30 */ |
390 | struct fw_cdev_event_phy_packet phy_packet; /* added in 2.6.36 */ | ||
344 | }; | 391 | }; |
345 | 392 | ||
346 | /* available since kernel version 2.6.22 */ | 393 | /* available since kernel version 2.6.22 */ |
@@ -375,6 +422,7 @@ union fw_cdev_event { | |||
375 | /* available since kernel version 2.6.36 */ | 422 | /* available since kernel version 2.6.36 */ |
376 | #define FW_CDEV_IOC_SEND_PHY_PACKET _IOWR('#', 0x15, struct fw_cdev_send_phy_packet) | 423 | #define FW_CDEV_IOC_SEND_PHY_PACKET _IOWR('#', 0x15, struct fw_cdev_send_phy_packet) |
377 | #define FW_CDEV_IOC_RECEIVE_PHY_PACKETS _IOW('#', 0x16, struct fw_cdev_receive_phy_packets) | 424 | #define FW_CDEV_IOC_RECEIVE_PHY_PACKETS _IOW('#', 0x16, struct fw_cdev_receive_phy_packets) |
425 | #define FW_CDEV_IOC_SET_ISO_CHANNELS _IOW('#', 0x17, struct fw_cdev_set_iso_channels) | ||
378 | 426 | ||
379 | /* | 427 | /* |
380 | * ABI version history | 428 | * ABI version history |
@@ -391,10 +439,13 @@ union fw_cdev_event { | |||
391 | * - shared use and auto-response for FCP registers | 439 | * - shared use and auto-response for FCP registers |
392 | * 3 (2.6.34) - made &fw_cdev_get_cycle_timer reliable | 440 | * 3 (2.6.34) - made &fw_cdev_get_cycle_timer reliable |
393 | * - added %FW_CDEV_IOC_GET_CYCLE_TIMER2 | 441 | * - added %FW_CDEV_IOC_GET_CYCLE_TIMER2 |
394 | * 4 (2.6.36) - added %FW_CDEV_EVENT_REQUEST2, %FW_CDEV_EVENT_PHY_PACKET_* | 442 | * 4 (2.6.36) - added %FW_CDEV_EVENT_REQUEST2, %FW_CDEV_EVENT_PHY_PACKET_*, |
443 | * and &fw_cdev_allocate.region_end | ||
395 | * - implemented &fw_cdev_event_bus_reset.bm_node_id | 444 | * - implemented &fw_cdev_event_bus_reset.bm_node_id |
396 | * - added %FW_CDEV_IOC_SEND_PHY_PACKET, _RECEIVE_PHY_PACKETS | 445 | * - added %FW_CDEV_IOC_SEND_PHY_PACKET, _RECEIVE_PHY_PACKETS |
397 | * - added &fw_cdev_allocate.region_end | 446 | * - added %FW_CDEV_EVENT_ISO_INTERRUPT_MULTICHANNEL, |
447 | * %FW_CDEV_ISO_CONTEXT_RECEIVE_MULTICHANNEL, and | ||
448 | * %FW_CDEV_IOC_SET_ISO_CHANNELS | ||
398 | */ | 449 | */ |
399 | #define FW_CDEV_VERSION 3 /* Meaningless; don't use this macro. */ | 450 | #define FW_CDEV_VERSION 3 /* Meaningless; don't use this macro. */ |
400 | 451 | ||
@@ -597,34 +648,43 @@ struct fw_cdev_remove_descriptor { | |||
597 | __u32 handle; | 648 | __u32 handle; |
598 | }; | 649 | }; |
599 | 650 | ||
600 | #define FW_CDEV_ISO_CONTEXT_TRANSMIT 0 | 651 | #define FW_CDEV_ISO_CONTEXT_TRANSMIT 0 |
601 | #define FW_CDEV_ISO_CONTEXT_RECEIVE 1 | 652 | #define FW_CDEV_ISO_CONTEXT_RECEIVE 1 |
653 | #define FW_CDEV_ISO_CONTEXT_RECEIVE_MULTICHANNEL 2 /* added in 2.6.36 */ | ||
602 | 654 | ||
603 | /** | 655 | /** |
604 | * struct fw_cdev_create_iso_context - Create a context for isochronous IO | 656 | * struct fw_cdev_create_iso_context - Create a context for isochronous I/O |
605 | * @type: %FW_CDEV_ISO_CONTEXT_TRANSMIT or %FW_CDEV_ISO_CONTEXT_RECEIVE | 657 | * @type: %FW_CDEV_ISO_CONTEXT_TRANSMIT or %FW_CDEV_ISO_CONTEXT_RECEIVE or |
606 | * @header_size: Header size to strip for receive contexts | 658 | * %FW_CDEV_ISO_CONTEXT_RECEIVE_MULTICHANNEL |
607 | * @channel: Channel to bind to | 659 | * @header_size: Header size to strip in single-channel reception |
608 | * @speed: Speed for transmit contexts | 660 | * @channel: Channel to bind to in single-channel reception or transmission |
609 | * @closure: To be returned in &fw_cdev_event_iso_interrupt | 661 | * @speed: Transmission speed |
662 | * @closure: To be returned in &fw_cdev_event_iso_interrupt or | ||
663 | * &fw_cdev_event_iso_interrupt_multichannel | ||
610 | * @handle: Handle to context, written back by kernel | 664 | * @handle: Handle to context, written back by kernel |
611 | * | 665 | * |
612 | * Prior to sending or receiving isochronous I/O, a context must be created. | 666 | * Prior to sending or receiving isochronous I/O, a context must be created. |
613 | * The context records information about the transmit or receive configuration | 667 | * The context records information about the transmit or receive configuration |
614 | * and typically maps to an underlying hardware resource. A context is set up | 668 | * and typically maps to an underlying hardware resource. A context is set up |
615 | * for either sending or receiving. It is bound to a specific isochronous | 669 | * for either sending or receiving. It is bound to a specific isochronous |
616 | * channel. | 670 | * @channel. |
617 | * | 671 | * |
618 | * If a context was successfully created, the kernel writes back a handle to the | 672 | * In case of multichannel reception, @header_size and @channel are ignored |
619 | * context, which must be passed in for subsequent operations on that context. | 673 | * and the channels are selected by %FW_CDEV_IOC_SET_ISO_CHANNELS. |
674 | * | ||
675 | * For %FW_CDEV_ISO_CONTEXT_RECEIVE contexts, @header_size must be at least 4 | ||
676 | * and must be a multiple of 4. It is ignored in other context types. | ||
620 | * | 677 | * |
621 | * For receive contexts, @header_size must be at least 4 and must be a multiple | 678 | * @speed is ignored in receive context types. |
622 | * of 4. | ||
623 | * | 679 | * |
624 | * Note that the effect of a @header_size > 4 depends on | 680 | * If a context was successfully created, the kernel writes back a handle to the |
625 | * &fw_cdev_get_info.version, as documented at &fw_cdev_event_iso_interrupt. | 681 | * context, which must be passed in for subsequent operations on that context. |
626 | * | 682 | * |
683 | * Limitations: | ||
627 | * No more than one iso context can be created per fd. | 684 | * No more than one iso context can be created per fd. |
685 | * The total number of contexts that all userspace and kernelspace drivers can | ||
686 | * create on a card at a time is a hardware limit, typically 4 or 8 contexts per | ||
687 | * direction, and of them at most one multichannel receive context. | ||
628 | */ | 688 | */ |
629 | struct fw_cdev_create_iso_context { | 689 | struct fw_cdev_create_iso_context { |
630 | __u32 type; | 690 | __u32 type; |
@@ -635,6 +695,22 @@ struct fw_cdev_create_iso_context { | |||
635 | __u32 handle; | 695 | __u32 handle; |
636 | }; | 696 | }; |
637 | 697 | ||
698 | /** | ||
699 | * struct fw_cdev_set_iso_channels - Select channels in multichannel reception | ||
700 | * @channels: Bitmask of channels to listen to | ||
701 | * @handle: Handle of the mutichannel receive context | ||
702 | * | ||
703 | * @channels is the bitwise or of 1ULL << n for each channel n to listen to. | ||
704 | * | ||
705 | * The ioctl fails with errno %EBUSY if there is already another receive context | ||
706 | * on a channel in @channels. In that case, the bitmask of all unoccupied | ||
707 | * channels is returned in @channels. | ||
708 | */ | ||
709 | struct fw_cdev_set_iso_channels { | ||
710 | __u64 channels; | ||
711 | __u32 handle; | ||
712 | }; | ||
713 | |||
638 | #define FW_CDEV_ISO_PAYLOAD_LENGTH(v) (v) | 714 | #define FW_CDEV_ISO_PAYLOAD_LENGTH(v) (v) |
639 | #define FW_CDEV_ISO_INTERRUPT (1 << 16) | 715 | #define FW_CDEV_ISO_INTERRUPT (1 << 16) |
640 | #define FW_CDEV_ISO_SKIP (1 << 17) | 716 | #define FW_CDEV_ISO_SKIP (1 << 17) |
@@ -645,42 +721,72 @@ struct fw_cdev_create_iso_context { | |||
645 | 721 | ||
646 | /** | 722 | /** |
647 | * struct fw_cdev_iso_packet - Isochronous packet | 723 | * struct fw_cdev_iso_packet - Isochronous packet |
648 | * @control: Contains the header length (8 uppermost bits), the sy field | 724 | * @control: Contains the header length (8 uppermost bits), |
649 | * (4 bits), the tag field (2 bits), a sync flag (1 bit), | 725 | * the sy field (4 bits), the tag field (2 bits), a sync flag |
650 | * a skip flag (1 bit), an interrupt flag (1 bit), and the | 726 | * or a skip flag (1 bit), an interrupt flag (1 bit), and the |
651 | * payload length (16 lowermost bits) | 727 | * payload length (16 lowermost bits) |
652 | * @header: Header and payload | 728 | * @header: Header and payload in case of a transmit context. |
653 | * | 729 | * |
654 | * &struct fw_cdev_iso_packet is used to describe isochronous packet queues. | 730 | * &struct fw_cdev_iso_packet is used to describe isochronous packet queues. |
655 | * | ||
656 | * Use the FW_CDEV_ISO_ macros to fill in @control. | 731 | * Use the FW_CDEV_ISO_ macros to fill in @control. |
732 | * The @header array is empty in case of receive contexts. | ||
733 | * | ||
734 | * Context type %FW_CDEV_ISO_CONTEXT_TRANSMIT: | ||
735 | * | ||
736 | * @control.HEADER_LENGTH must be a multiple of 4. It specifies the numbers of | ||
737 | * bytes in @header that will be prepended to the packet's payload. These bytes | ||
738 | * are copied into the kernel and will not be accessed after the ioctl has | ||
739 | * returned. | ||
740 | * | ||
741 | * The @control.SY and TAG fields are copied to the iso packet header. These | ||
742 | * fields are specified by IEEE 1394a and IEC 61883-1. | ||
743 | * | ||
744 | * The @control.SKIP flag specifies that no packet is to be sent in a frame. | ||
745 | * When using this, all other fields except @control.INTERRUPT must be zero. | ||
746 | * | ||
747 | * When a packet with the @control.INTERRUPT flag set has been completed, an | ||
748 | * &fw_cdev_event_iso_interrupt event will be sent. | ||
749 | * | ||
750 | * Context type %FW_CDEV_ISO_CONTEXT_RECEIVE: | ||
657 | * | 751 | * |
658 | * For transmit packets, the header length must be a multiple of 4 and specifies | 752 | * @control.HEADER_LENGTH must be a multiple of the context's header_size. |
659 | * the numbers of bytes in @header that will be prepended to the packet's | 753 | * If the HEADER_LENGTH is larger than the context's header_size, multiple |
660 | * payload; these bytes are copied into the kernel and will not be accessed | 754 | * packets are queued for this entry. |
661 | * after the ioctl has returned. The sy and tag fields are copied to the iso | 755 | * |
662 | * packet header (these fields are specified by IEEE 1394a and IEC 61883-1). | 756 | * The @control.SY and TAG fields are ignored. |
663 | * The skip flag specifies that no packet is to be sent in a frame; when using | 757 | * |
664 | * this, all other fields except the interrupt flag must be zero. | 758 | * If the @control.SYNC flag is set, the context drops all packets until a |
665 | * | 759 | * packet with a sy field is received which matches &fw_cdev_start_iso.sync. |
666 | * For receive packets, the header length must be a multiple of the context's | 760 | * |
667 | * header size; if the header length is larger than the context's header size, | 761 | * @control.PAYLOAD_LENGTH defines how many payload bytes can be received for |
668 | * multiple packets are queued for this entry. The sy and tag fields are | 762 | * one packet (in addition to payload quadlets that have been defined as headers |
669 | * ignored. If the sync flag is set, the context drops all packets until | 763 | * and are stripped and returned in the &fw_cdev_event_iso_interrupt structure). |
670 | * a packet with a matching sy field is received (the sync value to wait for is | 764 | * If more bytes are received, the additional bytes are dropped. If less bytes |
671 | * specified in the &fw_cdev_start_iso structure). The payload length defines | 765 | * are received, the remaining bytes in this part of the payload buffer will not |
672 | * how many payload bytes can be received for one packet (in addition to payload | 766 | * be written to, not even by the next packet. I.e., packets received in |
673 | * quadlets that have been defined as headers and are stripped and returned in | 767 | * consecutive frames will not necessarily be consecutive in memory. If an |
674 | * the &fw_cdev_event_iso_interrupt structure). If more bytes are received, the | 768 | * entry has queued multiple packets, the PAYLOAD_LENGTH is divided equally |
675 | * additional bytes are dropped. If less bytes are received, the remaining | 769 | * among them. |
676 | * bytes in this part of the payload buffer will not be written to, not even by | 770 | * |
677 | * the next packet, i.e., packets received in consecutive frames will not | 771 | * When a packet with the @control.INTERRUPT flag set has been completed, an |
678 | * necessarily be consecutive in memory. If an entry has queued multiple | ||
679 | * packets, the payload length is divided equally among them. | ||
680 | * | ||
681 | * When a packet with the interrupt flag set has been completed, the | ||
682 | * &fw_cdev_event_iso_interrupt event will be sent. An entry that has queued | 772 | * &fw_cdev_event_iso_interrupt event will be sent. An entry that has queued |
683 | * multiple receive packets is completed when its last packet is completed. | 773 | * multiple receive packets is completed when its last packet is completed. |
774 | * | ||
775 | * Context type %FW_CDEV_ISO_CONTEXT_RECEIVE_MULTICHANNEL: | ||
776 | * | ||
777 | * Here, &fw_cdev_iso_packet would be more aptly named _iso_buffer_chunk since | ||
778 | * it specifies a chunk of the mmap()'ed buffer, while the number and alignment | ||
779 | * of packets to be placed into the buffer chunk is not known beforehand. | ||
780 | * | ||
781 | * @control.PAYLOAD_LENGTH is the size of the buffer chunk and specifies room | ||
782 | * for header, payload, padding, and trailer bytes of one or more packets. | ||
783 | * It must be a multiple of 4. | ||
784 | * | ||
785 | * @control.HEADER_LENGTH, TAG and SY are ignored. SYNC is treated as described | ||
786 | * for single-channel reception. | ||
787 | * | ||
788 | * When a buffer chunk with the @control.INTERRUPT flag set has been filled | ||
789 | * entirely, an &fw_cdev_event_iso_interrupt_mc event will be sent. | ||
684 | */ | 790 | */ |
685 | struct fw_cdev_iso_packet { | 791 | struct fw_cdev_iso_packet { |
686 | __u32 control; | 792 | __u32 control; |
@@ -689,9 +795,9 @@ struct fw_cdev_iso_packet { | |||
689 | 795 | ||
690 | /** | 796 | /** |
691 | * struct fw_cdev_queue_iso - Queue isochronous packets for I/O | 797 | * struct fw_cdev_queue_iso - Queue isochronous packets for I/O |
692 | * @packets: Userspace pointer to packet data | 798 | * @packets: Userspace pointer to an array of &fw_cdev_iso_packet |
693 | * @data: Pointer into mmap()'ed payload buffer | 799 | * @data: Pointer into mmap()'ed payload buffer |
694 | * @size: Size of packet data in bytes | 800 | * @size: Size of the @packets array, in bytes |
695 | * @handle: Isochronous context handle | 801 | * @handle: Isochronous context handle |
696 | * | 802 | * |
697 | * Queue a number of isochronous packets for reception or transmission. | 803 | * Queue a number of isochronous packets for reception or transmission. |
@@ -704,6 +810,9 @@ struct fw_cdev_iso_packet { | |||
704 | * The kernel may or may not queue all packets, but will write back updated | 810 | * The kernel may or may not queue all packets, but will write back updated |
705 | * values of the @packets, @data and @size fields, so the ioctl can be | 811 | * values of the @packets, @data and @size fields, so the ioctl can be |
706 | * resubmitted easily. | 812 | * resubmitted easily. |
813 | * | ||
814 | * In case of a multichannel receive context, @data must be quadlet-aligned | ||
815 | * relative to the buffer start. | ||
707 | */ | 816 | */ |
708 | struct fw_cdev_queue_iso { | 817 | struct fw_cdev_queue_iso { |
709 | __u64 packets; | 818 | __u64 packets; |
diff --git a/include/linux/firewire.h b/include/linux/firewire.h index d974aa4a24c9..1cd637ef62d2 100644 --- a/include/linux/firewire.h +++ b/include/linux/firewire.h | |||
@@ -372,17 +372,19 @@ void fw_core_remove_descriptor(struct fw_descriptor *desc); | |||
372 | * scatter-gather streaming (e.g. assembling video frame automatically). | 372 | * scatter-gather streaming (e.g. assembling video frame automatically). |
373 | */ | 373 | */ |
374 | struct fw_iso_packet { | 374 | struct fw_iso_packet { |
375 | u16 payload_length; /* Length of indirect payload. */ | 375 | u16 payload_length; /* Length of indirect payload */ |
376 | u32 interrupt:1; /* Generate interrupt on this packet */ | 376 | u32 interrupt:1; /* Generate interrupt on this packet */ |
377 | u32 skip:1; /* Set to not send packet at all. */ | 377 | u32 skip:1; /* tx: Set to not send packet at all */ |
378 | u32 tag:2; | 378 | /* rx: Sync bit, wait for matching sy */ |
379 | u32 sy:4; | 379 | u32 tag:2; /* tx: Tag in packet header */ |
380 | u32 header_length:8; /* Length of immediate header. */ | 380 | u32 sy:4; /* tx: Sy in packet header */ |
381 | u32 header[0]; | 381 | u32 header_length:8; /* Length of immediate header */ |
382 | u32 header[0]; /* tx: Top of 1394 isoch. data_block */ | ||
382 | }; | 383 | }; |
383 | 384 | ||
384 | #define FW_ISO_CONTEXT_TRANSMIT 0 | 385 | #define FW_ISO_CONTEXT_TRANSMIT 0 |
385 | #define FW_ISO_CONTEXT_RECEIVE 1 | 386 | #define FW_ISO_CONTEXT_RECEIVE 1 |
387 | #define FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL 2 | ||
386 | 388 | ||
387 | #define FW_ISO_CONTEXT_MATCH_TAG0 1 | 389 | #define FW_ISO_CONTEXT_MATCH_TAG0 1 |
388 | #define FW_ISO_CONTEXT_MATCH_TAG1 2 | 390 | #define FW_ISO_CONTEXT_MATCH_TAG1 2 |
@@ -406,24 +408,31 @@ struct fw_iso_buffer { | |||
406 | int fw_iso_buffer_init(struct fw_iso_buffer *buffer, struct fw_card *card, | 408 | int fw_iso_buffer_init(struct fw_iso_buffer *buffer, struct fw_card *card, |
407 | int page_count, enum dma_data_direction direction); | 409 | int page_count, enum dma_data_direction direction); |
408 | void fw_iso_buffer_destroy(struct fw_iso_buffer *buffer, struct fw_card *card); | 410 | void fw_iso_buffer_destroy(struct fw_iso_buffer *buffer, struct fw_card *card); |
411 | size_t fw_iso_buffer_lookup(struct fw_iso_buffer *buffer, dma_addr_t completed); | ||
409 | 412 | ||
410 | struct fw_iso_context; | 413 | struct fw_iso_context; |
411 | typedef void (*fw_iso_callback_t)(struct fw_iso_context *context, | 414 | typedef void (*fw_iso_callback_t)(struct fw_iso_context *context, |
412 | u32 cycle, size_t header_length, | 415 | u32 cycle, size_t header_length, |
413 | void *header, void *data); | 416 | void *header, void *data); |
417 | typedef void (*fw_iso_mc_callback_t)(struct fw_iso_context *context, | ||
418 | dma_addr_t completed, void *data); | ||
414 | struct fw_iso_context { | 419 | struct fw_iso_context { |
415 | struct fw_card *card; | 420 | struct fw_card *card; |
416 | int type; | 421 | int type; |
417 | int channel; | 422 | int channel; |
418 | int speed; | 423 | int speed; |
419 | size_t header_size; | 424 | size_t header_size; |
420 | fw_iso_callback_t callback; | 425 | union { |
426 | fw_iso_callback_t sc; | ||
427 | fw_iso_mc_callback_t mc; | ||
428 | } callback; | ||
421 | void *callback_data; | 429 | void *callback_data; |
422 | }; | 430 | }; |
423 | 431 | ||
424 | struct fw_iso_context *fw_iso_context_create(struct fw_card *card, | 432 | struct fw_iso_context *fw_iso_context_create(struct fw_card *card, |
425 | int type, int channel, int speed, size_t header_size, | 433 | int type, int channel, int speed, size_t header_size, |
426 | fw_iso_callback_t callback, void *callback_data); | 434 | fw_iso_callback_t callback, void *callback_data); |
435 | int fw_iso_context_set_channels(struct fw_iso_context *ctx, u64 *channels); | ||
427 | int fw_iso_context_queue(struct fw_iso_context *ctx, | 436 | int fw_iso_context_queue(struct fw_iso_context *ctx, |
428 | struct fw_iso_packet *packet, | 437 | struct fw_iso_packet *packet, |
429 | struct fw_iso_buffer *buffer, | 438 | struct fw_iso_buffer *buffer, |