• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6.36/drivers/staging/dt3155v4l/
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 <media/v4l2-dev.h>
26#include <media/v4l2-ioctl.h>
27#include <media/videobuf-dma-contig.h>
28
29#include "dt3155v4l.h"
30
31#define DT3155_VENDOR_ID 0x8086
32#define DT3155_DEVICE_ID 0x1223
33
34/* DT3155_CHUNK_SIZE is 4M (2^22) 8 full size buffers */
35#define DT3155_CHUNK_SIZE (1U << 22)
36
37#define DT3155_COH_FLAGS (GFP_KERNEL | GFP_DMA32 | __GFP_COLD | __GFP_NOWARN)
38
39#define DT3155_BUF_SIZE (768 * 576)
40
41/*  global initializers (for all boards)  */
42#ifdef CONFIG_DT3155_CCIR
43static const u8 csr2_init = VT_50HZ;
44#define DT3155_CURRENT_NORM V4L2_STD_625_50
45static const unsigned int img_width = 768;
46static const unsigned int img_height = 576;
47static const unsigned int frames_per_sec = 25;
48static const struct v4l2_fmtdesc frame_std[] = {
49	{
50	.index = 0,
51	.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
52	.flags = 0,
53	.description = "CCIR/50Hz 8 bits gray",
54	.pixelformat = V4L2_PIX_FMT_GREY,
55	},
56};
57#else
58static const u8 csr2_init = VT_60HZ;
59#define DT3155_CURRENT_NORM V4L2_STD_525_60
60static const unsigned int img_width = 640;
61static const unsigned int img_height = 480;
62static const unsigned int frames_per_sec = 30;
63static const struct v4l2_fmtdesc frame_std[] = {
64	{
65	.index = 0,
66	.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
67	.flags = 0,
68	.description = "RS-170/60Hz 8 bits gray",
69	.pixelformat = V4L2_PIX_FMT_GREY,
70	},
71};
72#endif
73
74#define NUM_OF_FORMATS ARRAY_SIZE(frame_std)
75
76static u8 config_init = ACQ_MODE_EVEN;
77
78/**
79 * read_i2c_reg - reads an internal i2c register
80 *
81 * @addr:	dt3155 mmio base address
82 * @index:	index (internal address) of register to read
83 * @data:	pointer to byte the read data will be placed in
84 *
85 * returns:	zero on success or error code
86 *
87 * This function starts reading the specified (by index) register
88 * and busy waits for the process to finish. The result is placed
89 * in a byte pointed by data.
90 */
91static int
92read_i2c_reg(void __iomem *addr, u8 index, u8 *data)
93{
94	u32 tmp = index;
95
96	iowrite32((tmp<<17) | IIC_READ, addr + IIC_CSR2);
97	mmiowb();
98	udelay(45); /* wait at least 43 usec for NEW_CYCLE to clear */
99	if (ioread32(addr + IIC_CSR2) & NEW_CYCLE) {
100		/* error: NEW_CYCLE not cleared */
101		printk(KERN_ERR "dt3155: NEW_CYCLE not cleared\n");
102		return -EIO;
103	}
104	tmp = ioread32(addr + IIC_CSR1);
105	if (tmp & DIRECT_ABORT) {
106		/* error: DIRECT_ABORT set */
107		printk(KERN_ERR "dt3155: DIRECT_ABORT set\n");
108		/* reset DIRECT_ABORT bit */
109		iowrite32(DIRECT_ABORT, addr + IIC_CSR1);
110		return -EIO;
111	}
112	*data = tmp>>24;
113	return 0;
114}
115
116/**
117 * write_i2c_reg - writes to an internal i2c register
118 *
119 * @addr:	dt3155 mmio base address
120 * @index:	index (internal address) of register to read
121 * @data:	data to be written
122 *
123 * returns:	zero on success or error code
124 *
125 * This function starts writting the specified (by index) register
126 * and busy waits for the process to finish.
127 */
128static int
129write_i2c_reg(void __iomem *addr, u8 index, u8 data)
130{
131	u32 tmp = index;
132
133	iowrite32((tmp<<17) | IIC_WRITE | data, addr + IIC_CSR2);
134	mmiowb();
135	udelay(65); /* wait at least 63 usec for NEW_CYCLE to clear */
136	if (ioread32(addr + IIC_CSR2) & NEW_CYCLE) {
137		/* error: NEW_CYCLE not cleared */
138		printk(KERN_ERR "dt3155: NEW_CYCLE not cleared\n");
139		return -EIO;
140	}
141	if (ioread32(addr + IIC_CSR1) & DIRECT_ABORT) {
142		/* error: DIRECT_ABORT set */
143		printk(KERN_ERR "dt3155: DIRECT_ABORT set\n");
144		/* reset DIRECT_ABORT bit */
145		iowrite32(DIRECT_ABORT, addr + IIC_CSR1);
146		return -EIO;
147	}
148	return 0;
149}
150
151/**
152 * write_i2c_reg_nowait - writes to an internal i2c register
153 *
154 * @addr:	dt3155 mmio base address
155 * @index:	index (internal address) of register to read
156 * @data:	data to be written
157 *
158 * This function starts writting the specified (by index) register
159 * and then returns.
160 */
161static void write_i2c_reg_nowait(void __iomem *addr, u8 index, u8 data)
162{
163	u32 tmp = index;
164
165	iowrite32((tmp<<17) | IIC_WRITE | data, addr + IIC_CSR2);
166	mmiowb();
167}
168
169/**
170 * wait_i2c_reg - waits the read/write to finish
171 *
172 * @addr:	dt3155 mmio base address
173 *
174 * returns:	zero on success or error code
175 *
176 * This function waits reading/writting to finish.
177 */
178static int wait_i2c_reg(void __iomem *addr)
179{
180	if (ioread32(addr + IIC_CSR2) & NEW_CYCLE)
181		udelay(65); /* wait at least 63 usec for NEW_CYCLE to clear */
182	if (ioread32(addr + IIC_CSR2) & NEW_CYCLE) {
183		/* error: NEW_CYCLE not cleared */
184		printk(KERN_ERR "dt3155: NEW_CYCLE not cleared\n");
185		return -EIO;
186	}
187	if (ioread32(addr + IIC_CSR1) & DIRECT_ABORT) {
188		/* error: DIRECT_ABORT set */
189		printk(KERN_ERR "dt3155: DIRECT_ABORT set\n");
190		/* reset DIRECT_ABORT bit */
191		iowrite32(DIRECT_ABORT, addr + IIC_CSR1);
192		return -EIO;
193	}
194	return 0;
195}
196
197static int
198dt3155_start_acq(struct dt3155_priv *pd)
199{
200	struct videobuf_buffer *vb = pd->curr_buf;
201	dma_addr_t dma_addr;
202
203	dma_addr = videobuf_to_dma_contig(vb);
204	iowrite32(dma_addr, pd->regs + EVEN_DMA_START);
205	iowrite32(dma_addr + vb->width, pd->regs + ODD_DMA_START);
206	iowrite32(vb->width, pd->regs + EVEN_DMA_STRIDE);
207	iowrite32(vb->width, pd->regs + ODD_DMA_STRIDE);
208	/* enable interrupts, clear all irq flags */
209	iowrite32(FLD_START_EN | FLD_END_ODD_EN | FLD_START |
210			FLD_END_EVEN | FLD_END_ODD, pd->regs + INT_CSR);
211	iowrite32(FIFO_EN | SRST | FLD_CRPT_ODD | FLD_CRPT_EVEN |
212		  FLD_DN_ODD | FLD_DN_EVEN | CAP_CONT_EVEN | CAP_CONT_ODD,
213							pd->regs + CSR1);
214	wait_i2c_reg(pd->regs);
215	write_i2c_reg(pd->regs, CONFIG, pd->config);
216	write_i2c_reg(pd->regs, EVEN_CSR, CSR_ERROR | CSR_DONE);
217	write_i2c_reg(pd->regs, ODD_CSR, CSR_ERROR | CSR_DONE);
218
219	/*  start the board  */
220	write_i2c_reg(pd->regs, CSR2, pd->csr2 | BUSY_EVEN | BUSY_ODD);
221	return 0; /* success  */
222}
223
224static int
225dt3155_stop_acq(struct dt3155_priv *pd)
226{
227	int tmp;
228
229	/*  stop the board  */
230	wait_i2c_reg(pd->regs);
231	write_i2c_reg(pd->regs, CSR2, pd->csr2);
232
233	/* disable all irqs, clear all irq flags */
234	iowrite32(FLD_START | FLD_END_EVEN | FLD_END_ODD, pd->regs + INT_CSR);
235	write_i2c_reg(pd->regs, EVEN_CSR, CSR_ERROR | CSR_DONE);
236	write_i2c_reg(pd->regs, ODD_CSR, CSR_ERROR | CSR_DONE);
237	tmp = ioread32(pd->regs + CSR1) & (FLD_CRPT_EVEN | FLD_CRPT_ODD);
238	if (tmp)
239		printk(KERN_ERR "dt3155: corrupted field %u\n", tmp);
240	iowrite32(FIFO_EN | SRST | FLD_CRPT_ODD | FLD_CRPT_EVEN |
241		  FLD_DN_ODD | FLD_DN_EVEN | CAP_CONT_EVEN | CAP_CONT_ODD,
242							pd->regs + CSR1);
243	return 0;
244}
245
246/* Locking: Caller holds q->vb_lock */
247static int
248dt3155_buf_setup(struct videobuf_queue *q, unsigned int *count,
249							unsigned int *size)
250{
251	*size = img_width * img_height;
252	return 0;
253}
254
255/* Locking: Caller holds q->vb_lock */
256static int
257dt3155_buf_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
258							enum v4l2_field field)
259{
260	int ret = 0;
261
262	vb->width = img_width;
263	vb->height = img_height;
264	vb->size = img_width * img_height;
265	vb->field = field;
266	if (vb->state == VIDEOBUF_NEEDS_INIT)
267		ret = videobuf_iolock(q, vb, NULL);
268	if (ret) {
269		vb->state = VIDEOBUF_ERROR;
270		printk(KERN_ERR "ERROR: videobuf_iolock() failed\n");
271		videobuf_dma_contig_free(q, vb);
272	} else
273		vb->state = VIDEOBUF_PREPARED;
274	return ret;
275}
276
277/* Locking: Caller holds q->vb_lock & q->irqlock */
278static void
279dt3155_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
280{
281	struct dt3155_priv *pd = q->priv_data;
282
283	if (vb->state != VIDEOBUF_NEEDS_INIT) {
284		vb->state = VIDEOBUF_QUEUED;
285		list_add_tail(&vb->queue, &pd->dmaq);
286		wake_up_interruptible_sync(&pd->do_dma);
287	} else
288		vb->state = VIDEOBUF_ERROR;
289}
290
291/* Locking: Caller holds q->vb_lock */
292static void
293dt3155_buf_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
294{
295	if (vb->state == VIDEOBUF_ACTIVE)
296		videobuf_waiton(vb, 0, 0);
297	videobuf_dma_contig_free(q, vb);
298	vb->state = VIDEOBUF_NEEDS_INIT;
299}
300
301static struct videobuf_queue_ops vbq_ops = {
302	.buf_setup = dt3155_buf_setup,
303	.buf_prepare = dt3155_buf_prepare,
304	.buf_queue = dt3155_buf_queue,
305	.buf_release = dt3155_buf_release,
306};
307
308static irqreturn_t
309dt3155_irq_handler_even(int irq, void *dev_id)
310{
311	struct dt3155_priv *ipd = dev_id;
312	struct videobuf_buffer *ivb;
313	dma_addr_t dma_addr;
314	u32 tmp;
315
316	tmp = ioread32(ipd->regs + INT_CSR) & (FLD_START | FLD_END_ODD);
317	if (!tmp)
318		return IRQ_NONE;  /* not our irq */
319	if ((tmp & FLD_START) && !(tmp & FLD_END_ODD)) {
320		iowrite32(FLD_START_EN | FLD_END_ODD_EN | FLD_START,
321							ipd->regs + INT_CSR);
322		ipd->field_count++;
323		return IRQ_HANDLED; /* start of field irq */
324	}
325	if ((tmp & FLD_START) && (tmp & FLD_END_ODD)) {
326		if (!ipd->stats.start_before_end++)
327			printk(KERN_ERR "dt3155: irq: START before END\n");
328	}
329	/*	check for corrupted fields     */
330/*	write_i2c_reg(ipd->regs, EVEN_CSR, CSR_ERROR | CSR_DONE);	*/
331/*	write_i2c_reg(ipd->regs, ODD_CSR, CSR_ERROR | CSR_DONE);	*/
332	tmp = ioread32(ipd->regs + CSR1) & (FLD_CRPT_EVEN | FLD_CRPT_ODD);
333	if (tmp) {
334		if (!ipd->stats.corrupted_fields++)
335			printk(KERN_ERR "dt3155: corrupted field %u\n", tmp);
336		iowrite32(FIFO_EN | SRST | FLD_CRPT_ODD | FLD_CRPT_EVEN |
337						FLD_DN_ODD | FLD_DN_EVEN |
338						CAP_CONT_EVEN | CAP_CONT_ODD,
339							ipd->regs + CSR1);
340		mmiowb();
341	}
342
343	spin_lock(&ipd->lock);
344	if (ipd->curr_buf && ipd->curr_buf->state == VIDEOBUF_ACTIVE) {
345		if (waitqueue_active(&ipd->curr_buf->done)) {
346			do_gettimeofday(&ipd->curr_buf->ts);
347			ipd->curr_buf->field_count = ipd->field_count;
348			ipd->curr_buf->state = VIDEOBUF_DONE;
349			wake_up(&ipd->curr_buf->done);
350		} else {
351			ivb = ipd->curr_buf;
352			goto load_dma;
353		}
354	} else
355		goto stop_dma;
356	if (list_empty(&ipd->dmaq))
357		goto stop_dma;
358	ivb = list_first_entry(&ipd->dmaq, typeof(*ivb), queue);
359	list_del(&ivb->queue);
360	if (ivb->state == VIDEOBUF_QUEUED) {
361		ivb->state = VIDEOBUF_ACTIVE;
362		ipd->curr_buf = ivb;
363	} else
364		goto stop_dma;
365load_dma:
366	dma_addr = videobuf_to_dma_contig(ivb);
367	iowrite32(dma_addr, ipd->regs + EVEN_DMA_START);
368	iowrite32(dma_addr + ivb->width, ipd->regs + ODD_DMA_START);
369	iowrite32(ivb->width, ipd->regs + EVEN_DMA_STRIDE);
370	iowrite32(ivb->width, ipd->regs + ODD_DMA_STRIDE);
371	mmiowb();
372	/* enable interrupts, clear all irq flags */
373	iowrite32(FLD_START_EN | FLD_END_ODD_EN | FLD_START |
374			FLD_END_EVEN | FLD_END_ODD, ipd->regs + INT_CSR);
375	spin_unlock(&ipd->lock);
376	return IRQ_HANDLED;
377
378stop_dma:
379	ipd->curr_buf = NULL;
380	/* stop the board */
381	write_i2c_reg_nowait(ipd->regs, CSR2, ipd->csr2);
382	/* disable interrupts, clear all irq flags */
383	iowrite32(FLD_START | FLD_END_EVEN | FLD_END_ODD, ipd->regs + INT_CSR);
384	spin_unlock(&ipd->lock);
385	return IRQ_HANDLED;
386}
387
388static int
389dt3155_threadfn(void *arg)
390{
391	struct dt3155_priv *pd = arg;
392	struct videobuf_buffer *vb;
393	unsigned long flags;
394
395	while (1) {
396		wait_event_interruptible(pd->do_dma,
397			kthread_should_stop() || !list_empty(&pd->dmaq));
398		if (kthread_should_stop())
399			break;
400
401		spin_lock_irqsave(&pd->lock, flags);
402		if (pd->curr_buf) /* dma is active */
403			goto done;
404		if (list_empty(&pd->dmaq)) /* no empty biffers */
405			goto done;
406		vb = list_first_entry(&pd->dmaq, typeof(*vb), queue);
407		list_del(&vb->queue);
408		if (vb->state == VIDEOBUF_QUEUED) {
409			vb->state = VIDEOBUF_ACTIVE;
410			pd->curr_buf = vb;
411			spin_unlock_irqrestore(&pd->lock, flags);
412			/* start dma */
413			dt3155_start_acq(pd);
414			continue;
415		} else
416			printk(KERN_DEBUG "%s(): This is a BUG\n", __func__);
417done:
418		spin_unlock_irqrestore(&pd->lock, flags);
419	}
420	return 0;
421}
422
423static int
424dt3155_open(struct file *filp)
425{
426	int ret = 0;
427	struct dt3155_priv *pd = video_drvdata(filp);
428
429	printk(KERN_INFO "dt3155: open(): minor: %i\n", pd->vdev->minor);
430
431	if (mutex_lock_interruptible(&pd->mux) == -EINTR)
432		return -ERESTARTSYS;
433	if (!pd->users) {
434		pd->vidq = kzalloc(sizeof(*pd->vidq), GFP_KERNEL);
435		if (!pd->vidq) {
436			printk(KERN_ERR "dt3155: error: alloc queue\n");
437			ret = -ENOMEM;
438			goto err_alloc_queue;
439		}
440		videobuf_queue_dma_contig_init(pd->vidq, &vbq_ops,
441				&pd->pdev->dev, &pd->lock,
442				V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE,
443				sizeof(struct videobuf_buffer), pd);
444		/* disable all irqs, clear all irq flags */
445		iowrite32(FLD_START | FLD_END_EVEN | FLD_END_ODD,
446						pd->regs + INT_CSR);
447		pd->irq_handler = dt3155_irq_handler_even;
448		ret = request_irq(pd->pdev->irq, pd->irq_handler,
449						IRQF_SHARED, DT3155_NAME, pd);
450		if (ret) {
451			printk(KERN_ERR "dt3155: error: request_irq\n");
452			goto err_request_irq;
453		}
454		pd->curr_buf = NULL;
455		pd->thread = kthread_run(dt3155_threadfn, pd,
456					"dt3155_thread_%i", pd->vdev->minor);
457		if (IS_ERR(pd->thread)) {
458			printk(KERN_ERR "dt3155: kthread_run() failed\n");
459			ret = PTR_ERR(pd->thread);
460			goto err_thread;
461		}
462		pd->field_count = 0;
463	}
464	pd->users++;
465	goto done;
466err_thread:
467	free_irq(pd->pdev->irq, pd);
468err_request_irq:
469	kfree(pd->vidq);
470	pd->vidq = NULL;
471err_alloc_queue:
472done:
473	mutex_unlock(&pd->mux);
474	return ret;
475}
476
477static int
478dt3155_release(struct file *filp)
479{
480	struct dt3155_priv *pd = video_drvdata(filp);
481	struct videobuf_buffer *tmp;
482	unsigned long flags;
483	int ret = 0;
484
485	printk(KERN_INFO "dt3155: release(): minor: %i\n", pd->vdev->minor);
486
487	if (mutex_lock_interruptible(&pd->mux) == -EINTR)
488		return -ERESTARTSYS;
489	pd->users--;
490	BUG_ON(pd->users < 0);
491	if (pd->acq_fp == filp) {
492		spin_lock_irqsave(&pd->lock, flags);
493		INIT_LIST_HEAD(&pd->dmaq); /* queue is emptied */
494		tmp = pd->curr_buf;
495		spin_unlock_irqrestore(&pd->lock, flags);
496		if (tmp)
497			videobuf_waiton(tmp, 0, 1); /* block, interruptible */
498		dt3155_stop_acq(pd);
499		videobuf_stop(pd->vidq);
500		pd->acq_fp = NULL;
501		pd->streaming = 0;
502	}
503	if (!pd->users) {
504		kthread_stop(pd->thread);
505		free_irq(pd->pdev->irq, pd);
506		kfree(pd->vidq);
507		pd->vidq = NULL;
508	}
509	mutex_unlock(&pd->mux);
510	return ret;
511}
512
513static ssize_t
514dt3155_read(struct file *filp, char __user *user, size_t size, loff_t *loff)
515{
516	struct dt3155_priv *pd = video_drvdata(filp);
517	int ret;
518
519	if (mutex_lock_interruptible(&pd->mux) == -EINTR)
520		return -ERESTARTSYS;
521	if (!pd->acq_fp) {
522		pd->acq_fp = filp;
523		pd->streaming = 0;
524	} else if (pd->acq_fp != filp) {
525		ret = -EBUSY;
526		goto done;
527	} else if (pd->streaming == 1) {
528		ret = -EINVAL;
529		goto done;
530	}
531	ret = videobuf_read_stream(pd->vidq, user, size, loff, 0,
532						filp->f_flags & O_NONBLOCK);
533done:
534	mutex_unlock(&pd->mux);
535	return ret;
536}
537
538static unsigned int
539dt3155_poll(struct file *filp, struct poll_table_struct *polltbl)
540{
541	struct dt3155_priv *pd = video_drvdata(filp);
542
543	return videobuf_poll_stream(filp, pd->vidq, polltbl);
544}
545
546static int
547dt3155_mmap(struct file *filp, struct vm_area_struct *vma)
548{
549	struct dt3155_priv *pd = video_drvdata(filp);
550
551	return videobuf_mmap_mapper(pd->vidq, vma);
552}
553
554static const struct v4l2_file_operations dt3155_fops = {
555	.owner = THIS_MODULE,
556	.open = dt3155_open,
557	.release = dt3155_release,
558	.read = dt3155_read,
559	.poll = dt3155_poll,
560	.unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */
561	.mmap = dt3155_mmap,
562};
563
564static int
565dt3155_ioc_streamon(struct file *filp, void *p, enum v4l2_buf_type type)
566{
567	struct dt3155_priv *pd = video_drvdata(filp);
568	int ret = -ERESTARTSYS;
569
570	if (mutex_lock_interruptible(&pd->mux) == -EINTR)
571		return ret;
572	if (!pd->acq_fp) {
573		ret = videobuf_streamon(pd->vidq);
574		if (ret)
575			goto unlock;
576		pd->acq_fp = filp;
577		pd->streaming = 1;
578		wake_up_interruptible_sync(&pd->do_dma);
579	} else if (pd->acq_fp == filp) {
580		pd->streaming = 1;
581		ret = videobuf_streamon(pd->vidq);
582		if (!ret)
583			wake_up_interruptible_sync(&pd->do_dma);
584	} else
585		ret = -EBUSY;
586unlock:
587	mutex_unlock(&pd->mux);
588	return ret;
589}
590
591static int
592dt3155_ioc_streamoff(struct file *filp, void *p, enum v4l2_buf_type type)
593{
594	struct dt3155_priv *pd = video_drvdata(filp);
595	struct videobuf_buffer *tmp;
596	unsigned long flags;
597	int ret;
598
599	ret = videobuf_streamoff(pd->vidq);
600	if (ret)
601		return ret;
602	spin_lock_irqsave(&pd->lock, flags);
603	tmp = pd->curr_buf;
604	spin_unlock_irqrestore(&pd->lock, flags);
605	if (tmp)
606		videobuf_waiton(tmp, 0, 1); /* block, interruptible */
607	return ret;
608}
609
610static int
611dt3155_ioc_querycap(struct file *filp, void *p, struct v4l2_capability *cap)
612{
613	struct dt3155_priv *pd = video_drvdata(filp);
614
615	strcpy(cap->driver, DT3155_NAME);
616	strcpy(cap->card, DT3155_NAME " frame grabber");
617	sprintf(cap->bus_info, "PCI:%s", pci_name(pd->pdev));
618	cap->version =
619	       KERNEL_VERSION(DT3155_VER_MAJ, DT3155_VER_MIN, DT3155_VER_EXT);
620	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
621				V4L2_CAP_STREAMING |
622				V4L2_CAP_READWRITE;
623	return 0;
624}
625
626static int
627dt3155_ioc_enum_fmt_vid_cap(struct file *filp, void *p, struct v4l2_fmtdesc *f)
628{
629	if (f->index >= NUM_OF_FORMATS)
630		return -EINVAL;
631	*f = frame_std[f->index];
632	return 0;
633}
634
635static int
636dt3155_ioc_g_fmt_vid_cap(struct file *filp, void *p, struct v4l2_format *f)
637{
638	if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
639		return -EINVAL;
640	f->fmt.pix.width = img_width;
641	f->fmt.pix.height = img_height;
642	f->fmt.pix.pixelformat = V4L2_PIX_FMT_GREY;
643	f->fmt.pix.field = V4L2_FIELD_NONE;
644	f->fmt.pix.bytesperline = f->fmt.pix.width;
645	f->fmt.pix.sizeimage = f->fmt.pix.width * f->fmt.pix.height;
646	f->fmt.pix.colorspace = 0;
647	f->fmt.pix.priv = 0;
648	return 0;
649}
650
651static int
652dt3155_ioc_try_fmt_vid_cap(struct file *filp, void *p, struct v4l2_format *f)
653{
654	if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
655		return -EINVAL;
656	if (f->fmt.pix.width == img_width &&
657		f->fmt.pix.height == img_height &&
658		f->fmt.pix.pixelformat == V4L2_PIX_FMT_GREY &&
659		f->fmt.pix.field == V4L2_FIELD_NONE &&
660		f->fmt.pix.bytesperline == f->fmt.pix.width &&
661		f->fmt.pix.sizeimage == f->fmt.pix.width * f->fmt.pix.height)
662			return 0;
663	else
664		return -EINVAL;
665}
666
667static int
668dt3155_ioc_s_fmt_vid_cap(struct file *filp, void *p, struct v4l2_format *f)
669{
670	struct dt3155_priv *pd = video_drvdata(filp);
671	int ret =  -ERESTARTSYS;
672
673	if (mutex_lock_interruptible(&pd->mux) == -EINTR)
674		return ret;
675	if (!pd->acq_fp) {
676		pd->acq_fp = filp;
677		pd->streaming = 0;
678	} else if (pd->acq_fp != filp) {
679		ret = -EBUSY;
680		goto done;
681	}
682	ret = dt3155_ioc_g_fmt_vid_cap(filp, p, f);
683done:
684	mutex_unlock(&pd->mux);
685	return ret;
686}
687
688static int
689dt3155_ioc_reqbufs(struct file *filp, void *p, struct v4l2_requestbuffers *b)
690{
691	struct dt3155_priv *pd = video_drvdata(filp);
692	struct videobuf_queue *q = pd->vidq;
693	int ret = -ERESTARTSYS;
694
695	if (b->memory != V4L2_MEMORY_MMAP)
696		return -EINVAL;
697	if (mutex_lock_interruptible(&pd->mux) == -EINTR)
698		return ret;
699	if (!pd->acq_fp)
700		pd->acq_fp = filp;
701	else if (pd->acq_fp != filp) {
702		ret = -EBUSY;
703		goto done;
704	}
705	pd->streaming = 1;
706	ret = 0;
707done:
708	mutex_unlock(&pd->mux);
709	if (ret)
710		return ret;
711	if (b->count)
712		ret = videobuf_reqbufs(q, b);
713	else {
714		printk(KERN_DEBUG "dt3155: request to free buffers\n");
715		/* ret = videobuf_mmap_free(q); */
716		ret = dt3155_ioc_streamoff(filp, p,
717						V4L2_BUF_TYPE_VIDEO_CAPTURE);
718	}
719	return ret;
720}
721
722static int
723dt3155_ioc_querybuf(struct file *filp, void *p, struct v4l2_buffer *b)
724{
725	struct dt3155_priv *pd = video_drvdata(filp);
726	struct videobuf_queue *q = pd->vidq;
727
728	return videobuf_querybuf(q, b);
729}
730
731static int
732dt3155_ioc_qbuf(struct file *filp, void *p, struct v4l2_buffer *b)
733{
734	struct dt3155_priv *pd = video_drvdata(filp);
735	struct videobuf_queue *q = pd->vidq;
736	int ret;
737
738	ret = videobuf_qbuf(q, b);
739	if (ret)
740		return ret;
741	return videobuf_querybuf(q, b);
742}
743
744static int
745dt3155_ioc_dqbuf(struct file *filp, void *p, struct v4l2_buffer *b)
746{
747	struct dt3155_priv *pd = video_drvdata(filp);
748	struct videobuf_queue *q = pd->vidq;
749
750	return videobuf_dqbuf(q, b, filp->f_flags & O_NONBLOCK);
751}
752
753static int
754dt3155_ioc_querystd(struct file *filp, void *p, v4l2_std_id *norm)
755{
756	*norm = DT3155_CURRENT_NORM;
757	return 0;
758}
759
760static int
761dt3155_ioc_g_std(struct file *filp, void *p, v4l2_std_id *norm)
762{
763	*norm = DT3155_CURRENT_NORM;
764	return 0;
765}
766
767static int
768dt3155_ioc_s_std(struct file *filp, void *p, v4l2_std_id *norm)
769{
770	if (*norm & DT3155_CURRENT_NORM)
771		return 0;
772	return -EINVAL;
773}
774
775static int
776dt3155_ioc_enum_input(struct file *filp, void *p, struct v4l2_input *input)
777{
778	if (input->index)
779		return -EINVAL;
780	strcpy(input->name, "Coax in");
781	input->type = V4L2_INPUT_TYPE_CAMERA;
782	input->std = DT3155_CURRENT_NORM;
783	input->status = 0;
784	return 0;
785}
786
787static int
788dt3155_ioc_g_input(struct file *filp, void *p, unsigned int *i)
789{
790	*i = 0;
791	return 0;
792}
793
794static int
795dt3155_ioc_s_input(struct file *filp, void *p, unsigned int i)
796{
797	if (i)
798		return -EINVAL;
799	return 0;
800}
801
802static int
803dt3155_ioc_g_parm(struct file *filp, void *p, struct v4l2_streamparm *parms)
804{
805	if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
806		return -EINVAL;
807	parms->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
808	parms->parm.capture.capturemode = 0;
809	parms->parm.capture.timeperframe.numerator = 1001;
810	parms->parm.capture.timeperframe.denominator = frames_per_sec * 1000;
811	parms->parm.capture.extendedmode = 0;
812	parms->parm.capture.readbuffers = 1;
813	return 0;
814}
815
816static int
817dt3155_ioc_s_parm(struct file *filp, void *p, struct v4l2_streamparm *parms)
818{
819	if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
820		return -EINVAL;
821	parms->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
822	parms->parm.capture.capturemode = 0;
823	parms->parm.capture.timeperframe.numerator = 1001;
824	parms->parm.capture.timeperframe.denominator = frames_per_sec * 1000;
825	parms->parm.capture.extendedmode = 0;
826	parms->parm.capture.readbuffers = 1;
827	return 0;
828}
829
830static const struct v4l2_ioctl_ops dt3155_ioctl_ops = {
831	.vidioc_streamon = dt3155_ioc_streamon,
832	.vidioc_streamoff = dt3155_ioc_streamoff,
833	.vidioc_querycap = dt3155_ioc_querycap,
834/*
835	.vidioc_g_priority = dt3155_ioc_g_priority,
836	.vidioc_s_priority = dt3155_ioc_s_priority,
837*/
838	.vidioc_enum_fmt_vid_cap = dt3155_ioc_enum_fmt_vid_cap,
839	.vidioc_try_fmt_vid_cap = dt3155_ioc_try_fmt_vid_cap,
840	.vidioc_g_fmt_vid_cap = dt3155_ioc_g_fmt_vid_cap,
841	.vidioc_s_fmt_vid_cap = dt3155_ioc_s_fmt_vid_cap,
842	.vidioc_reqbufs = dt3155_ioc_reqbufs,
843	.vidioc_querybuf = dt3155_ioc_querybuf,
844	.vidioc_qbuf = dt3155_ioc_qbuf,
845	.vidioc_dqbuf = dt3155_ioc_dqbuf,
846	.vidioc_querystd = dt3155_ioc_querystd,
847	.vidioc_g_std = dt3155_ioc_g_std,
848	.vidioc_s_std = dt3155_ioc_s_std,
849	.vidioc_enum_input = dt3155_ioc_enum_input,
850	.vidioc_g_input = dt3155_ioc_g_input,
851	.vidioc_s_input = dt3155_ioc_s_input,
852/*
853	.vidioc_queryctrl = dt3155_ioc_queryctrl,
854	.vidioc_g_ctrl = dt3155_ioc_g_ctrl,
855	.vidioc_s_ctrl = dt3155_ioc_s_ctrl,
856	.vidioc_querymenu = dt3155_ioc_querymenu,
857	.vidioc_g_ext_ctrls = dt3155_ioc_g_ext_ctrls,
858	.vidioc_s_ext_ctrls = dt3155_ioc_s_ext_ctrls,
859*/
860	.vidioc_g_parm = dt3155_ioc_g_parm,
861	.vidioc_s_parm = dt3155_ioc_s_parm,
862/*
863	.vidioc_cropcap = dt3155_ioc_cropcap,
864	.vidioc_g_crop = dt3155_ioc_g_crop,
865	.vidioc_s_crop = dt3155_ioc_s_crop,
866	.vidioc_enum_framesizes = dt3155_ioc_enum_framesizes,
867	.vidioc_enum_frameintervals = dt3155_ioc_enum_frameintervals,
868#ifdef CONFIG_VIDEO_V4L1_COMPAT
869	.vidiocgmbuf = iocgmbuf,
870#endif
871*/
872};
873
874static int __devinit
875dt3155_init_board(struct pci_dev *dev)
876{
877	struct dt3155_priv *pd = pci_get_drvdata(dev);
878	void *buf_cpu;
879	dma_addr_t buf_dma;
880	int i;
881	u8 tmp;
882
883	pci_set_master(dev); /* dt3155 needs it */
884
885	/*  resetting the adapter  */
886	iowrite32(FLD_CRPT_ODD | FLD_CRPT_EVEN | FLD_DN_ODD | FLD_DN_EVEN,
887							pd->regs + CSR1);
888	mmiowb();
889	msleep(10);
890
891	/*  initializing adaper registers  */
892	iowrite32(FIFO_EN | SRST, pd->regs + CSR1);
893	mmiowb();
894	iowrite32(0xEEEEEE01, pd->regs + EVEN_PIXEL_FMT);
895	iowrite32(0xEEEEEE01, pd->regs + ODD_PIXEL_FMT);
896	iowrite32(0x00000020, pd->regs + FIFO_TRIGER);
897	iowrite32(0x00000103, pd->regs + XFER_MODE);
898	iowrite32(0, pd->regs + RETRY_WAIT_CNT);
899	iowrite32(0, pd->regs + INT_CSR);
900	iowrite32(1, pd->regs + EVEN_FLD_MASK);
901	iowrite32(1, pd->regs + ODD_FLD_MASK);
902	iowrite32(0, pd->regs + MASK_LENGTH);
903	iowrite32(0x0005007C, pd->regs + FIFO_FLAG_CNT);
904	iowrite32(0x01010101, pd->regs + IIC_CLK_DUR);
905	mmiowb();
906
907	/* verifying that we have a DT3155 board (not just a SAA7116 chip) */
908	read_i2c_reg(pd->regs, DT_ID, &tmp);
909	if (tmp != DT3155_ID)
910		return -ENODEV;
911
912	/* initialize AD LUT */
913	write_i2c_reg(pd->regs, AD_ADDR, 0);
914	for (i = 0; i < 256; i++)
915		write_i2c_reg(pd->regs, AD_LUT, i);
916
917	/* initialize ADC references */
918	write_i2c_reg(pd->regs, AD_ADDR, AD_CMD_REG);
919	write_i2c_reg(pd->regs, AD_CMD, VIDEO_CNL_1 | SYNC_CNL_1 | SYNC_LVL_3);
920	write_i2c_reg(pd->regs, AD_ADDR, AD_POS_REF);
921	write_i2c_reg(pd->regs, AD_CMD, 34);
922	write_i2c_reg(pd->regs, AD_ADDR, AD_NEG_REF);
923	write_i2c_reg(pd->regs, AD_CMD, 0);
924
925	/* initialize PM LUT */
926	write_i2c_reg(pd->regs, CONFIG, pd->config | PM_LUT_PGM);
927	for (i = 0; i < 256; i++) {
928		write_i2c_reg(pd->regs, PM_LUT_ADDR, i);
929		write_i2c_reg(pd->regs, PM_LUT_DATA, i);
930	}
931	write_i2c_reg(pd->regs, CONFIG, pd->config | PM_LUT_PGM | PM_LUT_SEL);
932	for (i = 0; i < 256; i++) {
933		write_i2c_reg(pd->regs, PM_LUT_ADDR, i);
934		write_i2c_reg(pd->regs, PM_LUT_DATA, i);
935	}
936	write_i2c_reg(pd->regs, CONFIG, pd->config); /*  ACQ_MODE_EVEN  */
937
938	/* select chanel 1 for input and set sync level */
939	write_i2c_reg(pd->regs, AD_ADDR, AD_CMD_REG);
940	write_i2c_reg(pd->regs, AD_CMD, VIDEO_CNL_1 | SYNC_CNL_1 | SYNC_LVL_3);
941
942	/* allocate memory, and initialize the DMA machine */
943	buf_cpu = dma_alloc_coherent(&dev->dev, DT3155_BUF_SIZE, &buf_dma,
944								GFP_KERNEL);
945	if (!buf_cpu) {
946		printk(KERN_ERR "dt3155: dma_alloc_coherent "
947					"(in dt3155_init_board) failed\n");
948		return -ENOMEM;
949	}
950	iowrite32(buf_dma, pd->regs + EVEN_DMA_START);
951	iowrite32(buf_dma, pd->regs + ODD_DMA_START);
952	iowrite32(0, pd->regs + EVEN_DMA_STRIDE);
953	iowrite32(0, pd->regs + ODD_DMA_STRIDE);
954
955	/*  Perform a pseudo even field acquire    */
956	iowrite32(FIFO_EN | SRST | CAP_CONT_ODD, pd->regs + CSR1);
957	write_i2c_reg(pd->regs, CSR2, pd->csr2 | SYNC_SNTL);
958	write_i2c_reg(pd->regs, CONFIG, pd->config);
959	write_i2c_reg(pd->regs, EVEN_CSR, CSR_SNGL);
960	write_i2c_reg(pd->regs, CSR2, pd->csr2 | BUSY_EVEN | SYNC_SNTL);
961	msleep(100);
962	read_i2c_reg(pd->regs, CSR2, &tmp);
963	write_i2c_reg(pd->regs, EVEN_CSR, CSR_ERROR | CSR_SNGL | CSR_DONE);
964	write_i2c_reg(pd->regs, ODD_CSR, CSR_ERROR | CSR_SNGL | CSR_DONE);
965	write_i2c_reg(pd->regs, CSR2, pd->csr2);
966	iowrite32(FIFO_EN | SRST | FLD_DN_EVEN | FLD_DN_ODD, pd->regs + CSR1);
967
968	/*  deallocate memory  */
969	dma_free_coherent(&dev->dev, DT3155_BUF_SIZE, buf_cpu, buf_dma);
970	if (tmp & BUSY_EVEN) {
971		printk(KERN_ERR "dt3155: BUSY_EVEN not cleared\n");
972		return -EIO;
973	}
974	return 0;
975}
976
977static struct video_device dt3155_vdev = {
978	.name = DT3155_NAME,
979	.fops = &dt3155_fops,
980	.ioctl_ops = &dt3155_ioctl_ops,
981	.minor = -1,
982	.release = video_device_release,
983	.tvnorms = DT3155_CURRENT_NORM,
984	.current_norm = DT3155_CURRENT_NORM,
985};
986
987/* same as in drivers/base/dma-coherent.c */
988struct dma_coherent_mem {
989	void		*virt_base;
990	u32		device_base;
991	int		size;
992	int		flags;
993	unsigned long	*bitmap;
994};
995
996static int __devinit
997dt3155_alloc_coherent(struct device *dev, size_t size, int flags)
998{
999	struct dma_coherent_mem *mem;
1000	dma_addr_t dev_base;
1001	int pages = size >> PAGE_SHIFT;
1002	int bitmap_size = BITS_TO_LONGS(pages) * sizeof(long);
1003
1004	if ((flags & DMA_MEMORY_MAP) == 0)
1005		goto out;
1006	if (!size)
1007		goto out;
1008	if (dev->dma_mem)
1009		goto out;
1010
1011	mem = kzalloc(sizeof(*mem), GFP_KERNEL);
1012	if (!mem)
1013		goto out;
1014	mem->virt_base = dma_alloc_coherent(dev, size, &dev_base,
1015							DT3155_COH_FLAGS);
1016	if (!mem->virt_base)
1017		goto err_alloc_coherent;
1018	mem->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
1019	if (!mem->bitmap)
1020		goto err_bitmap;
1021
1022	/* coherent_dma_mask is already set to 32 bits */
1023	mem->device_base = dev_base;
1024	mem->size = pages;
1025	mem->flags = flags;
1026	dev->dma_mem = mem;
1027	return DMA_MEMORY_MAP;
1028
1029err_bitmap:
1030	dma_free_coherent(dev, size, mem->virt_base, dev_base);
1031err_alloc_coherent:
1032	kfree(mem);
1033out:
1034	return 0;
1035}
1036
1037static void __devexit
1038dt3155_free_coherent(struct device *dev)
1039{
1040	struct dma_coherent_mem *mem = dev->dma_mem;
1041
1042	if (!mem)
1043		return;
1044	dev->dma_mem = NULL;
1045	dma_free_coherent(dev, mem->size << PAGE_SHIFT,
1046					mem->virt_base, mem->device_base);
1047	kfree(mem->bitmap);
1048	kfree(mem);
1049}
1050
1051static int __devinit
1052dt3155_probe(struct pci_dev *dev, const struct pci_device_id *id)
1053{
1054	int err;
1055	struct dt3155_priv *pd;
1056
1057	printk(KERN_INFO "dt3155: probe()\n");
1058	err = dma_set_mask(&dev->dev, DMA_BIT_MASK(32));
1059	if (err) {
1060		printk(KERN_ERR "dt3155: cannot set dma_mask\n");
1061		return -ENODEV;
1062	}
1063	err = dma_set_coherent_mask(&dev->dev, DMA_BIT_MASK(32));
1064	if (err) {
1065		printk(KERN_ERR "dt3155: cannot set dma_coherent_mask\n");
1066		return -ENODEV;
1067	}
1068	pd = kzalloc(sizeof(*pd), GFP_KERNEL);
1069	if (!pd) {
1070		printk(KERN_ERR "dt3155: cannot allocate dt3155_priv\n");
1071		return -ENOMEM;
1072	}
1073	pd->vdev = video_device_alloc();
1074	if (!pd->vdev) {
1075		printk(KERN_ERR "dt3155: cannot allocate vdev structure\n");
1076		goto err_video_device_alloc;
1077	}
1078	*pd->vdev = dt3155_vdev;
1079	pci_set_drvdata(dev, pd);    /* for use in dt3155_remove() */
1080	video_set_drvdata(pd->vdev, pd);  /* for use in video_fops */
1081	pd->users = 0;
1082	pd->acq_fp = NULL;
1083	pd->pdev = dev;
1084	INIT_LIST_HEAD(&pd->dmaq);
1085	init_waitqueue_head(&pd->do_dma);
1086	mutex_init(&pd->mux);
1087	pd->csr2 = csr2_init;
1088	pd->config = config_init;
1089	err = pci_enable_device(pd->pdev);
1090	if (err) {
1091		printk(KERN_ERR "dt3155: pci_dev not enabled\n");
1092		goto err_enable_dev;
1093	}
1094	err = pci_request_region(pd->pdev, 0, pci_name(pd->pdev));
1095	if (err)
1096		goto err_req_region;
1097	pd->regs = pci_iomap(pd->pdev, 0, pci_resource_len(pd->pdev, 0));
1098	if (!pd->regs) {
1099		err = -ENOMEM;
1100		printk(KERN_ERR "dt3155: pci_iomap failed\n");
1101		goto err_pci_iomap;
1102	}
1103	err = dt3155_init_board(pd->pdev);
1104	if (err) {
1105		printk(KERN_ERR "dt3155: dt3155_init_board failed\n");
1106		goto err_init_board;
1107	}
1108	err = video_register_device(pd->vdev, VFL_TYPE_GRABBER, -1);
1109	if (err) {
1110		printk(KERN_ERR "dt3155: Cannot register video device\n");
1111		goto err_init_board;
1112	}
1113	err = dt3155_alloc_coherent(&dev->dev, DT3155_CHUNK_SIZE,
1114							DMA_MEMORY_MAP);
1115	if (err)
1116		printk(KERN_INFO "dt3155: preallocated 8 buffers\n");
1117	printk(KERN_INFO "dt3155: /dev/video%i is ready\n", pd->vdev->minor);
1118	return 0;  /*   success   */
1119
1120err_init_board:
1121	pci_iounmap(pd->pdev, pd->regs);
1122err_pci_iomap:
1123	pci_release_region(pd->pdev, 0);
1124err_req_region:
1125	pci_disable_device(pd->pdev);
1126err_enable_dev:
1127	video_device_release(pd->vdev);
1128err_video_device_alloc:
1129	kfree(pd);
1130	return err;
1131}
1132
1133static void __devexit
1134dt3155_remove(struct pci_dev *dev)
1135{
1136	struct dt3155_priv *pd = pci_get_drvdata(dev);
1137
1138	printk(KERN_INFO "dt3155: remove()\n");
1139	dt3155_free_coherent(&dev->dev);
1140	video_unregister_device(pd->vdev);
1141	pci_iounmap(dev, pd->regs);
1142	pci_release_region(pd->pdev, 0);
1143	pci_disable_device(pd->pdev);
1144	/*
1145	 * video_device_release() is invoked automatically
1146	 * see: struct video_device dt3155_vdev
1147	 */
1148	kfree(pd);
1149}
1150
1151static DEFINE_PCI_DEVICE_TABLE(pci_ids) = {
1152	{ PCI_DEVICE(DT3155_VENDOR_ID, DT3155_DEVICE_ID) },
1153	{ 0, /* zero marks the end */ },
1154};
1155MODULE_DEVICE_TABLE(pci, pci_ids);
1156
1157static struct pci_driver pci_driver = {
1158	.name = DT3155_NAME,
1159	.id_table = pci_ids,
1160	.probe = dt3155_probe,
1161	.remove = __devexit_p(dt3155_remove),
1162};
1163
1164static int __init
1165dt3155_init_module(void)
1166{
1167	int err;
1168
1169	printk(KERN_INFO "dt3155: ==================\n");
1170	printk(KERN_INFO "dt3155: init()\n");
1171	err = pci_register_driver(&pci_driver);
1172	if (err) {
1173		printk(KERN_ERR "dt3155: cannot register pci_driver\n");
1174		return err;
1175	}
1176	return 0; /* succes */
1177}
1178
1179static void __exit
1180dt3155_exit_module(void)
1181{
1182	pci_unregister_driver(&pci_driver);
1183	printk(KERN_INFO "dt3155: exit()\n");
1184	printk(KERN_INFO "dt3155: ==================\n");
1185}
1186
1187module_init(dt3155_init_module);
1188module_exit(dt3155_exit_module);
1189
1190MODULE_DESCRIPTION("video4linux pci-driver for dt3155 frame grabber");
1191MODULE_AUTHOR("Marin Mitov <mitov@issp.bas.bg>");
1192MODULE_VERSION(DT3155_VERSION);
1193MODULE_LICENSE("GPL");
1194