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