diff options
Diffstat (limited to 'drivers/staging/dt3155v4l')
-rw-r--r-- | drivers/staging/dt3155v4l/Kconfig | 28 | ||||
-rw-r--r-- | drivers/staging/dt3155v4l/Makefile | 1 | ||||
-rw-r--r-- | drivers/staging/dt3155v4l/dt3155v4l.c | 1055 | ||||
-rw-r--r-- | drivers/staging/dt3155v4l/dt3155v4l.h | 214 |
4 files changed, 1298 insertions, 0 deletions
diff --git a/drivers/staging/dt3155v4l/Kconfig b/drivers/staging/dt3155v4l/Kconfig new file mode 100644 index 00000000000..226a1ca90b3 --- /dev/null +++ b/drivers/staging/dt3155v4l/Kconfig | |||
@@ -0,0 +1,28 @@ | |||
1 | config VIDEO_DT3155 | ||
2 | tristate "DT3155 frame grabber, Video4Linux interface" | ||
3 | depends on PCI && VIDEO_DEV && VIDEO_V4L2 | ||
4 | select VIDEOBUF2_DMA_CONTIG | ||
5 | default n | ||
6 | ---help--- | ||
7 | Enables dt3155 device driver for the DataTranslation DT3155 frame grabber. | ||
8 | Say Y here if you have this hardware. | ||
9 | In doubt, say N. | ||
10 | |||
11 | To compile this driver as a module, choose M here: the | ||
12 | module will be called dt3155v4l. | ||
13 | |||
14 | config DT3155_CCIR | ||
15 | bool "Selects CCIR/50Hz vertical refresh" | ||
16 | depends on VIDEO_DT3155 | ||
17 | default y | ||
18 | ---help--- | ||
19 | Select it for CCIR/50Hz (European region), | ||
20 | or leave it unselected for RS-170/60Hz (North America). | ||
21 | |||
22 | config DT3155_STREAMING | ||
23 | bool "Selects streaming capture method" | ||
24 | depends on VIDEO_DT3155 | ||
25 | default y | ||
26 | ---help--- | ||
27 | Select it if you want to use streaming of memory mapped buffers | ||
28 | or leave it unselected if you want to use read method (one copy more). | ||
diff --git a/drivers/staging/dt3155v4l/Makefile b/drivers/staging/dt3155v4l/Makefile new file mode 100644 index 00000000000..ce7a3ec2faf --- /dev/null +++ b/drivers/staging/dt3155v4l/Makefile | |||
@@ -0,0 +1 @@ | |||
obj-$(CONFIG_VIDEO_DT3155) += dt3155v4l.o | |||
diff --git a/drivers/staging/dt3155v4l/dt3155v4l.c b/drivers/staging/dt3155v4l/dt3155v4l.c new file mode 100644 index 00000000000..05aa41cf875 --- /dev/null +++ b/drivers/staging/dt3155v4l/dt3155v4l.c | |||
@@ -0,0 +1,1055 @@ | |||
1 | /*************************************************************************** | ||
2 | * Copyright (C) 2006-2010 by Marin Mitov * | ||
3 | * mitov@issp.bas.bg * | ||
4 | * * | ||
5 | * This program is free software; you can redistribute it and/or modify * | ||
6 | * it under the terms of the GNU General Public License as published by * | ||
7 | * the Free Software Foundation; either version 2 of the License, or * | ||
8 | * (at your option) any later version. * | ||
9 | * * | ||
10 | * This program is distributed in the hope that it will be useful, * | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
13 | * GNU General Public License for more details. * | ||
14 | * * | ||
15 | * You should have received a copy of the GNU General Public License * | ||
16 | * along with this program; if not, write to the * | ||
17 | * Free Software Foundation, Inc., * | ||
18 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * | ||
19 | ***************************************************************************/ | ||
20 | |||
21 | #include <linux/version.h> | ||
22 | #include <linux/stringify.h> | ||
23 | #include <linux/delay.h> | ||
24 | #include <linux/kthread.h> | ||
25 | #include <linux/slab.h> | ||
26 | #include <media/v4l2-dev.h> | ||
27 | #include <media/v4l2-ioctl.h> | ||
28 | #include <media/videobuf2-dma-contig.h> | ||
29 | |||
30 | #include "dt3155v4l.h" | ||
31 | |||
32 | #define DT3155_VENDOR_ID 0x8086 | ||
33 | #define DT3155_DEVICE_ID 0x1223 | ||
34 | |||
35 | /* DT3155_CHUNK_SIZE is 4M (2^22) 8 full size buffers */ | ||
36 | #define DT3155_CHUNK_SIZE (1U << 22) | ||
37 | |||
38 | #define DT3155_COH_FLAGS (GFP_KERNEL | GFP_DMA32 | __GFP_COLD | __GFP_NOWARN) | ||
39 | |||
40 | #define DT3155_BUF_SIZE (768 * 576) | ||
41 | |||
42 | #ifdef CONFIG_DT3155_STREAMING | ||
43 | #define DT3155_CAPTURE_METHOD V4L2_CAP_STREAMING | ||
44 | #else | ||
45 | #define DT3155_CAPTURE_METHOD V4L2_CAP_READWRITE | ||
46 | #endif | ||
47 | |||
48 | /* global initializers (for all boards) */ | ||
49 | #ifdef CONFIG_DT3155_CCIR | ||
50 | static const u8 csr2_init = VT_50HZ; | ||
51 | #define DT3155_CURRENT_NORM V4L2_STD_625_50 | ||
52 | static const unsigned int img_width = 768; | ||
53 | static const unsigned int img_height = 576; | ||
54 | static const unsigned int frames_per_sec = 25; | ||
55 | static const struct v4l2_fmtdesc frame_std[] = { | ||
56 | { | ||
57 | .index = 0, | ||
58 | .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, | ||
59 | .flags = 0, | ||
60 | .description = "CCIR/50Hz 8 bits gray", | ||
61 | .pixelformat = V4L2_PIX_FMT_GREY, | ||
62 | }, | ||
63 | }; | ||
64 | #else | ||
65 | static const u8 csr2_init = VT_60HZ; | ||
66 | #define DT3155_CURRENT_NORM V4L2_STD_525_60 | ||
67 | static const unsigned int img_width = 640; | ||
68 | static const unsigned int img_height = 480; | ||
69 | static const unsigned int frames_per_sec = 30; | ||
70 | static const struct v4l2_fmtdesc frame_std[] = { | ||
71 | { | ||
72 | .index = 0, | ||
73 | .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, | ||
74 | .flags = 0, | ||
75 | .description = "RS-170/60Hz 8 bits gray", | ||
76 | .pixelformat = V4L2_PIX_FMT_GREY, | ||
77 | }, | ||
78 | }; | ||
79 | #endif | ||
80 | |||
81 | #define NUM_OF_FORMATS ARRAY_SIZE(frame_std) | ||
82 | |||
83 | static u8 config_init = ACQ_MODE_EVEN; | ||
84 | |||
85 | /** | ||
86 | * read_i2c_reg - reads an internal i2c register | ||
87 | * | ||
88 | * @addr: dt3155 mmio base address | ||
89 | * @index: index (internal address) of register to read | ||
90 | * @data: pointer to byte the read data will be placed in | ||
91 | * | ||
92 | * returns: zero on success or error code | ||
93 | * | ||
94 | * This function starts reading the specified (by index) register | ||
95 | * and busy waits for the process to finish. The result is placed | ||
96 | * in a byte pointed by data. | ||
97 | */ | ||
98 | static int | ||
99 | read_i2c_reg(void __iomem *addr, u8 index, u8 *data) | ||
100 | { | ||
101 | u32 tmp = index; | ||
102 | |||
103 | iowrite32((tmp<<17) | IIC_READ, addr + IIC_CSR2); | ||
104 | mmiowb(); | ||
105 | udelay(45); /* wait at least 43 usec for NEW_CYCLE to clear */ | ||
106 | if (ioread32(addr + IIC_CSR2) & NEW_CYCLE) { | ||
107 | /* error: NEW_CYCLE not cleared */ | ||
108 | printk(KERN_ERR "dt3155: NEW_CYCLE not cleared\n"); | ||
109 | return -EIO; | ||
110 | } | ||
111 | tmp = ioread32(addr + IIC_CSR1); | ||
112 | if (tmp & DIRECT_ABORT) { | ||
113 | /* error: DIRECT_ABORT set */ | ||
114 | printk(KERN_ERR "dt3155: DIRECT_ABORT set\n"); | ||
115 | /* reset DIRECT_ABORT bit */ | ||
116 | iowrite32(DIRECT_ABORT, addr + IIC_CSR1); | ||
117 | return -EIO; | ||
118 | } | ||
119 | *data = tmp>>24; | ||
120 | return 0; | ||
121 | } | ||
122 | |||
123 | /** | ||
124 | * write_i2c_reg - writes to an internal i2c register | ||
125 | * | ||
126 | * @addr: dt3155 mmio base address | ||
127 | * @index: index (internal address) of register to read | ||
128 | * @data: data to be written | ||
129 | * | ||
130 | * returns: zero on success or error code | ||
131 | * | ||
132 | * This function starts writting the specified (by index) register | ||
133 | * and busy waits for the process to finish. | ||
134 | */ | ||
135 | static int | ||
136 | write_i2c_reg(void __iomem *addr, u8 index, u8 data) | ||
137 | { | ||
138 | u32 tmp = index; | ||
139 | |||
140 | iowrite32((tmp<<17) | IIC_WRITE | data, addr + IIC_CSR2); | ||
141 | mmiowb(); | ||
142 | udelay(65); /* wait at least 63 usec for NEW_CYCLE to clear */ | ||
143 | if (ioread32(addr + IIC_CSR2) & NEW_CYCLE) { | ||
144 | /* error: NEW_CYCLE not cleared */ | ||
145 | printk(KERN_ERR "dt3155: NEW_CYCLE not cleared\n"); | ||
146 | return -EIO; | ||
147 | } | ||
148 | if (ioread32(addr + IIC_CSR1) & DIRECT_ABORT) { | ||
149 | /* error: DIRECT_ABORT set */ | ||
150 | printk(KERN_ERR "dt3155: DIRECT_ABORT set\n"); | ||
151 | /* reset DIRECT_ABORT bit */ | ||
152 | iowrite32(DIRECT_ABORT, addr + IIC_CSR1); | ||
153 | return -EIO; | ||
154 | } | ||
155 | return 0; | ||
156 | } | ||
157 | |||
158 | /** | ||
159 | * write_i2c_reg_nowait - writes to an internal i2c register | ||
160 | * | ||
161 | * @addr: dt3155 mmio base address | ||
162 | * @index: index (internal address) of register to read | ||
163 | * @data: data to be written | ||
164 | * | ||
165 | * This function starts writting the specified (by index) register | ||
166 | * and then returns. | ||
167 | */ | ||
168 | static void write_i2c_reg_nowait(void __iomem *addr, u8 index, u8 data) | ||
169 | { | ||
170 | u32 tmp = index; | ||
171 | |||
172 | iowrite32((tmp<<17) | IIC_WRITE | data, addr + IIC_CSR2); | ||
173 | mmiowb(); | ||
174 | } | ||
175 | |||
176 | /** | ||
177 | * wait_i2c_reg - waits the read/write to finish | ||
178 | * | ||
179 | * @addr: dt3155 mmio base address | ||
180 | * | ||
181 | * returns: zero on success or error code | ||
182 | * | ||
183 | * This function waits reading/writting to finish. | ||
184 | */ | ||
185 | static int wait_i2c_reg(void __iomem *addr) | ||
186 | { | ||
187 | if (ioread32(addr + IIC_CSR2) & NEW_CYCLE) | ||
188 | udelay(65); /* wait at least 63 usec for NEW_CYCLE to clear */ | ||
189 | if (ioread32(addr + IIC_CSR2) & NEW_CYCLE) { | ||
190 | /* error: NEW_CYCLE not cleared */ | ||
191 | printk(KERN_ERR "dt3155: NEW_CYCLE not cleared\n"); | ||
192 | return -EIO; | ||
193 | } | ||
194 | if (ioread32(addr + IIC_CSR1) & DIRECT_ABORT) { | ||
195 | /* error: DIRECT_ABORT set */ | ||
196 | printk(KERN_ERR "dt3155: DIRECT_ABORT set\n"); | ||
197 | /* reset DIRECT_ABORT bit */ | ||
198 | iowrite32(DIRECT_ABORT, addr + IIC_CSR1); | ||
199 | return -EIO; | ||
200 | } | ||
201 | return 0; | ||
202 | } | ||
203 | |||
204 | static int | ||
205 | dt3155_start_acq(struct dt3155_priv *pd) | ||
206 | { | ||
207 | struct vb2_buffer *vb = pd->curr_buf; | ||
208 | dma_addr_t dma_addr; | ||
209 | |||
210 | dma_addr = vb2_dma_contig_plane_paddr(vb, 0); | ||
211 | iowrite32(dma_addr, pd->regs + EVEN_DMA_START); | ||
212 | iowrite32(dma_addr + img_width, pd->regs + ODD_DMA_START); | ||
213 | iowrite32(img_width, pd->regs + EVEN_DMA_STRIDE); | ||
214 | iowrite32(img_width, pd->regs + ODD_DMA_STRIDE); | ||
215 | /* enable interrupts, clear all irq flags */ | ||
216 | iowrite32(FLD_START_EN | FLD_END_ODD_EN | FLD_START | | ||
217 | FLD_END_EVEN | FLD_END_ODD, pd->regs + INT_CSR); | ||
218 | iowrite32(FIFO_EN | SRST | FLD_CRPT_ODD | FLD_CRPT_EVEN | | ||
219 | FLD_DN_ODD | FLD_DN_EVEN | CAP_CONT_EVEN | CAP_CONT_ODD, | ||
220 | pd->regs + CSR1); | ||
221 | wait_i2c_reg(pd->regs); | ||
222 | write_i2c_reg(pd->regs, CONFIG, pd->config); | ||
223 | write_i2c_reg(pd->regs, EVEN_CSR, CSR_ERROR | CSR_DONE); | ||
224 | write_i2c_reg(pd->regs, ODD_CSR, CSR_ERROR | CSR_DONE); | ||
225 | |||
226 | /* start the board */ | ||
227 | write_i2c_reg(pd->regs, CSR2, pd->csr2 | BUSY_EVEN | BUSY_ODD); | ||
228 | return 0; /* success */ | ||
229 | } | ||
230 | |||
231 | /* | ||
232 | * driver-specific callbacks (vb2_ops) | ||
233 | */ | ||
234 | static int | ||
235 | dt3155_queue_setup(struct vb2_queue *q, unsigned int *num_buffers, | ||
236 | unsigned int *num_planes, unsigned long sizes[], | ||
237 | void *alloc_ctxs[]) | ||
238 | { | ||
239 | struct dt3155_priv *pd = vb2_get_drv_priv(q); | ||
240 | void *ret; | ||
241 | |||
242 | if (*num_buffers == 0) | ||
243 | *num_buffers = 1; | ||
244 | *num_planes = 1; | ||
245 | sizes[0] = img_width * img_height; | ||
246 | if (pd->q->alloc_ctx[0]) | ||
247 | return 0; | ||
248 | ret = vb2_dma_contig_init_ctx(&pd->pdev->dev); | ||
249 | if (IS_ERR(ret)) | ||
250 | return PTR_ERR(ret); | ||
251 | pd->q->alloc_ctx[0] = ret; | ||
252 | return 0; | ||
253 | } | ||
254 | |||
255 | static void | ||
256 | dt3155_wait_prepare(struct vb2_queue *q) | ||
257 | { | ||
258 | struct dt3155_priv *pd = vb2_get_drv_priv(q); | ||
259 | |||
260 | mutex_unlock(pd->vdev->lock); | ||
261 | } | ||
262 | |||
263 | static void | ||
264 | dt3155_wait_finish(struct vb2_queue *q) | ||
265 | { | ||
266 | struct dt3155_priv *pd = vb2_get_drv_priv(q); | ||
267 | |||
268 | mutex_lock(pd->vdev->lock); | ||
269 | } | ||
270 | |||
271 | static int | ||
272 | dt3155_buf_prepare(struct vb2_buffer *vb) | ||
273 | { | ||
274 | vb2_set_plane_payload(vb, 0, img_width * img_height); | ||
275 | return 0; | ||
276 | } | ||
277 | |||
278 | static int | ||
279 | dt3155_start_streaming(struct vb2_queue *q) | ||
280 | { | ||
281 | return 0; | ||
282 | } | ||
283 | |||
284 | static int | ||
285 | dt3155_stop_streaming(struct vb2_queue *q) | ||
286 | { | ||
287 | struct dt3155_priv *pd = vb2_get_drv_priv(q); | ||
288 | struct vb2_buffer *vb; | ||
289 | |||
290 | spin_lock_irq(&pd->lock); | ||
291 | while (!list_empty(&pd->dmaq)) { | ||
292 | vb = list_first_entry(&pd->dmaq, typeof(*vb), done_entry); | ||
293 | list_del(&vb->done_entry); | ||
294 | vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); | ||
295 | } | ||
296 | spin_unlock_irq(&pd->lock); | ||
297 | msleep(45); /* irq hendler will stop the hardware */ | ||
298 | return 0; | ||
299 | } | ||
300 | |||
301 | static void | ||
302 | dt3155_buf_queue(struct vb2_buffer *vb) | ||
303 | { | ||
304 | struct dt3155_priv *pd = vb2_get_drv_priv(vb->vb2_queue); | ||
305 | |||
306 | /* pd->q->streaming = 1 when dt3155_buf_queue() is invoked */ | ||
307 | spin_lock_irq(&pd->lock); | ||
308 | if (pd->curr_buf) | ||
309 | list_add_tail(&vb->done_entry, &pd->dmaq); | ||
310 | else { | ||
311 | pd->curr_buf = vb; | ||
312 | dt3155_start_acq(pd); | ||
313 | } | ||
314 | spin_unlock_irq(&pd->lock); | ||
315 | } | ||
316 | /* | ||
317 | * end driver-specific callbacks | ||
318 | */ | ||
319 | |||
320 | const struct vb2_ops q_ops = { | ||
321 | .queue_setup = dt3155_queue_setup, | ||
322 | .wait_prepare = dt3155_wait_prepare, | ||
323 | .wait_finish = dt3155_wait_finish, | ||
324 | .buf_prepare = dt3155_buf_prepare, | ||
325 | .start_streaming = dt3155_start_streaming, | ||
326 | .stop_streaming = dt3155_stop_streaming, | ||
327 | .buf_queue = dt3155_buf_queue, | ||
328 | }; | ||
329 | |||
330 | static irqreturn_t | ||
331 | dt3155_irq_handler_even(int irq, void *dev_id) | ||
332 | { | ||
333 | struct dt3155_priv *ipd = dev_id; | ||
334 | struct vb2_buffer *ivb; | ||
335 | dma_addr_t dma_addr; | ||
336 | u32 tmp; | ||
337 | |||
338 | tmp = ioread32(ipd->regs + INT_CSR) & (FLD_START | FLD_END_ODD); | ||
339 | if (!tmp) | ||
340 | return IRQ_NONE; /* not our irq */ | ||
341 | if ((tmp & FLD_START) && !(tmp & FLD_END_ODD)) { | ||
342 | iowrite32(FLD_START_EN | FLD_END_ODD_EN | FLD_START, | ||
343 | ipd->regs + INT_CSR); | ||
344 | ipd->field_count++; | ||
345 | return IRQ_HANDLED; /* start of field irq */ | ||
346 | } | ||
347 | if ((tmp & FLD_START) && (tmp & FLD_END_ODD)) { | ||
348 | if (!ipd->stats.start_before_end++) | ||
349 | printk(KERN_ERR "dt3155: irq: START before END\n"); | ||
350 | } | ||
351 | /* check for corrupted fields */ | ||
352 | /* write_i2c_reg(ipd->regs, EVEN_CSR, CSR_ERROR | CSR_DONE); */ | ||
353 | /* write_i2c_reg(ipd->regs, ODD_CSR, CSR_ERROR | CSR_DONE); */ | ||
354 | tmp = ioread32(ipd->regs + CSR1) & (FLD_CRPT_EVEN | FLD_CRPT_ODD); | ||
355 | if (tmp) { | ||
356 | if (!ipd->stats.corrupted_fields++) | ||
357 | printk(KERN_ERR "dt3155: corrupted field %u\n", tmp); | ||
358 | iowrite32(FIFO_EN | SRST | FLD_CRPT_ODD | FLD_CRPT_EVEN | | ||
359 | FLD_DN_ODD | FLD_DN_EVEN | | ||
360 | CAP_CONT_EVEN | CAP_CONT_ODD, | ||
361 | ipd->regs + CSR1); | ||
362 | mmiowb(); | ||
363 | } | ||
364 | |||
365 | spin_lock(&ipd->lock); | ||
366 | if (ipd->curr_buf) { | ||
367 | do_gettimeofday(&ipd->curr_buf->v4l2_buf.timestamp); | ||
368 | ipd->curr_buf->v4l2_buf.sequence = (ipd->field_count) >> 1; | ||
369 | vb2_buffer_done(ipd->curr_buf, VB2_BUF_STATE_DONE); | ||
370 | } | ||
371 | |||
372 | if (!ipd->q->streaming || list_empty(&ipd->dmaq)) | ||
373 | goto stop_dma; | ||
374 | ivb = list_first_entry(&ipd->dmaq, typeof(*ivb), done_entry); | ||
375 | list_del(&ivb->done_entry); | ||
376 | ipd->curr_buf = ivb; | ||
377 | dma_addr = vb2_dma_contig_plane_paddr(ivb, 0); | ||
378 | iowrite32(dma_addr, ipd->regs + EVEN_DMA_START); | ||
379 | iowrite32(dma_addr + img_width, ipd->regs + ODD_DMA_START); | ||
380 | iowrite32(img_width, ipd->regs + EVEN_DMA_STRIDE); | ||
381 | iowrite32(img_width, ipd->regs + ODD_DMA_STRIDE); | ||
382 | mmiowb(); | ||
383 | /* enable interrupts, clear all irq flags */ | ||
384 | iowrite32(FLD_START_EN | FLD_END_ODD_EN | FLD_START | | ||
385 | FLD_END_EVEN | FLD_END_ODD, ipd->regs + INT_CSR); | ||
386 | spin_unlock(&ipd->lock); | ||
387 | return IRQ_HANDLED; | ||
388 | |||
389 | stop_dma: | ||
390 | ipd->curr_buf = NULL; | ||
391 | /* stop the board */ | ||
392 | write_i2c_reg_nowait(ipd->regs, CSR2, ipd->csr2); | ||
393 | iowrite32(FIFO_EN | SRST | FLD_CRPT_ODD | FLD_CRPT_EVEN | | ||
394 | FLD_DN_ODD | FLD_DN_EVEN, ipd->regs + CSR1); | ||
395 | /* disable interrupts, clear all irq flags */ | ||
396 | iowrite32(FLD_START | FLD_END_EVEN | FLD_END_ODD, ipd->regs + INT_CSR); | ||
397 | spin_unlock(&ipd->lock); | ||
398 | return IRQ_HANDLED; | ||
399 | } | ||
400 | |||
401 | static int | ||
402 | dt3155_open(struct file *filp) | ||
403 | { | ||
404 | int ret = 0; | ||
405 | struct dt3155_priv *pd = video_drvdata(filp); | ||
406 | |||
407 | printk(KERN_INFO "dt3155: open(): minor: %i, users: %i\n", | ||
408 | pd->vdev->minor, pd->users); | ||
409 | |||
410 | if (!pd->users) { | ||
411 | pd->q = kzalloc(sizeof(*pd->q), GFP_KERNEL); | ||
412 | if (!pd->q) { | ||
413 | printk(KERN_ERR "dt3155: error: alloc queue\n"); | ||
414 | ret = -ENOMEM; | ||
415 | goto err_alloc_queue; | ||
416 | } | ||
417 | pd->q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
418 | pd->q->io_modes = VB2_READ | VB2_MMAP; | ||
419 | pd->q->ops = &q_ops; | ||
420 | pd->q->mem_ops = &vb2_dma_contig_memops; | ||
421 | pd->q->drv_priv = pd; | ||
422 | pd->curr_buf = NULL; | ||
423 | pd->field_count = 0; | ||
424 | vb2_queue_init(pd->q); /* cannot fail */ | ||
425 | INIT_LIST_HEAD(&pd->dmaq); | ||
426 | spin_lock_init(&pd->lock); | ||
427 | /* disable all irqs, clear all irq flags */ | ||
428 | iowrite32(FLD_START | FLD_END_EVEN | FLD_END_ODD, | ||
429 | pd->regs + INT_CSR); | ||
430 | pd->irq_handler = dt3155_irq_handler_even; | ||
431 | ret = request_irq(pd->pdev->irq, pd->irq_handler, | ||
432 | IRQF_SHARED, DT3155_NAME, pd); | ||
433 | if (ret) { | ||
434 | printk(KERN_ERR "dt3155: error: request_irq\n"); | ||
435 | goto err_request_irq; | ||
436 | } | ||
437 | } | ||
438 | pd->users++; | ||
439 | return 0; /* success */ | ||
440 | err_request_irq: | ||
441 | kfree(pd->q); | ||
442 | pd->q = NULL; | ||
443 | err_alloc_queue: | ||
444 | return ret; | ||
445 | } | ||
446 | |||
447 | static int | ||
448 | dt3155_release(struct file *filp) | ||
449 | { | ||
450 | struct dt3155_priv *pd = video_drvdata(filp); | ||
451 | |||
452 | printk(KERN_INFO "dt3155: release(): minor: %i, users: %i\n", | ||
453 | pd->vdev->minor, pd->users - 1); | ||
454 | |||
455 | pd->users--; | ||
456 | BUG_ON(pd->users < 0); | ||
457 | if (!pd->users) { | ||
458 | vb2_queue_release(pd->q); | ||
459 | free_irq(pd->pdev->irq, pd); | ||
460 | if (pd->q->alloc_ctx[0]) | ||
461 | vb2_dma_contig_cleanup_ctx(pd->q->alloc_ctx[0]); | ||
462 | kfree(pd->q); | ||
463 | pd->q = NULL; | ||
464 | } | ||
465 | return 0; | ||
466 | } | ||
467 | |||
468 | static ssize_t | ||
469 | dt3155_read(struct file *filp, char __user *user, size_t size, loff_t *loff) | ||
470 | { | ||
471 | struct dt3155_priv *pd = video_drvdata(filp); | ||
472 | |||
473 | return vb2_read(pd->q, user, size, loff, filp->f_flags & O_NONBLOCK); | ||
474 | } | ||
475 | |||
476 | static unsigned int | ||
477 | dt3155_poll(struct file *filp, struct poll_table_struct *polltbl) | ||
478 | { | ||
479 | struct dt3155_priv *pd = video_drvdata(filp); | ||
480 | |||
481 | return vb2_poll(pd->q, filp, polltbl); | ||
482 | } | ||
483 | |||
484 | static int | ||
485 | dt3155_mmap(struct file *filp, struct vm_area_struct *vma) | ||
486 | { | ||
487 | struct dt3155_priv *pd = video_drvdata(filp); | ||
488 | |||
489 | return vb2_mmap(pd->q, vma); | ||
490 | } | ||
491 | |||
492 | static const struct v4l2_file_operations dt3155_fops = { | ||
493 | .owner = THIS_MODULE, | ||
494 | .open = dt3155_open, | ||
495 | .release = dt3155_release, | ||
496 | .read = dt3155_read, | ||
497 | .poll = dt3155_poll, | ||
498 | .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */ | ||
499 | .mmap = dt3155_mmap, | ||
500 | }; | ||
501 | |||
502 | static int | ||
503 | dt3155_ioc_streamon(struct file *filp, void *p, enum v4l2_buf_type type) | ||
504 | { | ||
505 | struct dt3155_priv *pd = video_drvdata(filp); | ||
506 | |||
507 | return vb2_streamon(pd->q, type); | ||
508 | } | ||
509 | |||
510 | static int | ||
511 | dt3155_ioc_streamoff(struct file *filp, void *p, enum v4l2_buf_type type) | ||
512 | { | ||
513 | struct dt3155_priv *pd = video_drvdata(filp); | ||
514 | |||
515 | return vb2_streamoff(pd->q, type); | ||
516 | } | ||
517 | |||
518 | static int | ||
519 | dt3155_ioc_querycap(struct file *filp, void *p, struct v4l2_capability *cap) | ||
520 | { | ||
521 | struct dt3155_priv *pd = video_drvdata(filp); | ||
522 | |||
523 | strcpy(cap->driver, DT3155_NAME); | ||
524 | strcpy(cap->card, DT3155_NAME " frame grabber"); | ||
525 | sprintf(cap->bus_info, "PCI:%s", pci_name(pd->pdev)); | ||
526 | cap->version = | ||
527 | KERNEL_VERSION(DT3155_VER_MAJ, DT3155_VER_MIN, DT3155_VER_EXT); | ||
528 | cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | | ||
529 | DT3155_CAPTURE_METHOD; | ||
530 | return 0; | ||
531 | } | ||
532 | |||
533 | static int | ||
534 | dt3155_ioc_enum_fmt_vid_cap(struct file *filp, void *p, struct v4l2_fmtdesc *f) | ||
535 | { | ||
536 | if (f->index >= NUM_OF_FORMATS) | ||
537 | return -EINVAL; | ||
538 | *f = frame_std[f->index]; | ||
539 | return 0; | ||
540 | } | ||
541 | |||
542 | static int | ||
543 | dt3155_ioc_g_fmt_vid_cap(struct file *filp, void *p, struct v4l2_format *f) | ||
544 | { | ||
545 | if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
546 | return -EINVAL; | ||
547 | f->fmt.pix.width = img_width; | ||
548 | f->fmt.pix.height = img_height; | ||
549 | f->fmt.pix.pixelformat = V4L2_PIX_FMT_GREY; | ||
550 | f->fmt.pix.field = V4L2_FIELD_NONE; | ||
551 | f->fmt.pix.bytesperline = f->fmt.pix.width; | ||
552 | f->fmt.pix.sizeimage = f->fmt.pix.width * f->fmt.pix.height; | ||
553 | f->fmt.pix.colorspace = 0; | ||
554 | f->fmt.pix.priv = 0; | ||
555 | return 0; | ||
556 | } | ||
557 | |||
558 | static int | ||
559 | dt3155_ioc_try_fmt_vid_cap(struct file *filp, void *p, struct v4l2_format *f) | ||
560 | { | ||
561 | if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
562 | return -EINVAL; | ||
563 | if (f->fmt.pix.width == img_width && | ||
564 | f->fmt.pix.height == img_height && | ||
565 | f->fmt.pix.pixelformat == V4L2_PIX_FMT_GREY && | ||
566 | f->fmt.pix.field == V4L2_FIELD_NONE && | ||
567 | f->fmt.pix.bytesperline == f->fmt.pix.width && | ||
568 | f->fmt.pix.sizeimage == f->fmt.pix.width * f->fmt.pix.height) | ||
569 | return 0; | ||
570 | else | ||
571 | return -EINVAL; | ||
572 | } | ||
573 | |||
574 | static int | ||
575 | dt3155_ioc_s_fmt_vid_cap(struct file *filp, void *p, struct v4l2_format *f) | ||
576 | { | ||
577 | return dt3155_ioc_g_fmt_vid_cap(filp, p, f); | ||
578 | } | ||
579 | |||
580 | static int | ||
581 | dt3155_ioc_reqbufs(struct file *filp, void *p, struct v4l2_requestbuffers *b) | ||
582 | { | ||
583 | struct dt3155_priv *pd = video_drvdata(filp); | ||
584 | |||
585 | return vb2_reqbufs(pd->q, b); | ||
586 | } | ||
587 | |||
588 | static int | ||
589 | dt3155_ioc_querybuf(struct file *filp, void *p, struct v4l2_buffer *b) | ||
590 | { | ||
591 | struct dt3155_priv *pd = video_drvdata(filp); | ||
592 | |||
593 | return vb2_querybuf(pd->q, b); | ||
594 | } | ||
595 | |||
596 | static int | ||
597 | dt3155_ioc_qbuf(struct file *filp, void *p, struct v4l2_buffer *b) | ||
598 | { | ||
599 | struct dt3155_priv *pd = video_drvdata(filp); | ||
600 | |||
601 | return vb2_qbuf(pd->q, b); | ||
602 | } | ||
603 | |||
604 | static int | ||
605 | dt3155_ioc_dqbuf(struct file *filp, void *p, struct v4l2_buffer *b) | ||
606 | { | ||
607 | struct dt3155_priv *pd = video_drvdata(filp); | ||
608 | |||
609 | return vb2_dqbuf(pd->q, b, filp->f_flags & O_NONBLOCK); | ||
610 | } | ||
611 | |||
612 | static int | ||
613 | dt3155_ioc_querystd(struct file *filp, void *p, v4l2_std_id *norm) | ||
614 | { | ||
615 | *norm = DT3155_CURRENT_NORM; | ||
616 | return 0; | ||
617 | } | ||
618 | |||
619 | static int | ||
620 | dt3155_ioc_g_std(struct file *filp, void *p, v4l2_std_id *norm) | ||
621 | { | ||
622 | *norm = DT3155_CURRENT_NORM; | ||
623 | return 0; | ||
624 | } | ||
625 | |||
626 | static int | ||
627 | dt3155_ioc_s_std(struct file *filp, void *p, v4l2_std_id *norm) | ||
628 | { | ||
629 | if (*norm & DT3155_CURRENT_NORM) | ||
630 | return 0; | ||
631 | return -EINVAL; | ||
632 | } | ||
633 | |||
634 | static int | ||
635 | dt3155_ioc_enum_input(struct file *filp, void *p, struct v4l2_input *input) | ||
636 | { | ||
637 | if (input->index) | ||
638 | return -EINVAL; | ||
639 | strcpy(input->name, "Coax in"); | ||
640 | input->type = V4L2_INPUT_TYPE_CAMERA; | ||
641 | /* | ||
642 | * FIXME: input->std = 0 according to v4l2 API | ||
643 | * VIDIOC_G_STD, VIDIOC_S_STD, VIDIOC_QUERYSTD and VIDIOC_ENUMSTD | ||
644 | * should return -EINVAL | ||
645 | */ | ||
646 | input->std = DT3155_CURRENT_NORM; | ||
647 | input->status = 0;/* FIXME: add sync detection & V4L2_IN_ST_NO_H_LOCK */ | ||
648 | return 0; | ||
649 | } | ||
650 | |||
651 | static int | ||
652 | dt3155_ioc_g_input(struct file *filp, void *p, unsigned int *i) | ||
653 | { | ||
654 | *i = 0; | ||
655 | return 0; | ||
656 | } | ||
657 | |||
658 | static int | ||
659 | dt3155_ioc_s_input(struct file *filp, void *p, unsigned int i) | ||
660 | { | ||
661 | if (i) | ||
662 | return -EINVAL; | ||
663 | return 0; | ||
664 | } | ||
665 | |||
666 | static int | ||
667 | dt3155_ioc_g_parm(struct file *filp, void *p, struct v4l2_streamparm *parms) | ||
668 | { | ||
669 | if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
670 | return -EINVAL; | ||
671 | parms->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; | ||
672 | parms->parm.capture.capturemode = 0; | ||
673 | parms->parm.capture.timeperframe.numerator = 1001; | ||
674 | parms->parm.capture.timeperframe.denominator = frames_per_sec * 1000; | ||
675 | parms->parm.capture.extendedmode = 0; | ||
676 | parms->parm.capture.readbuffers = 1; /* FIXME: 2 buffers? */ | ||
677 | return 0; | ||
678 | } | ||
679 | |||
680 | static int | ||
681 | dt3155_ioc_s_parm(struct file *filp, void *p, struct v4l2_streamparm *parms) | ||
682 | { | ||
683 | if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
684 | return -EINVAL; | ||
685 | parms->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; | ||
686 | parms->parm.capture.capturemode = 0; | ||
687 | parms->parm.capture.timeperframe.numerator = 1001; | ||
688 | parms->parm.capture.timeperframe.denominator = frames_per_sec * 1000; | ||
689 | parms->parm.capture.extendedmode = 0; | ||
690 | parms->parm.capture.readbuffers = 1; /* FIXME: 2 buffers? */ | ||
691 | return 0; | ||
692 | } | ||
693 | |||
694 | static const struct v4l2_ioctl_ops dt3155_ioctl_ops = { | ||
695 | .vidioc_streamon = dt3155_ioc_streamon, | ||
696 | .vidioc_streamoff = dt3155_ioc_streamoff, | ||
697 | .vidioc_querycap = dt3155_ioc_querycap, | ||
698 | /* | ||
699 | .vidioc_g_priority = dt3155_ioc_g_priority, | ||
700 | .vidioc_s_priority = dt3155_ioc_s_priority, | ||
701 | */ | ||
702 | .vidioc_enum_fmt_vid_cap = dt3155_ioc_enum_fmt_vid_cap, | ||
703 | .vidioc_try_fmt_vid_cap = dt3155_ioc_try_fmt_vid_cap, | ||
704 | .vidioc_g_fmt_vid_cap = dt3155_ioc_g_fmt_vid_cap, | ||
705 | .vidioc_s_fmt_vid_cap = dt3155_ioc_s_fmt_vid_cap, | ||
706 | .vidioc_reqbufs = dt3155_ioc_reqbufs, | ||
707 | .vidioc_querybuf = dt3155_ioc_querybuf, | ||
708 | .vidioc_qbuf = dt3155_ioc_qbuf, | ||
709 | .vidioc_dqbuf = dt3155_ioc_dqbuf, | ||
710 | .vidioc_querystd = dt3155_ioc_querystd, | ||
711 | .vidioc_g_std = dt3155_ioc_g_std, | ||
712 | .vidioc_s_std = dt3155_ioc_s_std, | ||
713 | .vidioc_enum_input = dt3155_ioc_enum_input, | ||
714 | .vidioc_g_input = dt3155_ioc_g_input, | ||
715 | .vidioc_s_input = dt3155_ioc_s_input, | ||
716 | /* | ||
717 | .vidioc_queryctrl = dt3155_ioc_queryctrl, | ||
718 | .vidioc_g_ctrl = dt3155_ioc_g_ctrl, | ||
719 | .vidioc_s_ctrl = dt3155_ioc_s_ctrl, | ||
720 | .vidioc_querymenu = dt3155_ioc_querymenu, | ||
721 | .vidioc_g_ext_ctrls = dt3155_ioc_g_ext_ctrls, | ||
722 | .vidioc_s_ext_ctrls = dt3155_ioc_s_ext_ctrls, | ||
723 | */ | ||
724 | .vidioc_g_parm = dt3155_ioc_g_parm, | ||
725 | .vidioc_s_parm = dt3155_ioc_s_parm, | ||
726 | /* | ||
727 | .vidioc_cropcap = dt3155_ioc_cropcap, | ||
728 | .vidioc_g_crop = dt3155_ioc_g_crop, | ||
729 | .vidioc_s_crop = dt3155_ioc_s_crop, | ||
730 | .vidioc_enum_framesizes = dt3155_ioc_enum_framesizes, | ||
731 | .vidioc_enum_frameintervals = dt3155_ioc_enum_frameintervals, | ||
732 | */ | ||
733 | }; | ||
734 | |||
735 | static int __devinit | ||
736 | dt3155_init_board(struct pci_dev *pdev) | ||
737 | { | ||
738 | struct dt3155_priv *pd = pci_get_drvdata(pdev); | ||
739 | void *buf_cpu; | ||
740 | dma_addr_t buf_dma; | ||
741 | int i; | ||
742 | u8 tmp; | ||
743 | |||
744 | pci_set_master(pdev); /* dt3155 needs it */ | ||
745 | |||
746 | /* resetting the adapter */ | ||
747 | iowrite32(FLD_CRPT_ODD | FLD_CRPT_EVEN | FLD_DN_ODD | FLD_DN_EVEN, | ||
748 | pd->regs + CSR1); | ||
749 | mmiowb(); | ||
750 | msleep(20); | ||
751 | |||
752 | /* initializing adaper registers */ | ||
753 | iowrite32(FIFO_EN | SRST, pd->regs + CSR1); | ||
754 | mmiowb(); | ||
755 | iowrite32(0xEEEEEE01, pd->regs + EVEN_PIXEL_FMT); | ||
756 | iowrite32(0xEEEEEE01, pd->regs + ODD_PIXEL_FMT); | ||
757 | iowrite32(0x00000020, pd->regs + FIFO_TRIGER); | ||
758 | iowrite32(0x00000103, pd->regs + XFER_MODE); | ||
759 | iowrite32(0, pd->regs + RETRY_WAIT_CNT); | ||
760 | iowrite32(0, pd->regs + INT_CSR); | ||
761 | iowrite32(1, pd->regs + EVEN_FLD_MASK); | ||
762 | iowrite32(1, pd->regs + ODD_FLD_MASK); | ||
763 | iowrite32(0, pd->regs + MASK_LENGTH); | ||
764 | iowrite32(0x0005007C, pd->regs + FIFO_FLAG_CNT); | ||
765 | iowrite32(0x01010101, pd->regs + IIC_CLK_DUR); | ||
766 | mmiowb(); | ||
767 | |||
768 | /* verifying that we have a DT3155 board (not just a SAA7116 chip) */ | ||
769 | read_i2c_reg(pd->regs, DT_ID, &tmp); | ||
770 | if (tmp != DT3155_ID) | ||
771 | return -ENODEV; | ||
772 | |||
773 | /* initialize AD LUT */ | ||
774 | write_i2c_reg(pd->regs, AD_ADDR, 0); | ||
775 | for (i = 0; i < 256; i++) | ||
776 | write_i2c_reg(pd->regs, AD_LUT, i); | ||
777 | |||
778 | /* initialize ADC references */ | ||
779 | /* FIXME: pos_ref & neg_ref depend on VT_50HZ */ | ||
780 | write_i2c_reg(pd->regs, AD_ADDR, AD_CMD_REG); | ||
781 | write_i2c_reg(pd->regs, AD_CMD, VIDEO_CNL_1 | SYNC_CNL_1 | SYNC_LVL_3); | ||
782 | write_i2c_reg(pd->regs, AD_ADDR, AD_POS_REF); | ||
783 | write_i2c_reg(pd->regs, AD_CMD, 34); | ||
784 | write_i2c_reg(pd->regs, AD_ADDR, AD_NEG_REF); | ||
785 | write_i2c_reg(pd->regs, AD_CMD, 0); | ||
786 | |||
787 | /* initialize PM LUT */ | ||
788 | write_i2c_reg(pd->regs, CONFIG, pd->config | PM_LUT_PGM); | ||
789 | for (i = 0; i < 256; i++) { | ||
790 | write_i2c_reg(pd->regs, PM_LUT_ADDR, i); | ||
791 | write_i2c_reg(pd->regs, PM_LUT_DATA, i); | ||
792 | } | ||
793 | write_i2c_reg(pd->regs, CONFIG, pd->config | PM_LUT_PGM | PM_LUT_SEL); | ||
794 | for (i = 0; i < 256; i++) { | ||
795 | write_i2c_reg(pd->regs, PM_LUT_ADDR, i); | ||
796 | write_i2c_reg(pd->regs, PM_LUT_DATA, i); | ||
797 | } | ||
798 | write_i2c_reg(pd->regs, CONFIG, pd->config); /* ACQ_MODE_EVEN */ | ||
799 | |||
800 | /* select chanel 1 for input and set sync level */ | ||
801 | write_i2c_reg(pd->regs, AD_ADDR, AD_CMD_REG); | ||
802 | write_i2c_reg(pd->regs, AD_CMD, VIDEO_CNL_1 | SYNC_CNL_1 | SYNC_LVL_3); | ||
803 | |||
804 | /* allocate memory, and initialize the DMA machine */ | ||
805 | buf_cpu = dma_alloc_coherent(&pdev->dev, DT3155_BUF_SIZE, &buf_dma, | ||
806 | GFP_KERNEL); | ||
807 | if (!buf_cpu) { | ||
808 | printk(KERN_ERR "dt3155: dma_alloc_coherent " | ||
809 | "(in dt3155_init_board) failed\n"); | ||
810 | return -ENOMEM; | ||
811 | } | ||
812 | iowrite32(buf_dma, pd->regs + EVEN_DMA_START); | ||
813 | iowrite32(buf_dma, pd->regs + ODD_DMA_START); | ||
814 | iowrite32(0, pd->regs + EVEN_DMA_STRIDE); | ||
815 | iowrite32(0, pd->regs + ODD_DMA_STRIDE); | ||
816 | |||
817 | /* Perform a pseudo even field acquire */ | ||
818 | iowrite32(FIFO_EN | SRST | CAP_CONT_ODD, pd->regs + CSR1); | ||
819 | write_i2c_reg(pd->regs, CSR2, pd->csr2 | SYNC_SNTL); | ||
820 | write_i2c_reg(pd->regs, CONFIG, pd->config); | ||
821 | write_i2c_reg(pd->regs, EVEN_CSR, CSR_SNGL); | ||
822 | write_i2c_reg(pd->regs, CSR2, pd->csr2 | BUSY_EVEN | SYNC_SNTL); | ||
823 | msleep(100); | ||
824 | read_i2c_reg(pd->regs, CSR2, &tmp); | ||
825 | write_i2c_reg(pd->regs, EVEN_CSR, CSR_ERROR | CSR_SNGL | CSR_DONE); | ||
826 | write_i2c_reg(pd->regs, ODD_CSR, CSR_ERROR | CSR_SNGL | CSR_DONE); | ||
827 | write_i2c_reg(pd->regs, CSR2, pd->csr2); | ||
828 | iowrite32(FIFO_EN | SRST | FLD_DN_EVEN | FLD_DN_ODD, pd->regs + CSR1); | ||
829 | |||
830 | /* deallocate memory */ | ||
831 | dma_free_coherent(&pdev->dev, DT3155_BUF_SIZE, buf_cpu, buf_dma); | ||
832 | if (tmp & BUSY_EVEN) { | ||
833 | printk(KERN_ERR "dt3155: BUSY_EVEN not cleared\n"); | ||
834 | return -EIO; | ||
835 | } | ||
836 | return 0; | ||
837 | } | ||
838 | |||
839 | static struct video_device dt3155_vdev = { | ||
840 | .name = DT3155_NAME, | ||
841 | .fops = &dt3155_fops, | ||
842 | .ioctl_ops = &dt3155_ioctl_ops, | ||
843 | .minor = -1, | ||
844 | .release = video_device_release, | ||
845 | .tvnorms = DT3155_CURRENT_NORM, | ||
846 | .current_norm = DT3155_CURRENT_NORM, | ||
847 | }; | ||
848 | |||
849 | /* same as in drivers/base/dma-coherent.c */ | ||
850 | struct dma_coherent_mem { | ||
851 | void *virt_base; | ||
852 | dma_addr_t device_base; | ||
853 | int size; | ||
854 | int flags; | ||
855 | unsigned long *bitmap; | ||
856 | }; | ||
857 | |||
858 | static int __devinit | ||
859 | dt3155_alloc_coherent(struct device *dev, size_t size, int flags) | ||
860 | { | ||
861 | struct dma_coherent_mem *mem; | ||
862 | dma_addr_t dev_base; | ||
863 | int pages = size >> PAGE_SHIFT; | ||
864 | int bitmap_size = BITS_TO_LONGS(pages) * sizeof(long); | ||
865 | |||
866 | if ((flags & DMA_MEMORY_MAP) == 0) | ||
867 | goto out; | ||
868 | if (!size) | ||
869 | goto out; | ||
870 | if (dev->dma_mem) | ||
871 | goto out; | ||
872 | |||
873 | mem = kzalloc(sizeof(*mem), GFP_KERNEL); | ||
874 | if (!mem) | ||
875 | goto out; | ||
876 | mem->virt_base = dma_alloc_coherent(dev, size, &dev_base, | ||
877 | DT3155_COH_FLAGS); | ||
878 | if (!mem->virt_base) | ||
879 | goto err_alloc_coherent; | ||
880 | mem->bitmap = kzalloc(bitmap_size, GFP_KERNEL); | ||
881 | if (!mem->bitmap) | ||
882 | goto err_bitmap; | ||
883 | |||
884 | /* coherent_dma_mask is already set to 32 bits */ | ||
885 | mem->device_base = dev_base; | ||
886 | mem->size = pages; | ||
887 | mem->flags = flags; | ||
888 | dev->dma_mem = mem; | ||
889 | return DMA_MEMORY_MAP; | ||
890 | |||
891 | err_bitmap: | ||
892 | dma_free_coherent(dev, size, mem->virt_base, dev_base); | ||
893 | err_alloc_coherent: | ||
894 | kfree(mem); | ||
895 | out: | ||
896 | return 0; | ||
897 | } | ||
898 | |||
899 | static void __devexit | ||
900 | dt3155_free_coherent(struct device *dev) | ||
901 | { | ||
902 | struct dma_coherent_mem *mem = dev->dma_mem; | ||
903 | |||
904 | if (!mem) | ||
905 | return; | ||
906 | dev->dma_mem = NULL; | ||
907 | dma_free_coherent(dev, mem->size << PAGE_SHIFT, | ||
908 | mem->virt_base, mem->device_base); | ||
909 | kfree(mem->bitmap); | ||
910 | kfree(mem); | ||
911 | } | ||
912 | |||
913 | static int __devinit | ||
914 | dt3155_probe(struct pci_dev *pdev, const struct pci_device_id *id) | ||
915 | { | ||
916 | int err; | ||
917 | struct dt3155_priv *pd; | ||
918 | |||
919 | printk(KERN_INFO "dt3155: probe()\n"); | ||
920 | err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); | ||
921 | if (err) { | ||
922 | printk(KERN_ERR "dt3155: cannot set dma_mask\n"); | ||
923 | return -ENODEV; | ||
924 | } | ||
925 | err = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); | ||
926 | if (err) { | ||
927 | printk(KERN_ERR "dt3155: cannot set dma_coherent_mask\n"); | ||
928 | return -ENODEV; | ||
929 | } | ||
930 | pd = kzalloc(sizeof(*pd), GFP_KERNEL); | ||
931 | if (!pd) { | ||
932 | printk(KERN_ERR "dt3155: cannot allocate dt3155_priv\n"); | ||
933 | return -ENOMEM; | ||
934 | } | ||
935 | pd->vdev = video_device_alloc(); | ||
936 | if (!pd->vdev) { | ||
937 | printk(KERN_ERR "dt3155: cannot allocate vdev structure\n"); | ||
938 | goto err_video_device_alloc; | ||
939 | } | ||
940 | *pd->vdev = dt3155_vdev; | ||
941 | pci_set_drvdata(pdev, pd); /* for use in dt3155_remove() */ | ||
942 | video_set_drvdata(pd->vdev, pd); /* for use in video_fops */ | ||
943 | pd->users = 0; | ||
944 | pd->pdev = pdev; | ||
945 | INIT_LIST_HEAD(&pd->dmaq); | ||
946 | mutex_init(&pd->mux); | ||
947 | pd->vdev->lock = &pd->mux; /* for locking v4l2_file_operations */ | ||
948 | spin_lock_init(&pd->lock); | ||
949 | pd->csr2 = csr2_init; | ||
950 | pd->config = config_init; | ||
951 | err = pci_enable_device(pdev); | ||
952 | if (err) { | ||
953 | printk(KERN_ERR "dt3155: pci_dev not enabled\n"); | ||
954 | goto err_enable_dev; | ||
955 | } | ||
956 | err = pci_request_region(pdev, 0, pci_name(pdev)); | ||
957 | if (err) | ||
958 | goto err_req_region; | ||
959 | pd->regs = pci_iomap(pdev, 0, pci_resource_len(pd->pdev, 0)); | ||
960 | if (!pd->regs) { | ||
961 | err = -ENOMEM; | ||
962 | printk(KERN_ERR "dt3155: pci_iomap failed\n"); | ||
963 | goto err_pci_iomap; | ||
964 | } | ||
965 | err = dt3155_init_board(pdev); | ||
966 | if (err) { | ||
967 | printk(KERN_ERR "dt3155: dt3155_init_board failed\n"); | ||
968 | goto err_init_board; | ||
969 | } | ||
970 | err = video_register_device(pd->vdev, VFL_TYPE_GRABBER, -1); | ||
971 | if (err) { | ||
972 | printk(KERN_ERR "dt3155: Cannot register video device\n"); | ||
973 | goto err_init_board; | ||
974 | } | ||
975 | err = dt3155_alloc_coherent(&pdev->dev, DT3155_CHUNK_SIZE, | ||
976 | DMA_MEMORY_MAP); | ||
977 | if (err) | ||
978 | printk(KERN_INFO "dt3155: preallocated 8 buffers\n"); | ||
979 | printk(KERN_INFO "dt3155: /dev/video%i is ready\n", pd->vdev->minor); | ||
980 | return 0; /* success */ | ||
981 | |||
982 | err_init_board: | ||
983 | pci_iounmap(pdev, pd->regs); | ||
984 | err_pci_iomap: | ||
985 | pci_release_region(pdev, 0); | ||
986 | err_req_region: | ||
987 | pci_disable_device(pdev); | ||
988 | err_enable_dev: | ||
989 | video_device_release(pd->vdev); | ||
990 | err_video_device_alloc: | ||
991 | kfree(pd); | ||
992 | return err; | ||
993 | } | ||
994 | |||
995 | static void __devexit | ||
996 | dt3155_remove(struct pci_dev *pdev) | ||
997 | { | ||
998 | struct dt3155_priv *pd = pci_get_drvdata(pdev); | ||
999 | |||
1000 | printk(KERN_INFO "dt3155: remove()\n"); | ||
1001 | dt3155_free_coherent(&pdev->dev); | ||
1002 | video_unregister_device(pd->vdev); | ||
1003 | pci_iounmap(pdev, pd->regs); | ||
1004 | pci_release_region(pdev, 0); | ||
1005 | pci_disable_device(pdev); | ||
1006 | /* | ||
1007 | * video_device_release() is invoked automatically | ||
1008 | * see: struct video_device dt3155_vdev | ||
1009 | */ | ||
1010 | kfree(pd); | ||
1011 | } | ||
1012 | |||
1013 | static DEFINE_PCI_DEVICE_TABLE(pci_ids) = { | ||
1014 | { PCI_DEVICE(DT3155_VENDOR_ID, DT3155_DEVICE_ID) }, | ||
1015 | { 0, /* zero marks the end */ }, | ||
1016 | }; | ||
1017 | MODULE_DEVICE_TABLE(pci, pci_ids); | ||
1018 | |||
1019 | static struct pci_driver pci_driver = { | ||
1020 | .name = DT3155_NAME, | ||
1021 | .id_table = pci_ids, | ||
1022 | .probe = dt3155_probe, | ||
1023 | .remove = __devexit_p(dt3155_remove), | ||
1024 | }; | ||
1025 | |||
1026 | static int __init | ||
1027 | dt3155_init_module(void) | ||
1028 | { | ||
1029 | int err; | ||
1030 | |||
1031 | printk(KERN_INFO "dt3155: ==================\n"); | ||
1032 | printk(KERN_INFO "dt3155: init()\n"); | ||
1033 | err = pci_register_driver(&pci_driver); | ||
1034 | if (err) { | ||
1035 | printk(KERN_ERR "dt3155: cannot register pci_driver\n"); | ||
1036 | return err; | ||
1037 | } | ||
1038 | return 0; /* succes */ | ||
1039 | } | ||
1040 | |||
1041 | static void __exit | ||
1042 | dt3155_exit_module(void) | ||
1043 | { | ||
1044 | pci_unregister_driver(&pci_driver); | ||
1045 | printk(KERN_INFO "dt3155: exit()\n"); | ||
1046 | printk(KERN_INFO "dt3155: ==================\n"); | ||
1047 | } | ||
1048 | |||
1049 | module_init(dt3155_init_module); | ||
1050 | module_exit(dt3155_exit_module); | ||
1051 | |||
1052 | MODULE_DESCRIPTION("video4linux pci-driver for dt3155 frame grabber"); | ||
1053 | MODULE_AUTHOR("Marin Mitov <mitov@issp.bas.bg>"); | ||
1054 | MODULE_VERSION(DT3155_VERSION); | ||
1055 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/staging/dt3155v4l/dt3155v4l.h b/drivers/staging/dt3155v4l/dt3155v4l.h new file mode 100644 index 00000000000..b0792b3d9b7 --- /dev/null +++ b/drivers/staging/dt3155v4l/dt3155v4l.h | |||
@@ -0,0 +1,214 @@ | |||
1 | /*************************************************************************** | ||
2 | * Copyright (C) 2006-2010 by Marin Mitov * | ||
3 | * mitov@issp.bas.bg * | ||
4 | * * | ||
5 | * This program is free software; you can redistribute it and/or modify * | ||
6 | * it under the terms of the GNU General Public License as published by * | ||
7 | * the Free Software Foundation; either version 2 of the License, or * | ||
8 | * (at your option) any later version. * | ||
9 | * * | ||
10 | * This program is distributed in the hope that it will be useful, * | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
13 | * GNU General Public License for more details. * | ||
14 | * * | ||
15 | * You should have received a copy of the GNU General Public License * | ||
16 | * along with this program; if not, write to the * | ||
17 | * Free Software Foundation, Inc., * | ||
18 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * | ||
19 | ***************************************************************************/ | ||
20 | |||
21 | /* DT3155 header file */ | ||
22 | #ifndef _DT3155_H_ | ||
23 | #define _DT3155_H_ | ||
24 | |||
25 | #ifdef __KERNEL__ | ||
26 | |||
27 | #include <linux/pci.h> | ||
28 | #include <linux/interrupt.h> | ||
29 | |||
30 | #define DT3155_NAME "dt3155" | ||
31 | #define DT3155_VER_MAJ 1 | ||
32 | #define DT3155_VER_MIN 1 | ||
33 | #define DT3155_VER_EXT 0 | ||
34 | #define DT3155_VERSION __stringify(DT3155_VER_MAJ) "." \ | ||
35 | __stringify(DT3155_VER_MIN) "." \ | ||
36 | __stringify(DT3155_VER_EXT) | ||
37 | |||
38 | /* DT3155 Base Register offsets (memory mapped) */ | ||
39 | #define EVEN_DMA_START 0x00 | ||
40 | #define ODD_DMA_START 0x0C | ||
41 | #define EVEN_DMA_STRIDE 0x18 | ||
42 | #define ODD_DMA_STRIDE 0x24 | ||
43 | #define EVEN_PIXEL_FMT 0x30 | ||
44 | #define ODD_PIXEL_FMT 0x34 | ||
45 | #define FIFO_TRIGER 0x38 | ||
46 | #define XFER_MODE 0x3C | ||
47 | #define CSR1 0x40 | ||
48 | #define RETRY_WAIT_CNT 0x44 | ||
49 | #define INT_CSR 0x48 | ||
50 | #define EVEN_FLD_MASK 0x4C | ||
51 | #define ODD_FLD_MASK 0x50 | ||
52 | #define MASK_LENGTH 0x54 | ||
53 | #define FIFO_FLAG_CNT 0x58 | ||
54 | #define IIC_CLK_DUR 0x5C | ||
55 | #define IIC_CSR1 0x60 | ||
56 | #define IIC_CSR2 0x64 | ||
57 | |||
58 | /* DT3155 Internal Registers indexes (i2c/IIC mapped) */ | ||
59 | #define CSR2 0x10 | ||
60 | #define EVEN_CSR 0x11 | ||
61 | #define ODD_CSR 0x12 | ||
62 | #define CONFIG 0x13 | ||
63 | #define DT_ID 0x1F | ||
64 | #define X_CLIP_START 0x20 | ||
65 | #define Y_CLIP_START 0x22 | ||
66 | #define X_CLIP_END 0x24 | ||
67 | #define Y_CLIP_END 0x26 | ||
68 | #define AD_ADDR 0x30 | ||
69 | #define AD_LUT 0x31 | ||
70 | #define AD_CMD 0x32 | ||
71 | #define DIG_OUT 0x40 | ||
72 | #define PM_LUT_ADDR 0x50 | ||
73 | #define PM_LUT_DATA 0x51 | ||
74 | |||
75 | /* AD command register values */ | ||
76 | #define AD_CMD_REG 0x00 | ||
77 | #define AD_POS_REF 0x01 | ||
78 | #define AD_NEG_REF 0x02 | ||
79 | |||
80 | /* CSR1 bit masks */ | ||
81 | #define CRPT_DIS 0x00004000 | ||
82 | #define FLD_CRPT_ODD 0x00000200 | ||
83 | #define FLD_CRPT_EVEN 0x00000100 | ||
84 | #define FIFO_EN 0x00000080 | ||
85 | #define SRST 0x00000040 | ||
86 | #define FLD_DN_ODD 0x00000020 | ||
87 | #define FLD_DN_EVEN 0x00000010 | ||
88 | /* These should not be used. | ||
89 | * Use CAP_CONT_ODD/EVEN instead | ||
90 | #define CAP_SNGL_ODD 0x00000008 | ||
91 | #define CAP_SNGL_EVEN 0x00000004 | ||
92 | */ | ||
93 | #define CAP_CONT_ODD 0x00000002 | ||
94 | #define CAP_CONT_EVEN 0x00000001 | ||
95 | |||
96 | /* INT_CSR bit masks */ | ||
97 | #define FLD_START_EN 0x00000400 | ||
98 | #define FLD_END_ODD_EN 0x00000200 | ||
99 | #define FLD_END_EVEN_EN 0x00000100 | ||
100 | #define FLD_START 0x00000004 | ||
101 | #define FLD_END_ODD 0x00000002 | ||
102 | #define FLD_END_EVEN 0x00000001 | ||
103 | |||
104 | /* IIC_CSR1 bit masks */ | ||
105 | #define DIRECT_ABORT 0x00000200 | ||
106 | |||
107 | /* IIC_CSR2 bit masks */ | ||
108 | #define NEW_CYCLE 0x01000000 | ||
109 | #define DIR_RD 0x00010000 | ||
110 | #define IIC_READ 0x01010000 | ||
111 | #define IIC_WRITE 0x01000000 | ||
112 | |||
113 | /* CSR2 bit masks */ | ||
114 | #define DISP_PASS 0x40 | ||
115 | #define BUSY_ODD 0x20 | ||
116 | #define BUSY_EVEN 0x10 | ||
117 | #define SYNC_PRESENT 0x08 | ||
118 | #define VT_50HZ 0x04 | ||
119 | #define SYNC_SNTL 0x02 | ||
120 | #define CHROM_FILT 0x01 | ||
121 | #define VT_60HZ 0x00 | ||
122 | |||
123 | /* CSR_EVEN/ODD bit masks */ | ||
124 | #define CSR_ERROR 0x04 | ||
125 | #define CSR_SNGL 0x02 | ||
126 | #define CSR_DONE 0x01 | ||
127 | |||
128 | /* CONFIG bit masks */ | ||
129 | #define PM_LUT_PGM 0x80 | ||
130 | #define PM_LUT_SEL 0x40 | ||
131 | #define CLIP_EN 0x20 | ||
132 | #define HSCALE_EN 0x10 | ||
133 | #define EXT_TRIG_UP 0x0C | ||
134 | #define EXT_TRIG_DOWN 0x04 | ||
135 | #define ACQ_MODE_NEXT 0x02 | ||
136 | #define ACQ_MODE_ODD 0x01 | ||
137 | #define ACQ_MODE_EVEN 0x00 | ||
138 | |||
139 | /* AD_CMD bit masks */ | ||
140 | #define VIDEO_CNL_1 0x00 | ||
141 | #define VIDEO_CNL_2 0x40 | ||
142 | #define VIDEO_CNL_3 0x80 | ||
143 | #define VIDEO_CNL_4 0xC0 | ||
144 | #define SYNC_CNL_1 0x00 | ||
145 | #define SYNC_CNL_2 0x10 | ||
146 | #define SYNC_CNL_3 0x20 | ||
147 | #define SYNC_CNL_4 0x30 | ||
148 | #define SYNC_LVL_1 0x00 | ||
149 | #define SYNC_LVL_2 0x04 | ||
150 | #define SYNC_LVL_3 0x08 | ||
151 | #define SYNC_LVL_4 0x0C | ||
152 | |||
153 | /* DT3155 identificator */ | ||
154 | #define DT3155_ID 0x20 | ||
155 | |||
156 | #ifdef CONFIG_DT3155_CCIR | ||
157 | #define DMA_STRIDE 768 | ||
158 | #else | ||
159 | #define DMA_STRIDE 640 | ||
160 | #endif | ||
161 | |||
162 | /** | ||
163 | * struct dt3155_stats - statistics structure | ||
164 | * | ||
165 | * @free_bufs_empty: no free image buffers | ||
166 | * @corrupted_fields: corrupted fields | ||
167 | * @dma_map_failed: dma mapping failed | ||
168 | * @start_before_end: new started before old ended | ||
169 | */ | ||
170 | struct dt3155_stats { | ||
171 | int free_bufs_empty; | ||
172 | int corrupted_fields; | ||
173 | int dma_map_failed; | ||
174 | int start_before_end; | ||
175 | }; | ||
176 | |||
177 | /* per board private data structure */ | ||
178 | /** | ||
179 | * struct dt3155_priv - private data structure | ||
180 | * | ||
181 | * @vdev: pointer to video_device structure | ||
182 | * @pdev: pointer to pci_dev structure | ||
183 | * @q pointer to vb2_queue structure | ||
184 | * @curr_buf: pointer to curren buffer | ||
185 | * @mux: mutex to protect the instance | ||
186 | * @irq_handler: irq handler for the driver | ||
187 | * @dmaq queue for dma buffers | ||
188 | * @lock spinlock for dma queue | ||
189 | * @field_count fields counter | ||
190 | * @stats: statistics structure | ||
191 | * @users open count | ||
192 | * @regs: local copy of mmio base register | ||
193 | * @csr2: local copy of csr2 register | ||
194 | * @config: local copy of config register | ||
195 | */ | ||
196 | struct dt3155_priv { | ||
197 | struct video_device *vdev; | ||
198 | struct pci_dev *pdev; | ||
199 | struct vb2_queue *q; | ||
200 | struct vb2_buffer *curr_buf; | ||
201 | struct mutex mux; | ||
202 | irq_handler_t irq_handler; | ||
203 | struct list_head dmaq; | ||
204 | spinlock_t lock; | ||
205 | unsigned int field_count; | ||
206 | struct dt3155_stats stats; | ||
207 | void *regs; | ||
208 | int users; | ||
209 | u8 csr2, config; | ||
210 | }; | ||
211 | |||
212 | #endif /* __KERNEL__ */ | ||
213 | |||
214 | #endif /* _DT3155_H_ */ | ||