1 |
62 |
marcus.erl |
/*
|
2 |
|
|
* video1394.c - video driver for OHCI 1394 boards
|
3 |
|
|
* Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>
|
4 |
|
|
* Peter Schlaile <udbz@rz.uni-karlsruhe.de>
|
5 |
|
|
*
|
6 |
|
|
* This program is free software; you can redistribute it and/or modify
|
7 |
|
|
* it under the terms of the GNU General Public License as published by
|
8 |
|
|
* the Free Software Foundation; either version 2 of the License, or
|
9 |
|
|
* (at your option) any later version.
|
10 |
|
|
*
|
11 |
|
|
* This program is distributed in the hope that it will be useful,
|
12 |
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 |
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14 |
|
|
* GNU General Public License for more details.
|
15 |
|
|
*
|
16 |
|
|
* You should have received a copy of the GNU General Public License
|
17 |
|
|
* along with this program; if not, write to the Free Software Foundation,
|
18 |
|
|
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
19 |
|
|
*
|
20 |
|
|
* NOTES:
|
21 |
|
|
*
|
22 |
|
|
* ioctl return codes:
|
23 |
|
|
* EFAULT is only for invalid address for the argp
|
24 |
|
|
* EINVAL for out of range values
|
25 |
|
|
* EBUSY when trying to use an already used resource
|
26 |
|
|
* ESRCH when trying to free/stop a not used resource
|
27 |
|
|
* EAGAIN for resource allocation failure that could perhaps succeed later
|
28 |
|
|
* ENOTTY for unsupported ioctl request
|
29 |
|
|
*
|
30 |
|
|
*/
|
31 |
|
|
#include <linux/kernel.h>
|
32 |
|
|
#include <linux/list.h>
|
33 |
|
|
#include <linux/slab.h>
|
34 |
|
|
#include <linux/interrupt.h>
|
35 |
|
|
#include <linux/wait.h>
|
36 |
|
|
#include <linux/errno.h>
|
37 |
|
|
#include <linux/module.h>
|
38 |
|
|
#include <linux/init.h>
|
39 |
|
|
#include <linux/pci.h>
|
40 |
|
|
#include <linux/fs.h>
|
41 |
|
|
#include <linux/poll.h>
|
42 |
|
|
#include <linux/delay.h>
|
43 |
|
|
#include <linux/bitops.h>
|
44 |
|
|
#include <linux/types.h>
|
45 |
|
|
#include <linux/vmalloc.h>
|
46 |
|
|
#include <linux/timex.h>
|
47 |
|
|
#include <linux/mm.h>
|
48 |
|
|
#include <linux/compat.h>
|
49 |
|
|
#include <linux/cdev.h>
|
50 |
|
|
|
51 |
|
|
#include "dma.h"
|
52 |
|
|
#include "highlevel.h"
|
53 |
|
|
#include "hosts.h"
|
54 |
|
|
#include "ieee1394.h"
|
55 |
|
|
#include "ieee1394_core.h"
|
56 |
|
|
#include "ieee1394_hotplug.h"
|
57 |
|
|
#include "ieee1394_types.h"
|
58 |
|
|
#include "nodemgr.h"
|
59 |
|
|
#include "ohci1394.h"
|
60 |
|
|
#include "video1394.h"
|
61 |
|
|
|
62 |
|
|
#define ISO_CHANNELS 64
|
63 |
|
|
|
64 |
|
|
struct it_dma_prg {
|
65 |
|
|
struct dma_cmd begin;
|
66 |
|
|
quadlet_t data[4];
|
67 |
|
|
struct dma_cmd end;
|
68 |
|
|
quadlet_t pad[4]; /* FIXME: quick hack for memory alignment */
|
69 |
|
|
};
|
70 |
|
|
|
71 |
|
|
struct dma_iso_ctx {
|
72 |
|
|
struct ti_ohci *ohci;
|
73 |
|
|
int type; /* OHCI_ISO_TRANSMIT or OHCI_ISO_RECEIVE */
|
74 |
|
|
struct ohci1394_iso_tasklet iso_tasklet;
|
75 |
|
|
int channel;
|
76 |
|
|
int ctx;
|
77 |
|
|
int last_buffer;
|
78 |
|
|
int * next_buffer; /* For ISO Transmit of video packets
|
79 |
|
|
to write the correct SYT field
|
80 |
|
|
into the next block */
|
81 |
|
|
unsigned int num_desc;
|
82 |
|
|
unsigned int buf_size;
|
83 |
|
|
unsigned int frame_size;
|
84 |
|
|
unsigned int packet_size;
|
85 |
|
|
unsigned int left_size;
|
86 |
|
|
unsigned int nb_cmd;
|
87 |
|
|
|
88 |
|
|
struct dma_region dma;
|
89 |
|
|
|
90 |
|
|
struct dma_prog_region *prg_reg;
|
91 |
|
|
|
92 |
|
|
struct dma_cmd **ir_prg;
|
93 |
|
|
struct it_dma_prg **it_prg;
|
94 |
|
|
|
95 |
|
|
unsigned int *buffer_status;
|
96 |
|
|
unsigned int *buffer_prg_assignment;
|
97 |
|
|
struct timeval *buffer_time; /* time when the buffer was received */
|
98 |
|
|
unsigned int *last_used_cmd; /* For ISO Transmit with
|
99 |
|
|
variable sized packets only ! */
|
100 |
|
|
int ctrlClear;
|
101 |
|
|
int ctrlSet;
|
102 |
|
|
int cmdPtr;
|
103 |
|
|
int ctxMatch;
|
104 |
|
|
wait_queue_head_t waitq;
|
105 |
|
|
spinlock_t lock;
|
106 |
|
|
unsigned int syt_offset;
|
107 |
|
|
int flags;
|
108 |
|
|
|
109 |
|
|
struct list_head link;
|
110 |
|
|
};
|
111 |
|
|
|
112 |
|
|
|
113 |
|
|
struct file_ctx {
|
114 |
|
|
struct ti_ohci *ohci;
|
115 |
|
|
struct list_head context_list;
|
116 |
|
|
struct dma_iso_ctx *current_ctx;
|
117 |
|
|
};
|
118 |
|
|
|
119 |
|
|
#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
|
120 |
|
|
#define VIDEO1394_DEBUG
|
121 |
|
|
#endif
|
122 |
|
|
|
123 |
|
|
#ifdef DBGMSG
|
124 |
|
|
#undef DBGMSG
|
125 |
|
|
#endif
|
126 |
|
|
|
127 |
|
|
#ifdef VIDEO1394_DEBUG
|
128 |
|
|
#define DBGMSG(card, fmt, args...) \
|
129 |
|
|
printk(KERN_INFO "video1394_%d: " fmt "\n" , card , ## args)
|
130 |
|
|
#else
|
131 |
|
|
#define DBGMSG(card, fmt, args...) do {} while (0)
|
132 |
|
|
#endif
|
133 |
|
|
|
134 |
|
|
/* print general (card independent) information */
|
135 |
|
|
#define PRINT_G(level, fmt, args...) \
|
136 |
|
|
printk(level "video1394: " fmt "\n" , ## args)
|
137 |
|
|
|
138 |
|
|
/* print card specific information */
|
139 |
|
|
#define PRINT(level, card, fmt, args...) \
|
140 |
|
|
printk(level "video1394_%d: " fmt "\n" , card , ## args)
|
141 |
|
|
|
142 |
|
|
static void wakeup_dma_ir_ctx(unsigned long l);
|
143 |
|
|
static void wakeup_dma_it_ctx(unsigned long l);
|
144 |
|
|
|
145 |
|
|
static struct hpsb_highlevel video1394_highlevel;
|
146 |
|
|
|
147 |
|
|
static int free_dma_iso_ctx(struct dma_iso_ctx *d)
|
148 |
|
|
{
|
149 |
|
|
int i;
|
150 |
|
|
|
151 |
|
|
DBGMSG(d->ohci->host->id, "Freeing dma_iso_ctx %d", d->ctx);
|
152 |
|
|
|
153 |
|
|
ohci1394_stop_context(d->ohci, d->ctrlClear, NULL);
|
154 |
|
|
if (d->iso_tasklet.link.next != NULL)
|
155 |
|
|
ohci1394_unregister_iso_tasklet(d->ohci, &d->iso_tasklet);
|
156 |
|
|
|
157 |
|
|
dma_region_free(&d->dma);
|
158 |
|
|
|
159 |
|
|
if (d->prg_reg) {
|
160 |
|
|
for (i = 0; i < d->num_desc; i++)
|
161 |
|
|
dma_prog_region_free(&d->prg_reg[i]);
|
162 |
|
|
kfree(d->prg_reg);
|
163 |
|
|
}
|
164 |
|
|
|
165 |
|
|
kfree(d->ir_prg);
|
166 |
|
|
kfree(d->it_prg);
|
167 |
|
|
kfree(d->buffer_status);
|
168 |
|
|
kfree(d->buffer_prg_assignment);
|
169 |
|
|
kfree(d->buffer_time);
|
170 |
|
|
kfree(d->last_used_cmd);
|
171 |
|
|
kfree(d->next_buffer);
|
172 |
|
|
list_del(&d->link);
|
173 |
|
|
kfree(d);
|
174 |
|
|
|
175 |
|
|
return 0;
|
176 |
|
|
}
|
177 |
|
|
|
178 |
|
|
static struct dma_iso_ctx *
|
179 |
|
|
alloc_dma_iso_ctx(struct ti_ohci *ohci, int type, int num_desc,
|
180 |
|
|
int buf_size, int channel, unsigned int packet_size)
|
181 |
|
|
{
|
182 |
|
|
struct dma_iso_ctx *d;
|
183 |
|
|
int i;
|
184 |
|
|
|
185 |
|
|
d = kzalloc(sizeof(*d), GFP_KERNEL);
|
186 |
|
|
if (!d) {
|
187 |
|
|
PRINT(KERN_ERR, ohci->host->id, "Failed to allocate dma_iso_ctx");
|
188 |
|
|
return NULL;
|
189 |
|
|
}
|
190 |
|
|
|
191 |
|
|
d->ohci = ohci;
|
192 |
|
|
d->type = type;
|
193 |
|
|
d->channel = channel;
|
194 |
|
|
d->num_desc = num_desc;
|
195 |
|
|
d->frame_size = buf_size;
|
196 |
|
|
d->buf_size = PAGE_ALIGN(buf_size);
|
197 |
|
|
d->last_buffer = -1;
|
198 |
|
|
INIT_LIST_HEAD(&d->link);
|
199 |
|
|
init_waitqueue_head(&d->waitq);
|
200 |
|
|
|
201 |
|
|
/* Init the regions for easy cleanup */
|
202 |
|
|
dma_region_init(&d->dma);
|
203 |
|
|
|
204 |
|
|
if (dma_region_alloc(&d->dma, (d->num_desc - 1) * d->buf_size, ohci->dev,
|
205 |
|
|
PCI_DMA_BIDIRECTIONAL)) {
|
206 |
|
|
PRINT(KERN_ERR, ohci->host->id, "Failed to allocate dma buffer");
|
207 |
|
|
free_dma_iso_ctx(d);
|
208 |
|
|
return NULL;
|
209 |
|
|
}
|
210 |
|
|
|
211 |
|
|
if (type == OHCI_ISO_RECEIVE)
|
212 |
|
|
ohci1394_init_iso_tasklet(&d->iso_tasklet, type,
|
213 |
|
|
wakeup_dma_ir_ctx,
|
214 |
|
|
(unsigned long) d);
|
215 |
|
|
else
|
216 |
|
|
ohci1394_init_iso_tasklet(&d->iso_tasklet, type,
|
217 |
|
|
wakeup_dma_it_ctx,
|
218 |
|
|
(unsigned long) d);
|
219 |
|
|
|
220 |
|
|
if (ohci1394_register_iso_tasklet(ohci, &d->iso_tasklet) < 0) {
|
221 |
|
|
PRINT(KERN_ERR, ohci->host->id, "no free iso %s contexts",
|
222 |
|
|
type == OHCI_ISO_RECEIVE ? "receive" : "transmit");
|
223 |
|
|
free_dma_iso_ctx(d);
|
224 |
|
|
return NULL;
|
225 |
|
|
}
|
226 |
|
|
d->ctx = d->iso_tasklet.context;
|
227 |
|
|
|
228 |
|
|
d->prg_reg = kmalloc(d->num_desc * sizeof(*d->prg_reg), GFP_KERNEL);
|
229 |
|
|
if (!d->prg_reg) {
|
230 |
|
|
PRINT(KERN_ERR, ohci->host->id, "Failed to allocate ir prg regs");
|
231 |
|
|
free_dma_iso_ctx(d);
|
232 |
|
|
return NULL;
|
233 |
|
|
}
|
234 |
|
|
/* Makes for easier cleanup */
|
235 |
|
|
for (i = 0; i < d->num_desc; i++)
|
236 |
|
|
dma_prog_region_init(&d->prg_reg[i]);
|
237 |
|
|
|
238 |
|
|
if (type == OHCI_ISO_RECEIVE) {
|
239 |
|
|
d->ctrlSet = OHCI1394_IsoRcvContextControlSet+32*d->ctx;
|
240 |
|
|
d->ctrlClear = OHCI1394_IsoRcvContextControlClear+32*d->ctx;
|
241 |
|
|
d->cmdPtr = OHCI1394_IsoRcvCommandPtr+32*d->ctx;
|
242 |
|
|
d->ctxMatch = OHCI1394_IsoRcvContextMatch+32*d->ctx;
|
243 |
|
|
|
244 |
|
|
d->ir_prg = kzalloc(d->num_desc * sizeof(*d->ir_prg),
|
245 |
|
|
GFP_KERNEL);
|
246 |
|
|
|
247 |
|
|
if (!d->ir_prg) {
|
248 |
|
|
PRINT(KERN_ERR, ohci->host->id, "Failed to allocate dma ir prg");
|
249 |
|
|
free_dma_iso_ctx(d);
|
250 |
|
|
return NULL;
|
251 |
|
|
}
|
252 |
|
|
|
253 |
|
|
d->nb_cmd = d->buf_size / PAGE_SIZE + 1;
|
254 |
|
|
d->left_size = (d->frame_size % PAGE_SIZE) ?
|
255 |
|
|
d->frame_size % PAGE_SIZE : PAGE_SIZE;
|
256 |
|
|
|
257 |
|
|
for (i = 0;i < d->num_desc; i++) {
|
258 |
|
|
if (dma_prog_region_alloc(&d->prg_reg[i], d->nb_cmd *
|
259 |
|
|
sizeof(struct dma_cmd), ohci->dev)) {
|
260 |
|
|
PRINT(KERN_ERR, ohci->host->id, "Failed to allocate dma ir prg");
|
261 |
|
|
free_dma_iso_ctx(d);
|
262 |
|
|
return NULL;
|
263 |
|
|
}
|
264 |
|
|
d->ir_prg[i] = (struct dma_cmd *)d->prg_reg[i].kvirt;
|
265 |
|
|
}
|
266 |
|
|
|
267 |
|
|
} else { /* OHCI_ISO_TRANSMIT */
|
268 |
|
|
d->ctrlSet = OHCI1394_IsoXmitContextControlSet+16*d->ctx;
|
269 |
|
|
d->ctrlClear = OHCI1394_IsoXmitContextControlClear+16*d->ctx;
|
270 |
|
|
d->cmdPtr = OHCI1394_IsoXmitCommandPtr+16*d->ctx;
|
271 |
|
|
|
272 |
|
|
d->it_prg = kzalloc(d->num_desc * sizeof(*d->it_prg),
|
273 |
|
|
GFP_KERNEL);
|
274 |
|
|
|
275 |
|
|
if (!d->it_prg) {
|
276 |
|
|
PRINT(KERN_ERR, ohci->host->id,
|
277 |
|
|
"Failed to allocate dma it prg");
|
278 |
|
|
free_dma_iso_ctx(d);
|
279 |
|
|
return NULL;
|
280 |
|
|
}
|
281 |
|
|
|
282 |
|
|
d->packet_size = packet_size;
|
283 |
|
|
|
284 |
|
|
if (PAGE_SIZE % packet_size || packet_size>4096) {
|
285 |
|
|
PRINT(KERN_ERR, ohci->host->id,
|
286 |
|
|
"Packet size %d (page_size: %ld) "
|
287 |
|
|
"not yet supported\n",
|
288 |
|
|
packet_size, PAGE_SIZE);
|
289 |
|
|
free_dma_iso_ctx(d);
|
290 |
|
|
return NULL;
|
291 |
|
|
}
|
292 |
|
|
|
293 |
|
|
d->nb_cmd = d->frame_size / d->packet_size;
|
294 |
|
|
if (d->frame_size % d->packet_size) {
|
295 |
|
|
d->nb_cmd++;
|
296 |
|
|
d->left_size = d->frame_size % d->packet_size;
|
297 |
|
|
} else
|
298 |
|
|
d->left_size = d->packet_size;
|
299 |
|
|
|
300 |
|
|
for (i = 0; i < d->num_desc; i++) {
|
301 |
|
|
if (dma_prog_region_alloc(&d->prg_reg[i], d->nb_cmd *
|
302 |
|
|
sizeof(struct it_dma_prg), ohci->dev)) {
|
303 |
|
|
PRINT(KERN_ERR, ohci->host->id, "Failed to allocate dma it prg");
|
304 |
|
|
free_dma_iso_ctx(d);
|
305 |
|
|
return NULL;
|
306 |
|
|
}
|
307 |
|
|
d->it_prg[i] = (struct it_dma_prg *)d->prg_reg[i].kvirt;
|
308 |
|
|
}
|
309 |
|
|
}
|
310 |
|
|
|
311 |
|
|
d->buffer_status =
|
312 |
|
|
kzalloc(d->num_desc * sizeof(*d->buffer_status), GFP_KERNEL);
|
313 |
|
|
d->buffer_prg_assignment =
|
314 |
|
|
kzalloc(d->num_desc * sizeof(*d->buffer_prg_assignment), GFP_KERNEL);
|
315 |
|
|
d->buffer_time =
|
316 |
|
|
kzalloc(d->num_desc * sizeof(*d->buffer_time), GFP_KERNEL);
|
317 |
|
|
d->last_used_cmd =
|
318 |
|
|
kzalloc(d->num_desc * sizeof(*d->last_used_cmd), GFP_KERNEL);
|
319 |
|
|
d->next_buffer =
|
320 |
|
|
kzalloc(d->num_desc * sizeof(*d->next_buffer), GFP_KERNEL);
|
321 |
|
|
|
322 |
|
|
if (!d->buffer_status || !d->buffer_prg_assignment || !d->buffer_time ||
|
323 |
|
|
!d->last_used_cmd || !d->next_buffer) {
|
324 |
|
|
PRINT(KERN_ERR, ohci->host->id,
|
325 |
|
|
"Failed to allocate dma_iso_ctx member");
|
326 |
|
|
free_dma_iso_ctx(d);
|
327 |
|
|
return NULL;
|
328 |
|
|
}
|
329 |
|
|
|
330 |
|
|
spin_lock_init(&d->lock);
|
331 |
|
|
|
332 |
|
|
DBGMSG(ohci->host->id, "Iso %s DMA: %d buffers "
|
333 |
|
|
"of size %d allocated for a frame size %d, each with %d prgs",
|
334 |
|
|
(type == OHCI_ISO_RECEIVE) ? "receive" : "transmit",
|
335 |
|
|
d->num_desc - 1, d->buf_size, d->frame_size, d->nb_cmd);
|
336 |
|
|
|
337 |
|
|
return d;
|
338 |
|
|
}
|
339 |
|
|
|
340 |
|
|
static void reset_ir_status(struct dma_iso_ctx *d, int n)
|
341 |
|
|
{
|
342 |
|
|
int i;
|
343 |
|
|
d->ir_prg[n][0].status = cpu_to_le32(4);
|
344 |
|
|
d->ir_prg[n][1].status = cpu_to_le32(PAGE_SIZE-4);
|
345 |
|
|
for (i = 2; i < d->nb_cmd - 1; i++)
|
346 |
|
|
d->ir_prg[n][i].status = cpu_to_le32(PAGE_SIZE);
|
347 |
|
|
d->ir_prg[n][i].status = cpu_to_le32(d->left_size);
|
348 |
|
|
}
|
349 |
|
|
|
350 |
|
|
static void reprogram_dma_ir_prg(struct dma_iso_ctx *d, int n, int buffer, int flags)
|
351 |
|
|
{
|
352 |
|
|
struct dma_cmd *ir_prg = d->ir_prg[n];
|
353 |
|
|
unsigned long buf = (unsigned long)d->dma.kvirt + buffer * d->buf_size;
|
354 |
|
|
int i;
|
355 |
|
|
|
356 |
|
|
d->buffer_prg_assignment[n] = buffer;
|
357 |
|
|
|
358 |
|
|
ir_prg[0].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma, buf -
|
359 |
|
|
(unsigned long)d->dma.kvirt));
|
360 |
|
|
ir_prg[1].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma,
|
361 |
|
|
(buf + 4) - (unsigned long)d->dma.kvirt));
|
362 |
|
|
|
363 |
|
|
for (i=2;i<d->nb_cmd-1;i++) {
|
364 |
|
|
ir_prg[i].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma,
|
365 |
|
|
(buf+(i-1)*PAGE_SIZE) -
|
366 |
|
|
(unsigned long)d->dma.kvirt));
|
367 |
|
|
}
|
368 |
|
|
|
369 |
|
|
ir_prg[i].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE |
|
370 |
|
|
DMA_CTL_IRQ | DMA_CTL_BRANCH | d->left_size);
|
371 |
|
|
ir_prg[i].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma,
|
372 |
|
|
(buf+(i-1)*PAGE_SIZE) - (unsigned long)d->dma.kvirt));
|
373 |
|
|
}
|
374 |
|
|
|
375 |
|
|
static void initialize_dma_ir_prg(struct dma_iso_ctx *d, int n, int flags)
|
376 |
|
|
{
|
377 |
|
|
struct dma_cmd *ir_prg = d->ir_prg[n];
|
378 |
|
|
struct dma_prog_region *ir_reg = &d->prg_reg[n];
|
379 |
|
|
unsigned long buf = (unsigned long)d->dma.kvirt;
|
380 |
|
|
int i;
|
381 |
|
|
|
382 |
|
|
/* the first descriptor will read only 4 bytes */
|
383 |
|
|
ir_prg[0].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE |
|
384 |
|
|
DMA_CTL_BRANCH | 4);
|
385 |
|
|
|
386 |
|
|
/* set the sync flag */
|
387 |
|
|
if (flags & VIDEO1394_SYNC_FRAMES)
|
388 |
|
|
ir_prg[0].control |= cpu_to_le32(DMA_CTL_WAIT);
|
389 |
|
|
|
390 |
|
|
ir_prg[0].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma, buf -
|
391 |
|
|
(unsigned long)d->dma.kvirt));
|
392 |
|
|
ir_prg[0].branchAddress = cpu_to_le32((dma_prog_region_offset_to_bus(ir_reg,
|
393 |
|
|
1 * sizeof(struct dma_cmd)) & 0xfffffff0) | 0x1);
|
394 |
|
|
|
395 |
|
|
/* If there is *not* only one DMA page per frame (hence, d->nb_cmd==2) */
|
396 |
|
|
if (d->nb_cmd > 2) {
|
397 |
|
|
/* The second descriptor will read PAGE_SIZE-4 bytes */
|
398 |
|
|
ir_prg[1].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE |
|
399 |
|
|
DMA_CTL_BRANCH | (PAGE_SIZE-4));
|
400 |
|
|
ir_prg[1].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma, (buf + 4) -
|
401 |
|
|
(unsigned long)d->dma.kvirt));
|
402 |
|
|
ir_prg[1].branchAddress = cpu_to_le32((dma_prog_region_offset_to_bus(ir_reg,
|
403 |
|
|
2 * sizeof(struct dma_cmd)) & 0xfffffff0) | 0x1);
|
404 |
|
|
|
405 |
|
|
for (i = 2; i < d->nb_cmd - 1; i++) {
|
406 |
|
|
ir_prg[i].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE |
|
407 |
|
|
DMA_CTL_BRANCH | PAGE_SIZE);
|
408 |
|
|
ir_prg[i].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma,
|
409 |
|
|
(buf+(i-1)*PAGE_SIZE) -
|
410 |
|
|
(unsigned long)d->dma.kvirt));
|
411 |
|
|
|
412 |
|
|
ir_prg[i].branchAddress =
|
413 |
|
|
cpu_to_le32((dma_prog_region_offset_to_bus(ir_reg,
|
414 |
|
|
(i + 1) * sizeof(struct dma_cmd)) & 0xfffffff0) | 0x1);
|
415 |
|
|
}
|
416 |
|
|
|
417 |
|
|
/* The last descriptor will generate an interrupt */
|
418 |
|
|
ir_prg[i].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE |
|
419 |
|
|
DMA_CTL_IRQ | DMA_CTL_BRANCH | d->left_size);
|
420 |
|
|
ir_prg[i].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma,
|
421 |
|
|
(buf+(i-1)*PAGE_SIZE) -
|
422 |
|
|
(unsigned long)d->dma.kvirt));
|
423 |
|
|
} else {
|
424 |
|
|
/* Only one DMA page is used. Read d->left_size immediately and */
|
425 |
|
|
/* generate an interrupt as this is also the last page. */
|
426 |
|
|
ir_prg[1].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE |
|
427 |
|
|
DMA_CTL_IRQ | DMA_CTL_BRANCH | (d->left_size-4));
|
428 |
|
|
ir_prg[1].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma,
|
429 |
|
|
(buf + 4) - (unsigned long)d->dma.kvirt));
|
430 |
|
|
}
|
431 |
|
|
}
|
432 |
|
|
|
433 |
|
|
static void initialize_dma_ir_ctx(struct dma_iso_ctx *d, int tag, int flags)
|
434 |
|
|
{
|
435 |
|
|
struct ti_ohci *ohci = (struct ti_ohci *)d->ohci;
|
436 |
|
|
int i;
|
437 |
|
|
|
438 |
|
|
d->flags = flags;
|
439 |
|
|
|
440 |
|
|
ohci1394_stop_context(ohci, d->ctrlClear, NULL);
|
441 |
|
|
|
442 |
|
|
for (i=0;i<d->num_desc;i++) {
|
443 |
|
|
initialize_dma_ir_prg(d, i, flags);
|
444 |
|
|
reset_ir_status(d, i);
|
445 |
|
|
}
|
446 |
|
|
|
447 |
|
|
/* reset the ctrl register */
|
448 |
|
|
reg_write(ohci, d->ctrlClear, 0xf0000000);
|
449 |
|
|
|
450 |
|
|
/* Set bufferFill */
|
451 |
|
|
reg_write(ohci, d->ctrlSet, 0x80000000);
|
452 |
|
|
|
453 |
|
|
/* Set isoch header */
|
454 |
|
|
if (flags & VIDEO1394_INCLUDE_ISO_HEADERS)
|
455 |
|
|
reg_write(ohci, d->ctrlSet, 0x40000000);
|
456 |
|
|
|
457 |
|
|
/* Set the context match register to match on all tags,
|
458 |
|
|
sync for sync tag, and listen to d->channel */
|
459 |
|
|
reg_write(ohci, d->ctxMatch, 0xf0000000|((tag&0xf)<<8)|d->channel);
|
460 |
|
|
|
461 |
|
|
/* Set up isoRecvIntMask to generate interrupts */
|
462 |
|
|
reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 1<<d->ctx);
|
463 |
|
|
}
|
464 |
|
|
|
465 |
|
|
/* find which context is listening to this channel */
|
466 |
|
|
static struct dma_iso_ctx *
|
467 |
|
|
find_ctx(struct list_head *list, int type, int channel)
|
468 |
|
|
{
|
469 |
|
|
struct dma_iso_ctx *ctx;
|
470 |
|
|
|
471 |
|
|
list_for_each_entry(ctx, list, link) {
|
472 |
|
|
if (ctx->type == type && ctx->channel == channel)
|
473 |
|
|
return ctx;
|
474 |
|
|
}
|
475 |
|
|
|
476 |
|
|
return NULL;
|
477 |
|
|
}
|
478 |
|
|
|
479 |
|
|
static void wakeup_dma_ir_ctx(unsigned long l)
|
480 |
|
|
{
|
481 |
|
|
struct dma_iso_ctx *d = (struct dma_iso_ctx *) l;
|
482 |
|
|
int i;
|
483 |
|
|
|
484 |
|
|
spin_lock(&d->lock);
|
485 |
|
|
|
486 |
|
|
for (i = 0; i < d->num_desc; i++) {
|
487 |
|
|
if (d->ir_prg[i][d->nb_cmd-1].status & cpu_to_le32(0xFFFF0000)) {
|
488 |
|
|
reset_ir_status(d, i);
|
489 |
|
|
d->buffer_status[d->buffer_prg_assignment[i]] = VIDEO1394_BUFFER_READY;
|
490 |
|
|
do_gettimeofday(&d->buffer_time[d->buffer_prg_assignment[i]]);
|
491 |
|
|
dma_region_sync_for_cpu(&d->dma,
|
492 |
|
|
d->buffer_prg_assignment[i] * d->buf_size,
|
493 |
|
|
d->buf_size);
|
494 |
|
|
}
|
495 |
|
|
}
|
496 |
|
|
|
497 |
|
|
spin_unlock(&d->lock);
|
498 |
|
|
|
499 |
|
|
if (waitqueue_active(&d->waitq))
|
500 |
|
|
wake_up_interruptible(&d->waitq);
|
501 |
|
|
}
|
502 |
|
|
|
503 |
|
|
static inline void put_timestamp(struct ti_ohci *ohci, struct dma_iso_ctx * d,
|
504 |
|
|
int n)
|
505 |
|
|
{
|
506 |
|
|
unsigned char* buf = d->dma.kvirt + n * d->buf_size;
|
507 |
|
|
u32 cycleTimer;
|
508 |
|
|
u32 timeStamp;
|
509 |
|
|
|
510 |
|
|
if (n == -1) {
|
511 |
|
|
return;
|
512 |
|
|
}
|
513 |
|
|
|
514 |
|
|
cycleTimer = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
|
515 |
|
|
|
516 |
|
|
timeStamp = ((cycleTimer & 0x0fff) + d->syt_offset); /* 11059 = 450 us */
|
517 |
|
|
timeStamp = (timeStamp % 3072 + ((timeStamp / 3072) << 12)
|
518 |
|
|
+ (cycleTimer & 0xf000)) & 0xffff;
|
519 |
|
|
|
520 |
|
|
buf[6] = timeStamp >> 8;
|
521 |
|
|
buf[7] = timeStamp & 0xff;
|
522 |
|
|
|
523 |
|
|
/* if first packet is empty packet, then put timestamp into the next full one too */
|
524 |
|
|
if ( (le32_to_cpu(d->it_prg[n][0].data[1]) >>16) == 0x008) {
|
525 |
|
|
buf += d->packet_size;
|
526 |
|
|
buf[6] = timeStamp >> 8;
|
527 |
|
|
buf[7] = timeStamp & 0xff;
|
528 |
|
|
}
|
529 |
|
|
|
530 |
|
|
/* do the next buffer frame too in case of irq latency */
|
531 |
|
|
n = d->next_buffer[n];
|
532 |
|
|
if (n == -1) {
|
533 |
|
|
return;
|
534 |
|
|
}
|
535 |
|
|
buf = d->dma.kvirt + n * d->buf_size;
|
536 |
|
|
|
537 |
|
|
timeStamp += (d->last_used_cmd[n] << 12) & 0xffff;
|
538 |
|
|
|
539 |
|
|
buf[6] = timeStamp >> 8;
|
540 |
|
|
buf[7] = timeStamp & 0xff;
|
541 |
|
|
|
542 |
|
|
/* if first packet is empty packet, then put timestamp into the next full one too */
|
543 |
|
|
if ( (le32_to_cpu(d->it_prg[n][0].data[1]) >>16) == 0x008) {
|
544 |
|
|
buf += d->packet_size;
|
545 |
|
|
buf[6] = timeStamp >> 8;
|
546 |
|
|
buf[7] = timeStamp & 0xff;
|
547 |
|
|
}
|
548 |
|
|
|
549 |
|
|
#if 0
|
550 |
|
|
printk("curr: %d, next: %d, cycleTimer: %08x timeStamp: %08x\n",
|
551 |
|
|
curr, n, cycleTimer, timeStamp);
|
552 |
|
|
#endif
|
553 |
|
|
}
|
554 |
|
|
|
555 |
|
|
static void wakeup_dma_it_ctx(unsigned long l)
|
556 |
|
|
{
|
557 |
|
|
struct dma_iso_ctx *d = (struct dma_iso_ctx *) l;
|
558 |
|
|
struct ti_ohci *ohci = d->ohci;
|
559 |
|
|
int i;
|
560 |
|
|
|
561 |
|
|
spin_lock(&d->lock);
|
562 |
|
|
|
563 |
|
|
for (i = 0; i < d->num_desc; i++) {
|
564 |
|
|
if (d->it_prg[i][d->last_used_cmd[i]].end.status &
|
565 |
|
|
cpu_to_le32(0xFFFF0000)) {
|
566 |
|
|
int next = d->next_buffer[i];
|
567 |
|
|
put_timestamp(ohci, d, next);
|
568 |
|
|
d->it_prg[i][d->last_used_cmd[i]].end.status = 0;
|
569 |
|
|
d->buffer_status[d->buffer_prg_assignment[i]] = VIDEO1394_BUFFER_READY;
|
570 |
|
|
}
|
571 |
|
|
}
|
572 |
|
|
|
573 |
|
|
spin_unlock(&d->lock);
|
574 |
|
|
|
575 |
|
|
if (waitqueue_active(&d->waitq))
|
576 |
|
|
wake_up_interruptible(&d->waitq);
|
577 |
|
|
}
|
578 |
|
|
|
579 |
|
|
static void reprogram_dma_it_prg(struct dma_iso_ctx *d, int n, int buffer)
|
580 |
|
|
{
|
581 |
|
|
struct it_dma_prg *it_prg = d->it_prg[n];
|
582 |
|
|
unsigned long buf = (unsigned long)d->dma.kvirt + buffer * d->buf_size;
|
583 |
|
|
int i;
|
584 |
|
|
|
585 |
|
|
d->buffer_prg_assignment[n] = buffer;
|
586 |
|
|
for (i=0;i<d->nb_cmd;i++) {
|
587 |
|
|
it_prg[i].end.address =
|
588 |
|
|
cpu_to_le32(dma_region_offset_to_bus(&d->dma,
|
589 |
|
|
(buf+i*d->packet_size) - (unsigned long)d->dma.kvirt));
|
590 |
|
|
}
|
591 |
|
|
}
|
592 |
|
|
|
593 |
|
|
static void initialize_dma_it_prg(struct dma_iso_ctx *d, int n, int sync_tag)
|
594 |
|
|
{
|
595 |
|
|
struct it_dma_prg *it_prg = d->it_prg[n];
|
596 |
|
|
struct dma_prog_region *it_reg = &d->prg_reg[n];
|
597 |
|
|
unsigned long buf = (unsigned long)d->dma.kvirt;
|
598 |
|
|
int i;
|
599 |
|
|
d->last_used_cmd[n] = d->nb_cmd - 1;
|
600 |
|
|
for (i=0;i<d->nb_cmd;i++) {
|
601 |
|
|
|
602 |
|
|
it_prg[i].begin.control = cpu_to_le32(DMA_CTL_OUTPUT_MORE |
|
603 |
|
|
DMA_CTL_IMMEDIATE | 8) ;
|
604 |
|
|
it_prg[i].begin.address = 0;
|
605 |
|
|
|
606 |
|
|
it_prg[i].begin.status = 0;
|
607 |
|
|
|
608 |
|
|
it_prg[i].data[0] = cpu_to_le32(
|
609 |
|
|
(IEEE1394_SPEED_100 << 16)
|
610 |
|
|
| (/* tag */ 1 << 14)
|
611 |
|
|
| (d->channel << 8)
|
612 |
|
|
| (TCODE_ISO_DATA << 4));
|
613 |
|
|
if (i==0) it_prg[i].data[0] |= cpu_to_le32(sync_tag);
|
614 |
|
|
it_prg[i].data[1] = cpu_to_le32(d->packet_size << 16);
|
615 |
|
|
it_prg[i].data[2] = 0;
|
616 |
|
|
it_prg[i].data[3] = 0;
|
617 |
|
|
|
618 |
|
|
it_prg[i].end.control = cpu_to_le32(DMA_CTL_OUTPUT_LAST |
|
619 |
|
|
DMA_CTL_BRANCH);
|
620 |
|
|
it_prg[i].end.address =
|
621 |
|
|
cpu_to_le32(dma_region_offset_to_bus(&d->dma, (buf+i*d->packet_size) -
|
622 |
|
|
(unsigned long)d->dma.kvirt));
|
623 |
|
|
|
624 |
|
|
if (i<d->nb_cmd-1) {
|
625 |
|
|
it_prg[i].end.control |= cpu_to_le32(d->packet_size);
|
626 |
|
|
it_prg[i].begin.branchAddress =
|
627 |
|
|
cpu_to_le32((dma_prog_region_offset_to_bus(it_reg, (i + 1) *
|
628 |
|
|
sizeof(struct it_dma_prg)) & 0xfffffff0) | 0x3);
|
629 |
|
|
it_prg[i].end.branchAddress =
|
630 |
|
|
cpu_to_le32((dma_prog_region_offset_to_bus(it_reg, (i + 1) *
|
631 |
|
|
sizeof(struct it_dma_prg)) & 0xfffffff0) | 0x3);
|
632 |
|
|
} else {
|
633 |
|
|
/* the last prg generates an interrupt */
|
634 |
|
|
it_prg[i].end.control |= cpu_to_le32(DMA_CTL_UPDATE |
|
635 |
|
|
DMA_CTL_IRQ | d->left_size);
|
636 |
|
|
/* the last prg doesn't branch */
|
637 |
|
|
it_prg[i].begin.branchAddress = 0;
|
638 |
|
|
it_prg[i].end.branchAddress = 0;
|
639 |
|
|
}
|
640 |
|
|
it_prg[i].end.status = 0;
|
641 |
|
|
}
|
642 |
|
|
}
|
643 |
|
|
|
644 |
|
|
static void initialize_dma_it_prg_var_packet_queue(
|
645 |
|
|
struct dma_iso_ctx *d, int n, unsigned int * packet_sizes,
|
646 |
|
|
struct ti_ohci *ohci)
|
647 |
|
|
{
|
648 |
|
|
struct it_dma_prg *it_prg = d->it_prg[n];
|
649 |
|
|
struct dma_prog_region *it_reg = &d->prg_reg[n];
|
650 |
|
|
int i;
|
651 |
|
|
|
652 |
|
|
#if 0
|
653 |
|
|
if (n != -1) {
|
654 |
|
|
put_timestamp(ohci, d, n);
|
655 |
|
|
}
|
656 |
|
|
#endif
|
657 |
|
|
d->last_used_cmd[n] = d->nb_cmd - 1;
|
658 |
|
|
|
659 |
|
|
for (i = 0; i < d->nb_cmd; i++) {
|
660 |
|
|
unsigned int size;
|
661 |
|
|
if (packet_sizes[i] > d->packet_size) {
|
662 |
|
|
size = d->packet_size;
|
663 |
|
|
} else {
|
664 |
|
|
size = packet_sizes[i];
|
665 |
|
|
}
|
666 |
|
|
it_prg[i].data[1] = cpu_to_le32(size << 16);
|
667 |
|
|
it_prg[i].end.control = cpu_to_le32(DMA_CTL_OUTPUT_LAST | DMA_CTL_BRANCH);
|
668 |
|
|
|
669 |
|
|
if (i < d->nb_cmd-1 && packet_sizes[i+1] != 0) {
|
670 |
|
|
it_prg[i].end.control |= cpu_to_le32(size);
|
671 |
|
|
it_prg[i].begin.branchAddress =
|
672 |
|
|
cpu_to_le32((dma_prog_region_offset_to_bus(it_reg, (i + 1) *
|
673 |
|
|
sizeof(struct it_dma_prg)) & 0xfffffff0) | 0x3);
|
674 |
|
|
it_prg[i].end.branchAddress =
|
675 |
|
|
cpu_to_le32((dma_prog_region_offset_to_bus(it_reg, (i + 1) *
|
676 |
|
|
sizeof(struct it_dma_prg)) & 0xfffffff0) | 0x3);
|
677 |
|
|
} else {
|
678 |
|
|
/* the last prg generates an interrupt */
|
679 |
|
|
it_prg[i].end.control |= cpu_to_le32(DMA_CTL_UPDATE |
|
680 |
|
|
DMA_CTL_IRQ | size);
|
681 |
|
|
/* the last prg doesn't branch */
|
682 |
|
|
it_prg[i].begin.branchAddress = 0;
|
683 |
|
|
it_prg[i].end.branchAddress = 0;
|
684 |
|
|
d->last_used_cmd[n] = i;
|
685 |
|
|
break;
|
686 |
|
|
}
|
687 |
|
|
}
|
688 |
|
|
}
|
689 |
|
|
|
690 |
|
|
static void initialize_dma_it_ctx(struct dma_iso_ctx *d, int sync_tag,
|
691 |
|
|
unsigned int syt_offset, int flags)
|
692 |
|
|
{
|
693 |
|
|
struct ti_ohci *ohci = (struct ti_ohci *)d->ohci;
|
694 |
|
|
int i;
|
695 |
|
|
|
696 |
|
|
d->flags = flags;
|
697 |
|
|
d->syt_offset = (syt_offset == 0 ? 11000 : syt_offset);
|
698 |
|
|
|
699 |
|
|
ohci1394_stop_context(ohci, d->ctrlClear, NULL);
|
700 |
|
|
|
701 |
|
|
for (i=0;i<d->num_desc;i++)
|
702 |
|
|
initialize_dma_it_prg(d, i, sync_tag);
|
703 |
|
|
|
704 |
|
|
/* Set up isoRecvIntMask to generate interrupts */
|
705 |
|
|
reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, 1<<d->ctx);
|
706 |
|
|
}
|
707 |
|
|
|
708 |
|
|
static inline unsigned video1394_buffer_state(struct dma_iso_ctx *d,
|
709 |
|
|
unsigned int buffer)
|
710 |
|
|
{
|
711 |
|
|
unsigned long flags;
|
712 |
|
|
unsigned int ret;
|
713 |
|
|
spin_lock_irqsave(&d->lock, flags);
|
714 |
|
|
ret = d->buffer_status[buffer];
|
715 |
|
|
spin_unlock_irqrestore(&d->lock, flags);
|
716 |
|
|
return ret;
|
717 |
|
|
}
|
718 |
|
|
|
719 |
|
|
static long video1394_ioctl(struct file *file,
|
720 |
|
|
unsigned int cmd, unsigned long arg)
|
721 |
|
|
{
|
722 |
|
|
struct file_ctx *ctx = (struct file_ctx *)file->private_data;
|
723 |
|
|
struct ti_ohci *ohci = ctx->ohci;
|
724 |
|
|
unsigned long flags;
|
725 |
|
|
void __user *argp = (void __user *)arg;
|
726 |
|
|
|
727 |
|
|
switch(cmd)
|
728 |
|
|
{
|
729 |
|
|
case VIDEO1394_IOC_LISTEN_CHANNEL:
|
730 |
|
|
case VIDEO1394_IOC_TALK_CHANNEL:
|
731 |
|
|
{
|
732 |
|
|
struct video1394_mmap v;
|
733 |
|
|
u64 mask;
|
734 |
|
|
struct dma_iso_ctx *d;
|
735 |
|
|
int i;
|
736 |
|
|
|
737 |
|
|
if (copy_from_user(&v, argp, sizeof(v)))
|
738 |
|
|
return -EFAULT;
|
739 |
|
|
|
740 |
|
|
/* if channel < 0, find lowest available one */
|
741 |
|
|
if (v.channel < 0) {
|
742 |
|
|
mask = (u64)0x1;
|
743 |
|
|
for (i=0; ; i++) {
|
744 |
|
|
if (i == ISO_CHANNELS) {
|
745 |
|
|
PRINT(KERN_ERR, ohci->host->id,
|
746 |
|
|
"No free channel found");
|
747 |
|
|
return -EAGAIN;
|
748 |
|
|
}
|
749 |
|
|
if (!(ohci->ISO_channel_usage & mask)) {
|
750 |
|
|
v.channel = i;
|
751 |
|
|
PRINT(KERN_INFO, ohci->host->id, "Found free channel %d", i);
|
752 |
|
|
break;
|
753 |
|
|
}
|
754 |
|
|
mask = mask << 1;
|
755 |
|
|
}
|
756 |
|
|
} else if (v.channel >= ISO_CHANNELS) {
|
757 |
|
|
PRINT(KERN_ERR, ohci->host->id,
|
758 |
|
|
"Iso channel %d out of bounds", v.channel);
|
759 |
|
|
return -EINVAL;
|
760 |
|
|
} else {
|
761 |
|
|
mask = (u64)0x1<<v.channel;
|
762 |
|
|
}
|
763 |
|
|
DBGMSG(ohci->host->id, "mask: %08X%08X usage: %08X%08X\n",
|
764 |
|
|
(u32)(mask>>32),(u32)(mask&0xffffffff),
|
765 |
|
|
(u32)(ohci->ISO_channel_usage>>32),
|
766 |
|
|
(u32)(ohci->ISO_channel_usage&0xffffffff));
|
767 |
|
|
if (ohci->ISO_channel_usage & mask) {
|
768 |
|
|
PRINT(KERN_ERR, ohci->host->id,
|
769 |
|
|
"Channel %d is already taken", v.channel);
|
770 |
|
|
return -EBUSY;
|
771 |
|
|
}
|
772 |
|
|
|
773 |
|
|
if (v.buf_size == 0 || v.buf_size > VIDEO1394_MAX_SIZE) {
|
774 |
|
|
PRINT(KERN_ERR, ohci->host->id,
|
775 |
|
|
"Invalid %d length buffer requested",v.buf_size);
|
776 |
|
|
return -EINVAL;
|
777 |
|
|
}
|
778 |
|
|
|
779 |
|
|
if (v.nb_buffers == 0 || v.nb_buffers > VIDEO1394_MAX_SIZE) {
|
780 |
|
|
PRINT(KERN_ERR, ohci->host->id,
|
781 |
|
|
"Invalid %d buffers requested",v.nb_buffers);
|
782 |
|
|
return -EINVAL;
|
783 |
|
|
}
|
784 |
|
|
|
785 |
|
|
if (v.nb_buffers * v.buf_size > VIDEO1394_MAX_SIZE) {
|
786 |
|
|
PRINT(KERN_ERR, ohci->host->id,
|
787 |
|
|
"%d buffers of size %d bytes is too big",
|
788 |
|
|
v.nb_buffers, v.buf_size);
|
789 |
|
|
return -EINVAL;
|
790 |
|
|
}
|
791 |
|
|
|
792 |
|
|
if (cmd == VIDEO1394_IOC_LISTEN_CHANNEL) {
|
793 |
|
|
d = alloc_dma_iso_ctx(ohci, OHCI_ISO_RECEIVE,
|
794 |
|
|
v.nb_buffers + 1, v.buf_size,
|
795 |
|
|
v.channel, 0);
|
796 |
|
|
|
797 |
|
|
if (d == NULL) {
|
798 |
|
|
PRINT(KERN_ERR, ohci->host->id,
|
799 |
|
|
"Couldn't allocate ir context");
|
800 |
|
|
return -EAGAIN;
|
801 |
|
|
}
|
802 |
|
|
initialize_dma_ir_ctx(d, v.sync_tag, v.flags);
|
803 |
|
|
|
804 |
|
|
ctx->current_ctx = d;
|
805 |
|
|
|
806 |
|
|
v.buf_size = d->buf_size;
|
807 |
|
|
list_add_tail(&d->link, &ctx->context_list);
|
808 |
|
|
|
809 |
|
|
DBGMSG(ohci->host->id,
|
810 |
|
|
"iso context %d listen on channel %d",
|
811 |
|
|
d->ctx, v.channel);
|
812 |
|
|
}
|
813 |
|
|
else {
|
814 |
|
|
d = alloc_dma_iso_ctx(ohci, OHCI_ISO_TRANSMIT,
|
815 |
|
|
v.nb_buffers + 1, v.buf_size,
|
816 |
|
|
v.channel, v.packet_size);
|
817 |
|
|
|
818 |
|
|
if (d == NULL) {
|
819 |
|
|
PRINT(KERN_ERR, ohci->host->id,
|
820 |
|
|
"Couldn't allocate it context");
|
821 |
|
|
return -EAGAIN;
|
822 |
|
|
}
|
823 |
|
|
initialize_dma_it_ctx(d, v.sync_tag,
|
824 |
|
|
v.syt_offset, v.flags);
|
825 |
|
|
|
826 |
|
|
ctx->current_ctx = d;
|
827 |
|
|
|
828 |
|
|
v.buf_size = d->buf_size;
|
829 |
|
|
|
830 |
|
|
list_add_tail(&d->link, &ctx->context_list);
|
831 |
|
|
|
832 |
|
|
DBGMSG(ohci->host->id,
|
833 |
|
|
"Iso context %d talk on channel %d", d->ctx,
|
834 |
|
|
v.channel);
|
835 |
|
|
}
|
836 |
|
|
|
837 |
|
|
if (copy_to_user(argp, &v, sizeof(v))) {
|
838 |
|
|
/* FIXME : free allocated dma resources */
|
839 |
|
|
return -EFAULT;
|
840 |
|
|
}
|
841 |
|
|
|
842 |
|
|
ohci->ISO_channel_usage |= mask;
|
843 |
|
|
|
844 |
|
|
return 0;
|
845 |
|
|
}
|
846 |
|
|
case VIDEO1394_IOC_UNLISTEN_CHANNEL:
|
847 |
|
|
case VIDEO1394_IOC_UNTALK_CHANNEL:
|
848 |
|
|
{
|
849 |
|
|
int channel;
|
850 |
|
|
u64 mask;
|
851 |
|
|
struct dma_iso_ctx *d;
|
852 |
|
|
|
853 |
|
|
if (copy_from_user(&channel, argp, sizeof(int)))
|
854 |
|
|
return -EFAULT;
|
855 |
|
|
|
856 |
|
|
if (channel < 0 || channel >= ISO_CHANNELS) {
|
857 |
|
|
PRINT(KERN_ERR, ohci->host->id,
|
858 |
|
|
"Iso channel %d out of bound", channel);
|
859 |
|
|
return -EINVAL;
|
860 |
|
|
}
|
861 |
|
|
mask = (u64)0x1<<channel;
|
862 |
|
|
if (!(ohci->ISO_channel_usage & mask)) {
|
863 |
|
|
PRINT(KERN_ERR, ohci->host->id,
|
864 |
|
|
"Channel %d is not being used", channel);
|
865 |
|
|
return -ESRCH;
|
866 |
|
|
}
|
867 |
|
|
|
868 |
|
|
/* Mark this channel as unused */
|
869 |
|
|
ohci->ISO_channel_usage &= ~mask;
|
870 |
|
|
|
871 |
|
|
if (cmd == VIDEO1394_IOC_UNLISTEN_CHANNEL)
|
872 |
|
|
d = find_ctx(&ctx->context_list, OHCI_ISO_RECEIVE, channel);
|
873 |
|
|
else
|
874 |
|
|
d = find_ctx(&ctx->context_list, OHCI_ISO_TRANSMIT, channel);
|
875 |
|
|
|
876 |
|
|
if (d == NULL) return -ESRCH;
|
877 |
|
|
DBGMSG(ohci->host->id, "Iso context %d "
|
878 |
|
|
"stop talking on channel %d", d->ctx, channel);
|
879 |
|
|
free_dma_iso_ctx(d);
|
880 |
|
|
|
881 |
|
|
return 0;
|
882 |
|
|
}
|
883 |
|
|
case VIDEO1394_IOC_LISTEN_QUEUE_BUFFER:
|
884 |
|
|
{
|
885 |
|
|
struct video1394_wait v;
|
886 |
|
|
struct dma_iso_ctx *d;
|
887 |
|
|
int next_prg;
|
888 |
|
|
|
889 |
|
|
if (unlikely(copy_from_user(&v, argp, sizeof(v))))
|
890 |
|
|
return -EFAULT;
|
891 |
|
|
|
892 |
|
|
d = find_ctx(&ctx->context_list, OHCI_ISO_RECEIVE, v.channel);
|
893 |
|
|
if (unlikely(d == NULL))
|
894 |
|
|
return -EFAULT;
|
895 |
|
|
|
896 |
|
|
if (unlikely((v.buffer<0) || (v.buffer>=d->num_desc - 1))) {
|
897 |
|
|
PRINT(KERN_ERR, ohci->host->id,
|
898 |
|
|
"Buffer %d out of range",v.buffer);
|
899 |
|
|
return -EINVAL;
|
900 |
|
|
}
|
901 |
|
|
|
902 |
|
|
spin_lock_irqsave(&d->lock,flags);
|
903 |
|
|
|
904 |
|
|
if (unlikely(d->buffer_status[v.buffer]==VIDEO1394_BUFFER_QUEUED)) {
|
905 |
|
|
PRINT(KERN_ERR, ohci->host->id,
|
906 |
|
|
"Buffer %d is already used",v.buffer);
|
907 |
|
|
spin_unlock_irqrestore(&d->lock,flags);
|
908 |
|
|
return -EBUSY;
|
909 |
|
|
}
|
910 |
|
|
|
911 |
|
|
d->buffer_status[v.buffer]=VIDEO1394_BUFFER_QUEUED;
|
912 |
|
|
|
913 |
|
|
next_prg = (d->last_buffer + 1) % d->num_desc;
|
914 |
|
|
if (d->last_buffer>=0)
|
915 |
|
|
d->ir_prg[d->last_buffer][d->nb_cmd-1].branchAddress =
|
916 |
|
|
cpu_to_le32((dma_prog_region_offset_to_bus(&d->prg_reg[next_prg], 0)
|
917 |
|
|
& 0xfffffff0) | 0x1);
|
918 |
|
|
|
919 |
|
|
d->last_buffer = next_prg;
|
920 |
|
|
reprogram_dma_ir_prg(d, d->last_buffer, v.buffer, d->flags);
|
921 |
|
|
|
922 |
|
|
d->ir_prg[d->last_buffer][d->nb_cmd-1].branchAddress = 0;
|
923 |
|
|
|
924 |
|
|
spin_unlock_irqrestore(&d->lock,flags);
|
925 |
|
|
|
926 |
|
|
if (!(reg_read(ohci, d->ctrlSet) & 0x8000))
|
927 |
|
|
{
|
928 |
|
|
DBGMSG(ohci->host->id, "Starting iso DMA ctx=%d",d->ctx);
|
929 |
|
|
|
930 |
|
|
/* Tell the controller where the first program is */
|
931 |
|
|
reg_write(ohci, d->cmdPtr,
|
932 |
|
|
dma_prog_region_offset_to_bus(&d->prg_reg[d->last_buffer], 0) | 0x1);
|
933 |
|
|
|
934 |
|
|
/* Run IR context */
|
935 |
|
|
reg_write(ohci, d->ctrlSet, 0x8000);
|
936 |
|
|
}
|
937 |
|
|
else {
|
938 |
|
|
/* Wake up dma context if necessary */
|
939 |
|
|
if (!(reg_read(ohci, d->ctrlSet) & 0x400)) {
|
940 |
|
|
DBGMSG(ohci->host->id,
|
941 |
|
|
"Waking up iso dma ctx=%d", d->ctx);
|
942 |
|
|
reg_write(ohci, d->ctrlSet, 0x1000);
|
943 |
|
|
}
|
944 |
|
|
}
|
945 |
|
|
return 0;
|
946 |
|
|
|
947 |
|
|
}
|
948 |
|
|
case VIDEO1394_IOC_LISTEN_WAIT_BUFFER:
|
949 |
|
|
case VIDEO1394_IOC_LISTEN_POLL_BUFFER:
|
950 |
|
|
{
|
951 |
|
|
struct video1394_wait v;
|
952 |
|
|
struct dma_iso_ctx *d;
|
953 |
|
|
int i = 0;
|
954 |
|
|
|
955 |
|
|
if (unlikely(copy_from_user(&v, argp, sizeof(v))))
|
956 |
|
|
return -EFAULT;
|
957 |
|
|
|
958 |
|
|
d = find_ctx(&ctx->context_list, OHCI_ISO_RECEIVE, v.channel);
|
959 |
|
|
if (unlikely(d == NULL))
|
960 |
|
|
return -EFAULT;
|
961 |
|
|
|
962 |
|
|
if (unlikely((v.buffer<0) || (v.buffer>d->num_desc - 1))) {
|
963 |
|
|
PRINT(KERN_ERR, ohci->host->id,
|
964 |
|
|
"Buffer %d out of range",v.buffer);
|
965 |
|
|
return -EINVAL;
|
966 |
|
|
}
|
967 |
|
|
|
968 |
|
|
/*
|
969 |
|
|
* I change the way it works so that it returns
|
970 |
|
|
* the last received frame.
|
971 |
|
|
*/
|
972 |
|
|
spin_lock_irqsave(&d->lock, flags);
|
973 |
|
|
switch(d->buffer_status[v.buffer]) {
|
974 |
|
|
case VIDEO1394_BUFFER_READY:
|
975 |
|
|
d->buffer_status[v.buffer]=VIDEO1394_BUFFER_FREE;
|
976 |
|
|
break;
|
977 |
|
|
case VIDEO1394_BUFFER_QUEUED:
|
978 |
|
|
if (cmd == VIDEO1394_IOC_LISTEN_POLL_BUFFER) {
|
979 |
|
|
/* for polling, return error code EINTR */
|
980 |
|
|
spin_unlock_irqrestore(&d->lock, flags);
|
981 |
|
|
return -EINTR;
|
982 |
|
|
}
|
983 |
|
|
|
984 |
|
|
spin_unlock_irqrestore(&d->lock, flags);
|
985 |
|
|
wait_event_interruptible(d->waitq,
|
986 |
|
|
video1394_buffer_state(d, v.buffer) ==
|
987 |
|
|
VIDEO1394_BUFFER_READY);
|
988 |
|
|
if (signal_pending(current))
|
989 |
|
|
return -EINTR;
|
990 |
|
|
spin_lock_irqsave(&d->lock, flags);
|
991 |
|
|
d->buffer_status[v.buffer]=VIDEO1394_BUFFER_FREE;
|
992 |
|
|
break;
|
993 |
|
|
default:
|
994 |
|
|
PRINT(KERN_ERR, ohci->host->id,
|
995 |
|
|
"Buffer %d is not queued",v.buffer);
|
996 |
|
|
spin_unlock_irqrestore(&d->lock, flags);
|
997 |
|
|
return -ESRCH;
|
998 |
|
|
}
|
999 |
|
|
|
1000 |
|
|
/* set time of buffer */
|
1001 |
|
|
v.filltime = d->buffer_time[v.buffer];
|
1002 |
|
|
|
1003 |
|
|
/*
|
1004 |
|
|
* Look ahead to see how many more buffers have been received
|
1005 |
|
|
*/
|
1006 |
|
|
i=0;
|
1007 |
|
|
while (d->buffer_status[(v.buffer+1)%(d->num_desc - 1)]==
|
1008 |
|
|
VIDEO1394_BUFFER_READY) {
|
1009 |
|
|
v.buffer=(v.buffer+1)%(d->num_desc - 1);
|
1010 |
|
|
i++;
|
1011 |
|
|
}
|
1012 |
|
|
spin_unlock_irqrestore(&d->lock, flags);
|
1013 |
|
|
|
1014 |
|
|
v.buffer=i;
|
1015 |
|
|
if (unlikely(copy_to_user(argp, &v, sizeof(v))))
|
1016 |
|
|
return -EFAULT;
|
1017 |
|
|
|
1018 |
|
|
return 0;
|
1019 |
|
|
}
|
1020 |
|
|
case VIDEO1394_IOC_TALK_QUEUE_BUFFER:
|
1021 |
|
|
{
|
1022 |
|
|
struct video1394_wait v;
|
1023 |
|
|
unsigned int *psizes = NULL;
|
1024 |
|
|
struct dma_iso_ctx *d;
|
1025 |
|
|
int next_prg;
|
1026 |
|
|
|
1027 |
|
|
if (copy_from_user(&v, argp, sizeof(v)))
|
1028 |
|
|
return -EFAULT;
|
1029 |
|
|
|
1030 |
|
|
d = find_ctx(&ctx->context_list, OHCI_ISO_TRANSMIT, v.channel);
|
1031 |
|
|
if (d == NULL) return -EFAULT;
|
1032 |
|
|
|
1033 |
|
|
if ((v.buffer<0) || (v.buffer>=d->num_desc - 1)) {
|
1034 |
|
|
PRINT(KERN_ERR, ohci->host->id,
|
1035 |
|
|
"Buffer %d out of range",v.buffer);
|
1036 |
|
|
return -EINVAL;
|
1037 |
|
|
}
|
1038 |
|
|
|
1039 |
|
|
if (d->flags & VIDEO1394_VARIABLE_PACKET_SIZE) {
|
1040 |
|
|
int buf_size = d->nb_cmd * sizeof(*psizes);
|
1041 |
|
|
struct video1394_queue_variable __user *p = argp;
|
1042 |
|
|
unsigned int __user *qv;
|
1043 |
|
|
|
1044 |
|
|
if (get_user(qv, &p->packet_sizes))
|
1045 |
|
|
return -EFAULT;
|
1046 |
|
|
|
1047 |
|
|
psizes = kmalloc(buf_size, GFP_KERNEL);
|
1048 |
|
|
if (!psizes)
|
1049 |
|
|
return -ENOMEM;
|
1050 |
|
|
|
1051 |
|
|
if (copy_from_user(psizes, qv, buf_size)) {
|
1052 |
|
|
kfree(psizes);
|
1053 |
|
|
return -EFAULT;
|
1054 |
|
|
}
|
1055 |
|
|
}
|
1056 |
|
|
|
1057 |
|
|
spin_lock_irqsave(&d->lock,flags);
|
1058 |
|
|
|
1059 |
|
|
/* last_buffer is last_prg */
|
1060 |
|
|
next_prg = (d->last_buffer + 1) % d->num_desc;
|
1061 |
|
|
if (d->buffer_status[v.buffer]!=VIDEO1394_BUFFER_FREE) {
|
1062 |
|
|
PRINT(KERN_ERR, ohci->host->id,
|
1063 |
|
|
"Buffer %d is already used",v.buffer);
|
1064 |
|
|
spin_unlock_irqrestore(&d->lock,flags);
|
1065 |
|
|
kfree(psizes);
|
1066 |
|
|
return -EBUSY;
|
1067 |
|
|
}
|
1068 |
|
|
|
1069 |
|
|
if (d->flags & VIDEO1394_VARIABLE_PACKET_SIZE) {
|
1070 |
|
|
initialize_dma_it_prg_var_packet_queue(
|
1071 |
|
|
d, next_prg, psizes, ohci);
|
1072 |
|
|
}
|
1073 |
|
|
|
1074 |
|
|
d->buffer_status[v.buffer]=VIDEO1394_BUFFER_QUEUED;
|
1075 |
|
|
|
1076 |
|
|
if (d->last_buffer >= 0) {
|
1077 |
|
|
d->it_prg[d->last_buffer]
|
1078 |
|
|
[ d->last_used_cmd[d->last_buffer] ].end.branchAddress =
|
1079 |
|
|
cpu_to_le32((dma_prog_region_offset_to_bus(&d->prg_reg[next_prg],
|
1080 |
|
|
0) & 0xfffffff0) | 0x3);
|
1081 |
|
|
|
1082 |
|
|
d->it_prg[d->last_buffer]
|
1083 |
|
|
[ d->last_used_cmd[d->last_buffer] ].begin.branchAddress =
|
1084 |
|
|
cpu_to_le32((dma_prog_region_offset_to_bus(&d->prg_reg[next_prg],
|
1085 |
|
|
0) & 0xfffffff0) | 0x3);
|
1086 |
|
|
d->next_buffer[d->last_buffer] = (v.buffer + 1) % (d->num_desc - 1);
|
1087 |
|
|
}
|
1088 |
|
|
d->last_buffer = next_prg;
|
1089 |
|
|
reprogram_dma_it_prg(d, d->last_buffer, v.buffer);
|
1090 |
|
|
d->next_buffer[d->last_buffer] = -1;
|
1091 |
|
|
|
1092 |
|
|
d->it_prg[d->last_buffer][d->last_used_cmd[d->last_buffer]].end.branchAddress = 0;
|
1093 |
|
|
|
1094 |
|
|
spin_unlock_irqrestore(&d->lock,flags);
|
1095 |
|
|
|
1096 |
|
|
if (!(reg_read(ohci, d->ctrlSet) & 0x8000))
|
1097 |
|
|
{
|
1098 |
|
|
DBGMSG(ohci->host->id, "Starting iso transmit DMA ctx=%d",
|
1099 |
|
|
d->ctx);
|
1100 |
|
|
put_timestamp(ohci, d, d->last_buffer);
|
1101 |
|
|
dma_region_sync_for_device(&d->dma,
|
1102 |
|
|
v.buffer * d->buf_size, d->buf_size);
|
1103 |
|
|
|
1104 |
|
|
/* Tell the controller where the first program is */
|
1105 |
|
|
reg_write(ohci, d->cmdPtr,
|
1106 |
|
|
dma_prog_region_offset_to_bus(&d->prg_reg[next_prg], 0) | 0x3);
|
1107 |
|
|
|
1108 |
|
|
/* Run IT context */
|
1109 |
|
|
reg_write(ohci, d->ctrlSet, 0x8000);
|
1110 |
|
|
}
|
1111 |
|
|
else {
|
1112 |
|
|
/* Wake up dma context if necessary */
|
1113 |
|
|
if (!(reg_read(ohci, d->ctrlSet) & 0x400)) {
|
1114 |
|
|
DBGMSG(ohci->host->id,
|
1115 |
|
|
"Waking up iso transmit dma ctx=%d",
|
1116 |
|
|
d->ctx);
|
1117 |
|
|
put_timestamp(ohci, d, d->last_buffer);
|
1118 |
|
|
dma_region_sync_for_device(&d->dma,
|
1119 |
|
|
v.buffer * d->buf_size, d->buf_size);
|
1120 |
|
|
|
1121 |
|
|
reg_write(ohci, d->ctrlSet, 0x1000);
|
1122 |
|
|
}
|
1123 |
|
|
}
|
1124 |
|
|
|
1125 |
|
|
kfree(psizes);
|
1126 |
|
|
return 0;
|
1127 |
|
|
|
1128 |
|
|
}
|
1129 |
|
|
case VIDEO1394_IOC_TALK_WAIT_BUFFER:
|
1130 |
|
|
{
|
1131 |
|
|
struct video1394_wait v;
|
1132 |
|
|
struct dma_iso_ctx *d;
|
1133 |
|
|
|
1134 |
|
|
if (copy_from_user(&v, argp, sizeof(v)))
|
1135 |
|
|
return -EFAULT;
|
1136 |
|
|
|
1137 |
|
|
d = find_ctx(&ctx->context_list, OHCI_ISO_TRANSMIT, v.channel);
|
1138 |
|
|
if (d == NULL) return -EFAULT;
|
1139 |
|
|
|
1140 |
|
|
if ((v.buffer<0) || (v.buffer>=d->num_desc-1)) {
|
1141 |
|
|
PRINT(KERN_ERR, ohci->host->id,
|
1142 |
|
|
"Buffer %d out of range",v.buffer);
|
1143 |
|
|
return -EINVAL;
|
1144 |
|
|
}
|
1145 |
|
|
|
1146 |
|
|
switch(d->buffer_status[v.buffer]) {
|
1147 |
|
|
case VIDEO1394_BUFFER_READY:
|
1148 |
|
|
d->buffer_status[v.buffer]=VIDEO1394_BUFFER_FREE;
|
1149 |
|
|
return 0;
|
1150 |
|
|
case VIDEO1394_BUFFER_QUEUED:
|
1151 |
|
|
wait_event_interruptible(d->waitq,
|
1152 |
|
|
(d->buffer_status[v.buffer] == VIDEO1394_BUFFER_READY));
|
1153 |
|
|
if (signal_pending(current))
|
1154 |
|
|
return -EINTR;
|
1155 |
|
|
d->buffer_status[v.buffer]=VIDEO1394_BUFFER_FREE;
|
1156 |
|
|
return 0;
|
1157 |
|
|
default:
|
1158 |
|
|
PRINT(KERN_ERR, ohci->host->id,
|
1159 |
|
|
"Buffer %d is not queued",v.buffer);
|
1160 |
|
|
return -ESRCH;
|
1161 |
|
|
}
|
1162 |
|
|
}
|
1163 |
|
|
default:
|
1164 |
|
|
return -ENOTTY;
|
1165 |
|
|
}
|
1166 |
|
|
}
|
1167 |
|
|
|
1168 |
|
|
/*
|
1169 |
|
|
* This maps the vmalloced and reserved buffer to user space.
|
1170 |
|
|
*
|
1171 |
|
|
* FIXME:
|
1172 |
|
|
* - PAGE_READONLY should suffice!?
|
1173 |
|
|
* - remap_pfn_range is kind of inefficient for page by page remapping.
|
1174 |
|
|
* But e.g. pte_alloc() does not work in modules ... :-(
|
1175 |
|
|
*/
|
1176 |
|
|
|
1177 |
|
|
static int video1394_mmap(struct file *file, struct vm_area_struct *vma)
|
1178 |
|
|
{
|
1179 |
|
|
struct file_ctx *ctx = (struct file_ctx *)file->private_data;
|
1180 |
|
|
|
1181 |
|
|
if (ctx->current_ctx == NULL) {
|
1182 |
|
|
PRINT(KERN_ERR, ctx->ohci->host->id,
|
1183 |
|
|
"Current iso context not set");
|
1184 |
|
|
return -EINVAL;
|
1185 |
|
|
}
|
1186 |
|
|
|
1187 |
|
|
return dma_region_mmap(&ctx->current_ctx->dma, file, vma);
|
1188 |
|
|
}
|
1189 |
|
|
|
1190 |
|
|
static unsigned int video1394_poll(struct file *file, poll_table *pt)
|
1191 |
|
|
{
|
1192 |
|
|
struct file_ctx *ctx;
|
1193 |
|
|
unsigned int mask = 0;
|
1194 |
|
|
unsigned long flags;
|
1195 |
|
|
struct dma_iso_ctx *d;
|
1196 |
|
|
int i;
|
1197 |
|
|
|
1198 |
|
|
ctx = file->private_data;
|
1199 |
|
|
d = ctx->current_ctx;
|
1200 |
|
|
if (d == NULL) {
|
1201 |
|
|
PRINT(KERN_ERR, ctx->ohci->host->id,
|
1202 |
|
|
"Current iso context not set");
|
1203 |
|
|
return POLLERR;
|
1204 |
|
|
}
|
1205 |
|
|
|
1206 |
|
|
poll_wait(file, &d->waitq, pt);
|
1207 |
|
|
|
1208 |
|
|
spin_lock_irqsave(&d->lock, flags);
|
1209 |
|
|
for (i = 0; i < d->num_desc; i++) {
|
1210 |
|
|
if (d->buffer_status[i] == VIDEO1394_BUFFER_READY) {
|
1211 |
|
|
mask |= POLLIN | POLLRDNORM;
|
1212 |
|
|
break;
|
1213 |
|
|
}
|
1214 |
|
|
}
|
1215 |
|
|
spin_unlock_irqrestore(&d->lock, flags);
|
1216 |
|
|
|
1217 |
|
|
return mask;
|
1218 |
|
|
}
|
1219 |
|
|
|
1220 |
|
|
static int video1394_open(struct inode *inode, struct file *file)
|
1221 |
|
|
{
|
1222 |
|
|
int i = ieee1394_file_to_instance(file);
|
1223 |
|
|
struct ti_ohci *ohci;
|
1224 |
|
|
struct file_ctx *ctx;
|
1225 |
|
|
|
1226 |
|
|
ohci = hpsb_get_hostinfo_bykey(&video1394_highlevel, i);
|
1227 |
|
|
if (ohci == NULL)
|
1228 |
|
|
return -EIO;
|
1229 |
|
|
|
1230 |
|
|
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
|
1231 |
|
|
if (!ctx) {
|
1232 |
|
|
PRINT(KERN_ERR, ohci->host->id, "Cannot malloc file_ctx");
|
1233 |
|
|
return -ENOMEM;
|
1234 |
|
|
}
|
1235 |
|
|
|
1236 |
|
|
ctx->ohci = ohci;
|
1237 |
|
|
INIT_LIST_HEAD(&ctx->context_list);
|
1238 |
|
|
ctx->current_ctx = NULL;
|
1239 |
|
|
file->private_data = ctx;
|
1240 |
|
|
|
1241 |
|
|
return 0;
|
1242 |
|
|
}
|
1243 |
|
|
|
1244 |
|
|
static int video1394_release(struct inode *inode, struct file *file)
|
1245 |
|
|
{
|
1246 |
|
|
struct file_ctx *ctx = (struct file_ctx *)file->private_data;
|
1247 |
|
|
struct ti_ohci *ohci = ctx->ohci;
|
1248 |
|
|
struct list_head *lh, *next;
|
1249 |
|
|
u64 mask;
|
1250 |
|
|
|
1251 |
|
|
list_for_each_safe(lh, next, &ctx->context_list) {
|
1252 |
|
|
struct dma_iso_ctx *d;
|
1253 |
|
|
d = list_entry(lh, struct dma_iso_ctx, link);
|
1254 |
|
|
mask = (u64) 1 << d->channel;
|
1255 |
|
|
|
1256 |
|
|
if (!(ohci->ISO_channel_usage & mask))
|
1257 |
|
|
PRINT(KERN_ERR, ohci->host->id, "On release: Channel %d "
|
1258 |
|
|
"is not being used", d->channel);
|
1259 |
|
|
else
|
1260 |
|
|
ohci->ISO_channel_usage &= ~mask;
|
1261 |
|
|
DBGMSG(ohci->host->id, "On release: Iso %s context "
|
1262 |
|
|
"%d stop listening on channel %d",
|
1263 |
|
|
d->type == OHCI_ISO_RECEIVE ? "receive" : "transmit",
|
1264 |
|
|
d->ctx, d->channel);
|
1265 |
|
|
free_dma_iso_ctx(d);
|
1266 |
|
|
}
|
1267 |
|
|
|
1268 |
|
|
kfree(ctx);
|
1269 |
|
|
file->private_data = NULL;
|
1270 |
|
|
|
1271 |
|
|
return 0;
|
1272 |
|
|
}
|
1273 |
|
|
|
1274 |
|
|
#ifdef CONFIG_COMPAT
|
1275 |
|
|
static long video1394_compat_ioctl(struct file *f, unsigned cmd, unsigned long arg);
|
1276 |
|
|
#endif
|
1277 |
|
|
|
1278 |
|
|
static struct cdev video1394_cdev;
|
1279 |
|
|
static const struct file_operations video1394_fops=
|
1280 |
|
|
{
|
1281 |
|
|
.owner = THIS_MODULE,
|
1282 |
|
|
.unlocked_ioctl = video1394_ioctl,
|
1283 |
|
|
#ifdef CONFIG_COMPAT
|
1284 |
|
|
.compat_ioctl = video1394_compat_ioctl,
|
1285 |
|
|
#endif
|
1286 |
|
|
.poll = video1394_poll,
|
1287 |
|
|
.mmap = video1394_mmap,
|
1288 |
|
|
.open = video1394_open,
|
1289 |
|
|
.release = video1394_release
|
1290 |
|
|
};
|
1291 |
|
|
|
1292 |
|
|
/*** HOTPLUG STUFF **********************************************************/
|
1293 |
|
|
/*
|
1294 |
|
|
* Export information about protocols/devices supported by this driver.
|
1295 |
|
|
*/
|
1296 |
|
|
static struct ieee1394_device_id video1394_id_table[] = {
|
1297 |
|
|
{
|
1298 |
|
|
.match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
|
1299 |
|
|
.specifier_id = CAMERA_UNIT_SPEC_ID_ENTRY & 0xffffff,
|
1300 |
|
|
.version = CAMERA_SW_VERSION_ENTRY & 0xffffff
|
1301 |
|
|
},
|
1302 |
|
|
{
|
1303 |
|
|
.match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
|
1304 |
|
|
.specifier_id = CAMERA_UNIT_SPEC_ID_ENTRY & 0xffffff,
|
1305 |
|
|
.version = (CAMERA_SW_VERSION_ENTRY + 1) & 0xffffff
|
1306 |
|
|
},
|
1307 |
|
|
{
|
1308 |
|
|
.match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
|
1309 |
|
|
.specifier_id = CAMERA_UNIT_SPEC_ID_ENTRY & 0xffffff,
|
1310 |
|
|
.version = (CAMERA_SW_VERSION_ENTRY + 2) & 0xffffff
|
1311 |
|
|
},
|
1312 |
|
|
{ }
|
1313 |
|
|
};
|
1314 |
|
|
|
1315 |
|
|
MODULE_DEVICE_TABLE(ieee1394, video1394_id_table);
|
1316 |
|
|
|
1317 |
|
|
static struct hpsb_protocol_driver video1394_driver = {
|
1318 |
|
|
.name = VIDEO1394_DRIVER_NAME,
|
1319 |
|
|
.id_table = video1394_id_table,
|
1320 |
|
|
};
|
1321 |
|
|
|
1322 |
|
|
|
1323 |
|
|
static void video1394_add_host (struct hpsb_host *host)
|
1324 |
|
|
{
|
1325 |
|
|
struct ti_ohci *ohci;
|
1326 |
|
|
int minor;
|
1327 |
|
|
|
1328 |
|
|
/* We only work with the OHCI-1394 driver */
|
1329 |
|
|
if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME))
|
1330 |
|
|
return;
|
1331 |
|
|
|
1332 |
|
|
ohci = (struct ti_ohci *)host->hostdata;
|
1333 |
|
|
|
1334 |
|
|
if (!hpsb_create_hostinfo(&video1394_highlevel, host, 0)) {
|
1335 |
|
|
PRINT(KERN_ERR, ohci->host->id, "Cannot allocate hostinfo");
|
1336 |
|
|
return;
|
1337 |
|
|
}
|
1338 |
|
|
|
1339 |
|
|
hpsb_set_hostinfo(&video1394_highlevel, host, ohci);
|
1340 |
|
|
hpsb_set_hostinfo_key(&video1394_highlevel, host, ohci->host->id);
|
1341 |
|
|
|
1342 |
|
|
minor = IEEE1394_MINOR_BLOCK_VIDEO1394 * 16 + ohci->host->id;
|
1343 |
|
|
device_create(hpsb_protocol_class, NULL,
|
1344 |
|
|
MKDEV(IEEE1394_MAJOR, minor),
|
1345 |
|
|
"%s-%d", VIDEO1394_DRIVER_NAME, ohci->host->id);
|
1346 |
|
|
}
|
1347 |
|
|
|
1348 |
|
|
|
1349 |
|
|
static void video1394_remove_host (struct hpsb_host *host)
|
1350 |
|
|
{
|
1351 |
|
|
struct ti_ohci *ohci = hpsb_get_hostinfo(&video1394_highlevel, host);
|
1352 |
|
|
|
1353 |
|
|
if (ohci)
|
1354 |
|
|
device_destroy(hpsb_protocol_class, MKDEV(IEEE1394_MAJOR,
|
1355 |
|
|
IEEE1394_MINOR_BLOCK_VIDEO1394 * 16 + ohci->host->id));
|
1356 |
|
|
return;
|
1357 |
|
|
}
|
1358 |
|
|
|
1359 |
|
|
|
1360 |
|
|
static struct hpsb_highlevel video1394_highlevel = {
|
1361 |
|
|
.name = VIDEO1394_DRIVER_NAME,
|
1362 |
|
|
.add_host = video1394_add_host,
|
1363 |
|
|
.remove_host = video1394_remove_host,
|
1364 |
|
|
};
|
1365 |
|
|
|
1366 |
|
|
MODULE_AUTHOR("Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>");
|
1367 |
|
|
MODULE_DESCRIPTION("driver for digital video on OHCI board");
|
1368 |
|
|
MODULE_SUPPORTED_DEVICE(VIDEO1394_DRIVER_NAME);
|
1369 |
|
|
MODULE_LICENSE("GPL");
|
1370 |
|
|
|
1371 |
|
|
#ifdef CONFIG_COMPAT
|
1372 |
|
|
|
1373 |
|
|
#define VIDEO1394_IOC32_LISTEN_QUEUE_BUFFER \
|
1374 |
|
|
_IOW ('#', 0x12, struct video1394_wait32)
|
1375 |
|
|
#define VIDEO1394_IOC32_LISTEN_WAIT_BUFFER \
|
1376 |
|
|
_IOWR('#', 0x13, struct video1394_wait32)
|
1377 |
|
|
#define VIDEO1394_IOC32_TALK_WAIT_BUFFER \
|
1378 |
|
|
_IOW ('#', 0x17, struct video1394_wait32)
|
1379 |
|
|
#define VIDEO1394_IOC32_LISTEN_POLL_BUFFER \
|
1380 |
|
|
_IOWR('#', 0x18, struct video1394_wait32)
|
1381 |
|
|
|
1382 |
|
|
struct video1394_wait32 {
|
1383 |
|
|
u32 channel;
|
1384 |
|
|
u32 buffer;
|
1385 |
|
|
struct compat_timeval filltime;
|
1386 |
|
|
};
|
1387 |
|
|
|
1388 |
|
|
static int video1394_wr_wait32(struct file *file, unsigned int cmd, unsigned long arg)
|
1389 |
|
|
{
|
1390 |
|
|
struct video1394_wait32 __user *argp = (void __user *)arg;
|
1391 |
|
|
struct video1394_wait32 wait32;
|
1392 |
|
|
struct video1394_wait wait;
|
1393 |
|
|
mm_segment_t old_fs;
|
1394 |
|
|
int ret;
|
1395 |
|
|
|
1396 |
|
|
if (copy_from_user(&wait32, argp, sizeof(wait32)))
|
1397 |
|
|
return -EFAULT;
|
1398 |
|
|
|
1399 |
|
|
wait.channel = wait32.channel;
|
1400 |
|
|
wait.buffer = wait32.buffer;
|
1401 |
|
|
wait.filltime.tv_sec = (time_t)wait32.filltime.tv_sec;
|
1402 |
|
|
wait.filltime.tv_usec = (suseconds_t)wait32.filltime.tv_usec;
|
1403 |
|
|
|
1404 |
|
|
old_fs = get_fs();
|
1405 |
|
|
set_fs(KERNEL_DS);
|
1406 |
|
|
if (cmd == VIDEO1394_IOC32_LISTEN_WAIT_BUFFER)
|
1407 |
|
|
ret = video1394_ioctl(file,
|
1408 |
|
|
VIDEO1394_IOC_LISTEN_WAIT_BUFFER,
|
1409 |
|
|
(unsigned long) &wait);
|
1410 |
|
|
else
|
1411 |
|
|
ret = video1394_ioctl(file,
|
1412 |
|
|
VIDEO1394_IOC_LISTEN_POLL_BUFFER,
|
1413 |
|
|
(unsigned long) &wait);
|
1414 |
|
|
set_fs(old_fs);
|
1415 |
|
|
|
1416 |
|
|
if (!ret) {
|
1417 |
|
|
wait32.channel = wait.channel;
|
1418 |
|
|
wait32.buffer = wait.buffer;
|
1419 |
|
|
wait32.filltime.tv_sec = (int)wait.filltime.tv_sec;
|
1420 |
|
|
wait32.filltime.tv_usec = (int)wait.filltime.tv_usec;
|
1421 |
|
|
|
1422 |
|
|
if (copy_to_user(argp, &wait32, sizeof(wait32)))
|
1423 |
|
|
ret = -EFAULT;
|
1424 |
|
|
}
|
1425 |
|
|
|
1426 |
|
|
return ret;
|
1427 |
|
|
}
|
1428 |
|
|
|
1429 |
|
|
static int video1394_w_wait32(struct file *file, unsigned int cmd, unsigned long arg)
|
1430 |
|
|
{
|
1431 |
|
|
struct video1394_wait32 wait32;
|
1432 |
|
|
struct video1394_wait wait;
|
1433 |
|
|
mm_segment_t old_fs;
|
1434 |
|
|
int ret;
|
1435 |
|
|
|
1436 |
|
|
if (copy_from_user(&wait32, (void __user *)arg, sizeof(wait32)))
|
1437 |
|
|
return -EFAULT;
|
1438 |
|
|
|
1439 |
|
|
wait.channel = wait32.channel;
|
1440 |
|
|
wait.buffer = wait32.buffer;
|
1441 |
|
|
wait.filltime.tv_sec = (time_t)wait32.filltime.tv_sec;
|
1442 |
|
|
wait.filltime.tv_usec = (suseconds_t)wait32.filltime.tv_usec;
|
1443 |
|
|
|
1444 |
|
|
old_fs = get_fs();
|
1445 |
|
|
set_fs(KERNEL_DS);
|
1446 |
|
|
if (cmd == VIDEO1394_IOC32_LISTEN_QUEUE_BUFFER)
|
1447 |
|
|
ret = video1394_ioctl(file,
|
1448 |
|
|
VIDEO1394_IOC_LISTEN_QUEUE_BUFFER,
|
1449 |
|
|
(unsigned long) &wait);
|
1450 |
|
|
else
|
1451 |
|
|
ret = video1394_ioctl(file,
|
1452 |
|
|
VIDEO1394_IOC_TALK_WAIT_BUFFER,
|
1453 |
|
|
(unsigned long) &wait);
|
1454 |
|
|
set_fs(old_fs);
|
1455 |
|
|
|
1456 |
|
|
return ret;
|
1457 |
|
|
}
|
1458 |
|
|
|
1459 |
|
|
static int video1394_queue_buf32(struct file *file, unsigned int cmd, unsigned long arg)
|
1460 |
|
|
{
|
1461 |
|
|
return -EFAULT; /* ??? was there before. */
|
1462 |
|
|
|
1463 |
|
|
return video1394_ioctl(file,
|
1464 |
|
|
VIDEO1394_IOC_TALK_QUEUE_BUFFER, arg);
|
1465 |
|
|
}
|
1466 |
|
|
|
1467 |
|
|
static long video1394_compat_ioctl(struct file *f, unsigned cmd, unsigned long arg)
|
1468 |
|
|
{
|
1469 |
|
|
switch (cmd) {
|
1470 |
|
|
case VIDEO1394_IOC_LISTEN_CHANNEL:
|
1471 |
|
|
case VIDEO1394_IOC_UNLISTEN_CHANNEL:
|
1472 |
|
|
case VIDEO1394_IOC_TALK_CHANNEL:
|
1473 |
|
|
case VIDEO1394_IOC_UNTALK_CHANNEL:
|
1474 |
|
|
return video1394_ioctl(f, cmd, arg);
|
1475 |
|
|
|
1476 |
|
|
case VIDEO1394_IOC32_LISTEN_QUEUE_BUFFER:
|
1477 |
|
|
return video1394_w_wait32(f, cmd, arg);
|
1478 |
|
|
case VIDEO1394_IOC32_LISTEN_WAIT_BUFFER:
|
1479 |
|
|
return video1394_wr_wait32(f, cmd, arg);
|
1480 |
|
|
case VIDEO1394_IOC_TALK_QUEUE_BUFFER:
|
1481 |
|
|
return video1394_queue_buf32(f, cmd, arg);
|
1482 |
|
|
case VIDEO1394_IOC32_TALK_WAIT_BUFFER:
|
1483 |
|
|
return video1394_w_wait32(f, cmd, arg);
|
1484 |
|
|
case VIDEO1394_IOC32_LISTEN_POLL_BUFFER:
|
1485 |
|
|
return video1394_wr_wait32(f, cmd, arg);
|
1486 |
|
|
default:
|
1487 |
|
|
return -ENOIOCTLCMD;
|
1488 |
|
|
}
|
1489 |
|
|
}
|
1490 |
|
|
|
1491 |
|
|
#endif /* CONFIG_COMPAT */
|
1492 |
|
|
|
1493 |
|
|
static void __exit video1394_exit_module (void)
|
1494 |
|
|
{
|
1495 |
|
|
hpsb_unregister_protocol(&video1394_driver);
|
1496 |
|
|
hpsb_unregister_highlevel(&video1394_highlevel);
|
1497 |
|
|
cdev_del(&video1394_cdev);
|
1498 |
|
|
PRINT_G(KERN_INFO, "Removed " VIDEO1394_DRIVER_NAME " module");
|
1499 |
|
|
}
|
1500 |
|
|
|
1501 |
|
|
static int __init video1394_init_module (void)
|
1502 |
|
|
{
|
1503 |
|
|
int ret;
|
1504 |
|
|
|
1505 |
|
|
cdev_init(&video1394_cdev, &video1394_fops);
|
1506 |
|
|
video1394_cdev.owner = THIS_MODULE;
|
1507 |
|
|
kobject_set_name(&video1394_cdev.kobj, VIDEO1394_DRIVER_NAME);
|
1508 |
|
|
ret = cdev_add(&video1394_cdev, IEEE1394_VIDEO1394_DEV, 16);
|
1509 |
|
|
if (ret) {
|
1510 |
|
|
PRINT_G(KERN_ERR, "video1394: unable to get minor device block");
|
1511 |
|
|
return ret;
|
1512 |
|
|
}
|
1513 |
|
|
|
1514 |
|
|
hpsb_register_highlevel(&video1394_highlevel);
|
1515 |
|
|
|
1516 |
|
|
ret = hpsb_register_protocol(&video1394_driver);
|
1517 |
|
|
if (ret) {
|
1518 |
|
|
PRINT_G(KERN_ERR, "video1394: failed to register protocol");
|
1519 |
|
|
hpsb_unregister_highlevel(&video1394_highlevel);
|
1520 |
|
|
cdev_del(&video1394_cdev);
|
1521 |
|
|
return ret;
|
1522 |
|
|
}
|
1523 |
|
|
|
1524 |
|
|
PRINT_G(KERN_INFO, "Installed " VIDEO1394_DRIVER_NAME " module");
|
1525 |
|
|
return 0;
|
1526 |
|
|
}
|
1527 |
|
|
|
1528 |
|
|
|
1529 |
|
|
module_init(video1394_init_module);
|
1530 |
|
|
module_exit(video1394_exit_module);
|