0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/module.h>
0010 #include <linux/stringify.h>
0011 #include <linux/delay.h>
0012 #include <linux/kthread.h>
0013 #include <linux/slab.h>
0014 #include <media/v4l2-dev.h>
0015 #include <media/v4l2-ioctl.h>
0016 #include <media/v4l2-common.h>
0017 #include <media/videobuf2-dma-contig.h>
0018
0019 #include "dt3155.h"
0020
0021 #define DT3155_DEVICE_ID 0x1223
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036 static int read_i2c_reg(void __iomem *addr, u8 index, u8 *data)
0037 {
0038 u32 tmp = index;
0039
0040 iowrite32((tmp << 17) | IIC_READ, addr + IIC_CSR2);
0041 udelay(45);
0042 if (ioread32(addr + IIC_CSR2) & NEW_CYCLE)
0043 return -EIO;
0044 tmp = ioread32(addr + IIC_CSR1);
0045 if (tmp & DIRECT_ABORT) {
0046
0047 iowrite32(DIRECT_ABORT, addr + IIC_CSR1);
0048 return -EIO;
0049 }
0050 *data = tmp >> 24;
0051 return 0;
0052 }
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066 static int write_i2c_reg(void __iomem *addr, u8 index, u8 data)
0067 {
0068 u32 tmp = index;
0069
0070 iowrite32((tmp << 17) | IIC_WRITE | data, addr + IIC_CSR2);
0071 udelay(65);
0072 if (ioread32(addr + IIC_CSR2) & NEW_CYCLE)
0073 return -EIO;
0074 if (ioread32(addr + IIC_CSR1) & DIRECT_ABORT) {
0075
0076 iowrite32(DIRECT_ABORT, addr + IIC_CSR1);
0077 return -EIO;
0078 }
0079 return 0;
0080 }
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092 static void write_i2c_reg_nowait(void __iomem *addr, u8 index, u8 data)
0093 {
0094 u32 tmp = index;
0095
0096 iowrite32((tmp << 17) | IIC_WRITE | data, addr + IIC_CSR2);
0097 }
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107
0108 static int wait_i2c_reg(void __iomem *addr)
0109 {
0110 if (ioread32(addr + IIC_CSR2) & NEW_CYCLE)
0111 udelay(65);
0112 if (ioread32(addr + IIC_CSR2) & NEW_CYCLE)
0113 return -EIO;
0114 if (ioread32(addr + IIC_CSR1) & DIRECT_ABORT) {
0115
0116 iowrite32(DIRECT_ABORT, addr + IIC_CSR1);
0117 return -EIO;
0118 }
0119 return 0;
0120 }
0121
0122 static int
0123 dt3155_queue_setup(struct vb2_queue *vq,
0124 unsigned int *nbuffers, unsigned int *num_planes,
0125 unsigned int sizes[], struct device *alloc_devs[])
0126
0127 {
0128 struct dt3155_priv *pd = vb2_get_drv_priv(vq);
0129 unsigned size = pd->width * pd->height;
0130
0131 if (vq->num_buffers + *nbuffers < 2)
0132 *nbuffers = 2 - vq->num_buffers;
0133 if (*num_planes)
0134 return sizes[0] < size ? -EINVAL : 0;
0135 *num_planes = 1;
0136 sizes[0] = size;
0137 return 0;
0138 }
0139
0140 static int dt3155_buf_prepare(struct vb2_buffer *vb)
0141 {
0142 struct dt3155_priv *pd = vb2_get_drv_priv(vb->vb2_queue);
0143
0144 vb2_set_plane_payload(vb, 0, pd->width * pd->height);
0145 return 0;
0146 }
0147
0148 static int dt3155_start_streaming(struct vb2_queue *q, unsigned count)
0149 {
0150 struct dt3155_priv *pd = vb2_get_drv_priv(q);
0151 struct vb2_buffer *vb = &pd->curr_buf->vb2_buf;
0152 dma_addr_t dma_addr;
0153
0154 pd->sequence = 0;
0155 dma_addr = vb2_dma_contig_plane_dma_addr(vb, 0);
0156 iowrite32(dma_addr, pd->regs + EVEN_DMA_START);
0157 iowrite32(dma_addr + pd->width, pd->regs + ODD_DMA_START);
0158 iowrite32(pd->width, pd->regs + EVEN_DMA_STRIDE);
0159 iowrite32(pd->width, pd->regs + ODD_DMA_STRIDE);
0160
0161 iowrite32(FLD_START_EN | FLD_END_ODD_EN | FLD_START |
0162 FLD_END_EVEN | FLD_END_ODD, pd->regs + INT_CSR);
0163 iowrite32(FIFO_EN | SRST | FLD_CRPT_ODD | FLD_CRPT_EVEN |
0164 FLD_DN_ODD | FLD_DN_EVEN | CAP_CONT_EVEN | CAP_CONT_ODD,
0165 pd->regs + CSR1);
0166 wait_i2c_reg(pd->regs);
0167 write_i2c_reg(pd->regs, CONFIG, pd->config);
0168 write_i2c_reg(pd->regs, EVEN_CSR, CSR_ERROR | CSR_DONE);
0169 write_i2c_reg(pd->regs, ODD_CSR, CSR_ERROR | CSR_DONE);
0170
0171
0172 write_i2c_reg(pd->regs, CSR2, pd->csr2 | BUSY_EVEN | BUSY_ODD);
0173 return 0;
0174 }
0175
0176 static void dt3155_stop_streaming(struct vb2_queue *q)
0177 {
0178 struct dt3155_priv *pd = vb2_get_drv_priv(q);
0179 struct vb2_buffer *vb;
0180
0181 spin_lock_irq(&pd->lock);
0182
0183 write_i2c_reg_nowait(pd->regs, CSR2, pd->csr2);
0184 iowrite32(FIFO_EN | SRST | FLD_CRPT_ODD | FLD_CRPT_EVEN |
0185 FLD_DN_ODD | FLD_DN_EVEN, pd->regs + CSR1);
0186
0187 iowrite32(FLD_START | FLD_END_EVEN | FLD_END_ODD, pd->regs + INT_CSR);
0188 spin_unlock_irq(&pd->lock);
0189
0190
0191
0192
0193
0194
0195 msleep(45);
0196
0197 spin_lock_irq(&pd->lock);
0198 if (pd->curr_buf) {
0199 vb2_buffer_done(&pd->curr_buf->vb2_buf, VB2_BUF_STATE_ERROR);
0200 pd->curr_buf = NULL;
0201 }
0202
0203 while (!list_empty(&pd->dmaq)) {
0204 vb = list_first_entry(&pd->dmaq, typeof(*vb), done_entry);
0205 list_del(&vb->done_entry);
0206 vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
0207 }
0208 spin_unlock_irq(&pd->lock);
0209 }
0210
0211 static void dt3155_buf_queue(struct vb2_buffer *vb)
0212 {
0213 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
0214 struct dt3155_priv *pd = vb2_get_drv_priv(vb->vb2_queue);
0215
0216
0217 spin_lock_irq(&pd->lock);
0218 if (pd->curr_buf)
0219 list_add_tail(&vb->done_entry, &pd->dmaq);
0220 else
0221 pd->curr_buf = vbuf;
0222 spin_unlock_irq(&pd->lock);
0223 }
0224
0225 static const struct vb2_ops q_ops = {
0226 .queue_setup = dt3155_queue_setup,
0227 .wait_prepare = vb2_ops_wait_prepare,
0228 .wait_finish = vb2_ops_wait_finish,
0229 .buf_prepare = dt3155_buf_prepare,
0230 .start_streaming = dt3155_start_streaming,
0231 .stop_streaming = dt3155_stop_streaming,
0232 .buf_queue = dt3155_buf_queue,
0233 };
0234
0235 static irqreturn_t dt3155_irq_handler_even(int irq, void *dev_id)
0236 {
0237 struct dt3155_priv *ipd = dev_id;
0238 struct vb2_buffer *ivb;
0239 dma_addr_t dma_addr;
0240 u32 tmp;
0241
0242 tmp = ioread32(ipd->regs + INT_CSR) & (FLD_START | FLD_END_ODD);
0243 if (!tmp)
0244 return IRQ_NONE;
0245 if ((tmp & FLD_START) && !(tmp & FLD_END_ODD)) {
0246 iowrite32(FLD_START_EN | FLD_END_ODD_EN | FLD_START,
0247 ipd->regs + INT_CSR);
0248 return IRQ_HANDLED;
0249 }
0250 tmp = ioread32(ipd->regs + CSR1) & (FLD_CRPT_EVEN | FLD_CRPT_ODD);
0251 if (tmp) {
0252 iowrite32(FIFO_EN | SRST | FLD_CRPT_ODD | FLD_CRPT_EVEN |
0253 FLD_DN_ODD | FLD_DN_EVEN |
0254 CAP_CONT_EVEN | CAP_CONT_ODD,
0255 ipd->regs + CSR1);
0256 }
0257
0258 spin_lock(&ipd->lock);
0259 if (ipd->curr_buf && !list_empty(&ipd->dmaq)) {
0260 ipd->curr_buf->vb2_buf.timestamp = ktime_get_ns();
0261 ipd->curr_buf->sequence = ipd->sequence++;
0262 ipd->curr_buf->field = V4L2_FIELD_NONE;
0263 vb2_buffer_done(&ipd->curr_buf->vb2_buf, VB2_BUF_STATE_DONE);
0264
0265 ivb = list_first_entry(&ipd->dmaq, typeof(*ivb), done_entry);
0266 list_del(&ivb->done_entry);
0267 ipd->curr_buf = to_vb2_v4l2_buffer(ivb);
0268 dma_addr = vb2_dma_contig_plane_dma_addr(ivb, 0);
0269 iowrite32(dma_addr, ipd->regs + EVEN_DMA_START);
0270 iowrite32(dma_addr + ipd->width, ipd->regs + ODD_DMA_START);
0271 iowrite32(ipd->width, ipd->regs + EVEN_DMA_STRIDE);
0272 iowrite32(ipd->width, ipd->regs + ODD_DMA_STRIDE);
0273 }
0274
0275
0276 iowrite32(FLD_START_EN | FLD_END_ODD_EN | FLD_START |
0277 FLD_END_EVEN | FLD_END_ODD, ipd->regs + INT_CSR);
0278 spin_unlock(&ipd->lock);
0279 return IRQ_HANDLED;
0280 }
0281
0282 static const struct v4l2_file_operations dt3155_fops = {
0283 .owner = THIS_MODULE,
0284 .open = v4l2_fh_open,
0285 .release = vb2_fop_release,
0286 .unlocked_ioctl = video_ioctl2,
0287 .read = vb2_fop_read,
0288 .mmap = vb2_fop_mmap,
0289 .poll = vb2_fop_poll
0290 };
0291
0292 static int dt3155_querycap(struct file *filp, void *p,
0293 struct v4l2_capability *cap)
0294 {
0295 strscpy(cap->driver, DT3155_NAME, sizeof(cap->driver));
0296 strscpy(cap->card, DT3155_NAME " frame grabber", sizeof(cap->card));
0297 return 0;
0298 }
0299
0300 static int dt3155_enum_fmt_vid_cap(struct file *filp,
0301 void *p, struct v4l2_fmtdesc *f)
0302 {
0303 if (f->index)
0304 return -EINVAL;
0305 f->pixelformat = V4L2_PIX_FMT_GREY;
0306 return 0;
0307 }
0308
0309 static int dt3155_fmt_vid_cap(struct file *filp, void *p, struct v4l2_format *f)
0310 {
0311 struct dt3155_priv *pd = video_drvdata(filp);
0312
0313 f->fmt.pix.width = pd->width;
0314 f->fmt.pix.height = pd->height;
0315 f->fmt.pix.pixelformat = V4L2_PIX_FMT_GREY;
0316 f->fmt.pix.field = V4L2_FIELD_NONE;
0317 f->fmt.pix.bytesperline = f->fmt.pix.width;
0318 f->fmt.pix.sizeimage = f->fmt.pix.width * f->fmt.pix.height;
0319 f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
0320 return 0;
0321 }
0322
0323 static int dt3155_g_std(struct file *filp, void *p, v4l2_std_id *norm)
0324 {
0325 struct dt3155_priv *pd = video_drvdata(filp);
0326
0327 *norm = pd->std;
0328 return 0;
0329 }
0330
0331 static int dt3155_s_std(struct file *filp, void *p, v4l2_std_id norm)
0332 {
0333 struct dt3155_priv *pd = video_drvdata(filp);
0334
0335 if (pd->std == norm)
0336 return 0;
0337 if (vb2_is_busy(&pd->vidq))
0338 return -EBUSY;
0339 pd->std = norm;
0340 if (pd->std & V4L2_STD_525_60) {
0341 pd->csr2 = VT_60HZ;
0342 pd->width = 640;
0343 pd->height = 480;
0344 } else {
0345 pd->csr2 = VT_50HZ;
0346 pd->width = 768;
0347 pd->height = 576;
0348 }
0349 return 0;
0350 }
0351
0352 static int dt3155_enum_input(struct file *filp, void *p,
0353 struct v4l2_input *input)
0354 {
0355 if (input->index > 3)
0356 return -EINVAL;
0357 if (input->index)
0358 snprintf(input->name, sizeof(input->name), "VID%d",
0359 input->index);
0360 else
0361 strscpy(input->name, "J2/VID0", sizeof(input->name));
0362 input->type = V4L2_INPUT_TYPE_CAMERA;
0363 input->std = V4L2_STD_ALL;
0364 input->status = 0;
0365 return 0;
0366 }
0367
0368 static int dt3155_g_input(struct file *filp, void *p, unsigned int *i)
0369 {
0370 struct dt3155_priv *pd = video_drvdata(filp);
0371
0372 *i = pd->input;
0373 return 0;
0374 }
0375
0376 static int dt3155_s_input(struct file *filp, void *p, unsigned int i)
0377 {
0378 struct dt3155_priv *pd = video_drvdata(filp);
0379
0380 if (i > 3)
0381 return -EINVAL;
0382 pd->input = i;
0383 write_i2c_reg(pd->regs, AD_ADDR, AD_CMD_REG);
0384 write_i2c_reg(pd->regs, AD_CMD, (i << 6) | (i << 4) | SYNC_LVL_3);
0385 return 0;
0386 }
0387
0388 static const struct v4l2_ioctl_ops dt3155_ioctl_ops = {
0389 .vidioc_querycap = dt3155_querycap,
0390 .vidioc_enum_fmt_vid_cap = dt3155_enum_fmt_vid_cap,
0391 .vidioc_try_fmt_vid_cap = dt3155_fmt_vid_cap,
0392 .vidioc_g_fmt_vid_cap = dt3155_fmt_vid_cap,
0393 .vidioc_s_fmt_vid_cap = dt3155_fmt_vid_cap,
0394 .vidioc_reqbufs = vb2_ioctl_reqbufs,
0395 .vidioc_create_bufs = vb2_ioctl_create_bufs,
0396 .vidioc_querybuf = vb2_ioctl_querybuf,
0397 .vidioc_expbuf = vb2_ioctl_expbuf,
0398 .vidioc_qbuf = vb2_ioctl_qbuf,
0399 .vidioc_dqbuf = vb2_ioctl_dqbuf,
0400 .vidioc_streamon = vb2_ioctl_streamon,
0401 .vidioc_streamoff = vb2_ioctl_streamoff,
0402 .vidioc_g_std = dt3155_g_std,
0403 .vidioc_s_std = dt3155_s_std,
0404 .vidioc_enum_input = dt3155_enum_input,
0405 .vidioc_g_input = dt3155_g_input,
0406 .vidioc_s_input = dt3155_s_input,
0407 };
0408
0409 static int dt3155_init_board(struct dt3155_priv *pd)
0410 {
0411 struct pci_dev *pdev = pd->pdev;
0412 int i;
0413 u8 tmp = 0;
0414
0415 pci_set_master(pdev);
0416
0417
0418 iowrite32(ADDR_ERR_ODD | ADDR_ERR_EVEN | FLD_CRPT_ODD | FLD_CRPT_EVEN |
0419 FLD_DN_ODD | FLD_DN_EVEN, pd->regs + CSR1);
0420 msleep(20);
0421
0422
0423 iowrite32(FIFO_EN | SRST, pd->regs + CSR1);
0424 iowrite32(0xEEEEEE01, pd->regs + EVEN_PIXEL_FMT);
0425 iowrite32(0xEEEEEE01, pd->regs + ODD_PIXEL_FMT);
0426 iowrite32(0x00000020, pd->regs + FIFO_TRIGGER);
0427 iowrite32(0x00000103, pd->regs + XFER_MODE);
0428 iowrite32(0, pd->regs + RETRY_WAIT_CNT);
0429 iowrite32(0, pd->regs + INT_CSR);
0430 iowrite32(1, pd->regs + EVEN_FLD_MASK);
0431 iowrite32(1, pd->regs + ODD_FLD_MASK);
0432 iowrite32(0, pd->regs + MASK_LENGTH);
0433 iowrite32(0x0005007C, pd->regs + FIFO_FLAG_CNT);
0434 iowrite32(0x01010101, pd->regs + IIC_CLK_DUR);
0435
0436
0437 read_i2c_reg(pd->regs, DT_ID, &tmp);
0438 if (tmp != DT3155_ID)
0439 return -ENODEV;
0440
0441
0442 write_i2c_reg(pd->regs, AD_ADDR, 0);
0443 for (i = 0; i < 256; i++)
0444 write_i2c_reg(pd->regs, AD_LUT, i);
0445
0446
0447
0448 write_i2c_reg(pd->regs, AD_ADDR, AD_CMD_REG);
0449 write_i2c_reg(pd->regs, AD_CMD, VIDEO_CNL_1 | SYNC_CNL_1 | SYNC_LVL_3);
0450 write_i2c_reg(pd->regs, AD_ADDR, AD_POS_REF);
0451 write_i2c_reg(pd->regs, AD_CMD, 34);
0452 write_i2c_reg(pd->regs, AD_ADDR, AD_NEG_REF);
0453 write_i2c_reg(pd->regs, AD_CMD, 0);
0454
0455
0456 write_i2c_reg(pd->regs, CONFIG, pd->config | PM_LUT_PGM);
0457 for (i = 0; i < 256; i++) {
0458 write_i2c_reg(pd->regs, PM_LUT_ADDR, i);
0459 write_i2c_reg(pd->regs, PM_LUT_DATA, i);
0460 }
0461 write_i2c_reg(pd->regs, CONFIG, pd->config | PM_LUT_PGM | PM_LUT_SEL);
0462 for (i = 0; i < 256; i++) {
0463 write_i2c_reg(pd->regs, PM_LUT_ADDR, i);
0464 write_i2c_reg(pd->regs, PM_LUT_DATA, i);
0465 }
0466 write_i2c_reg(pd->regs, CONFIG, pd->config);
0467
0468
0469 write_i2c_reg(pd->regs, AD_ADDR, AD_CMD_REG);
0470 write_i2c_reg(pd->regs, AD_CMD, VIDEO_CNL_1 | SYNC_CNL_1 | SYNC_LVL_3);
0471
0472
0473 iowrite32(FLD_START | FLD_END_EVEN | FLD_END_ODD,
0474 pd->regs + INT_CSR);
0475
0476 return 0;
0477 }
0478
0479 static const struct video_device dt3155_vdev = {
0480 .name = DT3155_NAME,
0481 .fops = &dt3155_fops,
0482 .ioctl_ops = &dt3155_ioctl_ops,
0483 .minor = -1,
0484 .release = video_device_release_empty,
0485 .tvnorms = V4L2_STD_ALL,
0486 .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
0487 V4L2_CAP_READWRITE,
0488 };
0489
0490 static int dt3155_probe(struct pci_dev *pdev, const struct pci_device_id *id)
0491 {
0492 int err;
0493 struct dt3155_priv *pd;
0494
0495 err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
0496 if (err)
0497 return -ENODEV;
0498 pd = devm_kzalloc(&pdev->dev, sizeof(*pd), GFP_KERNEL);
0499 if (!pd)
0500 return -ENOMEM;
0501
0502 err = v4l2_device_register(&pdev->dev, &pd->v4l2_dev);
0503 if (err)
0504 return err;
0505 pd->vdev = dt3155_vdev;
0506 pd->vdev.v4l2_dev = &pd->v4l2_dev;
0507 video_set_drvdata(&pd->vdev, pd);
0508 pd->pdev = pdev;
0509 pd->std = V4L2_STD_625_50;
0510 pd->csr2 = VT_50HZ;
0511 pd->width = 768;
0512 pd->height = 576;
0513 INIT_LIST_HEAD(&pd->dmaq);
0514 mutex_init(&pd->mux);
0515 pd->vdev.lock = &pd->mux;
0516 pd->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
0517 pd->vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
0518 pd->vidq.io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ;
0519 pd->vidq.ops = &q_ops;
0520 pd->vidq.mem_ops = &vb2_dma_contig_memops;
0521 pd->vidq.drv_priv = pd;
0522 pd->vidq.min_buffers_needed = 2;
0523 pd->vidq.gfp_flags = GFP_DMA32;
0524 pd->vidq.lock = &pd->mux;
0525 pd->vidq.dev = &pdev->dev;
0526 pd->vdev.queue = &pd->vidq;
0527 err = vb2_queue_init(&pd->vidq);
0528 if (err < 0)
0529 goto err_v4l2_dev_unreg;
0530 spin_lock_init(&pd->lock);
0531 pd->config = ACQ_MODE_EVEN;
0532 err = pci_enable_device(pdev);
0533 if (err)
0534 goto err_v4l2_dev_unreg;
0535 err = pci_request_region(pdev, 0, pci_name(pdev));
0536 if (err)
0537 goto err_pci_disable;
0538 pd->regs = pci_iomap(pdev, 0, pci_resource_len(pd->pdev, 0));
0539 if (!pd->regs) {
0540 err = -ENOMEM;
0541 goto err_free_reg;
0542 }
0543 err = dt3155_init_board(pd);
0544 if (err)
0545 goto err_iounmap;
0546 err = request_irq(pd->pdev->irq, dt3155_irq_handler_even,
0547 IRQF_SHARED, DT3155_NAME, pd);
0548 if (err)
0549 goto err_iounmap;
0550 err = video_register_device(&pd->vdev, VFL_TYPE_VIDEO, -1);
0551 if (err)
0552 goto err_free_irq;
0553 dev_info(&pdev->dev, "/dev/video%i is ready\n", pd->vdev.minor);
0554 return 0;
0555
0556 err_free_irq:
0557 free_irq(pd->pdev->irq, pd);
0558 err_iounmap:
0559 pci_iounmap(pdev, pd->regs);
0560 err_free_reg:
0561 pci_release_region(pdev, 0);
0562 err_pci_disable:
0563 pci_disable_device(pdev);
0564 err_v4l2_dev_unreg:
0565 v4l2_device_unregister(&pd->v4l2_dev);
0566 return err;
0567 }
0568
0569 static void dt3155_remove(struct pci_dev *pdev)
0570 {
0571 struct v4l2_device *v4l2_dev = pci_get_drvdata(pdev);
0572 struct dt3155_priv *pd = container_of(v4l2_dev, struct dt3155_priv,
0573 v4l2_dev);
0574
0575 vb2_video_unregister_device(&pd->vdev);
0576 free_irq(pd->pdev->irq, pd);
0577 v4l2_device_unregister(&pd->v4l2_dev);
0578 pci_iounmap(pdev, pd->regs);
0579 pci_release_region(pdev, 0);
0580 pci_disable_device(pdev);
0581 }
0582
0583 static const struct pci_device_id pci_ids[] = {
0584 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, DT3155_DEVICE_ID) },
0585 { 0, },
0586 };
0587 MODULE_DEVICE_TABLE(pci, pci_ids);
0588
0589 static struct pci_driver pci_driver = {
0590 .name = DT3155_NAME,
0591 .id_table = pci_ids,
0592 .probe = dt3155_probe,
0593 .remove = dt3155_remove,
0594 };
0595
0596 module_pci_driver(pci_driver);
0597
0598 MODULE_DESCRIPTION("video4linux pci-driver for dt3155 frame grabber");
0599 MODULE_AUTHOR("Marin Mitov <mitov@issp.bas.bg>");
0600 MODULE_VERSION(DT3155_VERSION);
0601 MODULE_LICENSE("GPL");