3 Copyright 1996,2002,2005 Gregory D. Hager, Alfred A. Rizzi, Noah J. Cowan,
4 Jason Lapenta, Scott Smedley, Greg Sharp
6 This file is part of the DT3155 Device Driver.
8 The DT3155 Device Driver is free software; you can redistribute it
9 and/or modify it under the terms of the GNU General Public License as
10 published by the Free Software Foundation; either version 2 of the
11 License, or (at your option) any later version.
13 The DT3155 Device Driver is distributed in the hope that it will be
14 useful, but WITHOUT ANY WARRANTY; without even the implied warranty
15 of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with the DT3155 Device Driver; if not, write to the Free
20 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
25 Date Programmer Description of changes made
26 -------------------------------------------------------------------
28 10-Oct-2001 SS port to 2.4 kernel
29 02-Apr-2002 SS Mods to use allocator as a standalone module;
30 Merged John Roll's changes (john@cfa.harvard.edu)
31 to make work with multiple boards.
32 02-Jul-2002 SS Merged James Rose's chages (rosejr@purdue.edu) to:
33 * fix successive interrupt-driven captures
34 * add select/poll support.
35 10-Jul-2002 GCS Add error check when ndevices > MAXBOARDS.
36 02-Aug-2002 GCS Fix field mode so that odd (lower) field is stored
37 in lower half of buffer.
38 05-Aug-2005 SS port to 2.6 kernel.
39 26-Oct-2009 SS port to 2.6.30 kernel.
43 ** appended "mem=124" in lilo.conf to allow for 4megs free on my 128meg system.
44 * using allocator.c and allocator.h from o'reilly book (alessandro rubini)
45 ftp://ftp.systemy.it/pub/develop (see README.allocator)
47 + might want to get rid of MAXboards for allocating initial buffer.
48 confusing and not necessary
50 + in cleanup_module the MOD_IN_USE looks like it is check after it should
52 * GFP_DMA should not be set with a PCI system (pg 291)
54 - NJC why are only two buffers allowed? (see isr, approx line 358)
58 extern void printques(int);
61 #include <linux/module.h>
62 #include <linux/interrupt.h>
65 MODULE_LICENSE("GPL");
70 #error "DT3155 : Kernel PCI support not enabled (DT3155 drive requires PCI)"
73 #include <linux/pci.h>
74 #include <linux/types.h>
75 #include <linux/poll.h>
76 #include <linux/sched.h>
79 #include <asm/uaccess.h>
82 #include "dt3155_drv.h"
83 #include "dt3155_isr.h"
84 #include "dt3155_io.h"
85 #include "allocator.h"
87 /* Error variable. Zero means no error. */
90 #ifndef PCI_DEVICE_ID_INTEL_7116
91 #define PCI_DEVICE_ID_INTEL_7116 0x1223
94 #define DT3155_VENDORID PCI_VENDOR_ID_INTEL
95 #define DT3155_DEVICEID PCI_DEVICE_ID_INTEL_7116
99 #define DT_3155_DEBUG_MSG(x,y) printk(x,y)
101 #define DT_3155_DEBUG_MSG(x,y)
104 /* wait queue for interrupts */
105 wait_queue_head_t dt3155_read_wait_queue
[ MAXBOARDS
];
107 #define DT_3155_SUCCESS 0
108 #define DT_3155_FAILURE -EIO
110 /* set to dynamicaly allocate, but it is tunable: */
111 /* insmod DT_3155 dt3155 dt3155_major=XX */
112 int dt3155_major
= 0;
114 /* The minor numbers are 0 and 1 ... they are not tunable.
115 * They are used as the indices for the structure vectors,
116 * and register address vectors
119 /* Global structures and variables */
121 /* Status of each device */
122 struct dt3155_status_s dt3155_status
[ MAXBOARDS
];
124 /* kernel logical address of the board */
125 u8
*dt3155_lbase
[ MAXBOARDS
] = { NULL
130 /* DT3155 registers */
131 u8
*dt3155_bbase
= NULL
; /* kernel logical address of the *
133 u32 dt3155_dev_open
[ MAXBOARDS
] = {0
144 * Stops interrupt generation right away and resets the status
145 * to idle. I don't know why this works and the other way doesn't.
148 static void quick_stop (int minor
)
150 // TODO: scott was here
152 ReadMReg((dt3155_lbase
[ minor
] + INT_CSR
), int_csr_r
.reg
);
153 /* disable interrupts */
154 int_csr_r
.fld
.FLD_END_EVE_EN
= 0;
155 int_csr_r
.fld
.FLD_END_ODD_EN
= 0;
156 WriteMReg((dt3155_lbase
[ minor
] + INT_CSR
), int_csr_r
.reg
);
158 dt3155_status
[ minor
].state
&= ~(DT3155_STATE_STOP
|0xff);
159 /* mark the system stopped: */
160 dt3155_status
[ minor
].state
|= DT3155_STATE_IDLE
;
161 dt3155_fbuffer
[ minor
]->stop_acquire
= 0;
162 dt3155_fbuffer
[ minor
]->even_stopped
= 0;
164 dt3155_status
[minor
].state
|= DT3155_STATE_STOP
;
165 dt3155_status
[minor
].fbuffer
.stop_acquire
= 1;
171 /*****************************************************
172 * dt3155_isr() Interrupt service routien
174 * - looks like this isr supports IRQ sharing (or could) JML
175 * - Assumes irq's are disabled, via SA_INTERRUPT flag
176 * being set in request_irq() call from init_module()
177 *****************************************************/
178 static inline void dt3155_isr( int irq
, void *dev_id
, struct pt_regs
*regs
)
185 /* find out who issued the interrupt */
186 for ( index
= 0; index
< ndevices
; index
++ ) {
187 if( dev_id
== (void*) &dt3155_status
[ index
])
194 /* hopefully we should not get here */
195 if ( minor
< 0 || minor
>= MAXBOARDS
) {
196 printk(KERN_ERR
"dt3155_isr called with invalid dev_id\n");
200 /* Check for corruption and set a flag if so */
201 ReadMReg( (dt3155_lbase
[ minor
] + CSR1
), csr1_r
.reg
);
203 if ( (csr1_r
.fld
.FLD_CRPT_EVE
) || (csr1_r
.fld
.FLD_CRPT_ODD
) )
205 /* TODO: this should probably stop acquisition */
206 /* and set some flags so that dt3155_read */
207 /* returns an error next time it is called */
208 dt3155_errno
= DT_ERR_CORRUPT
;
209 printk("dt3155: corrupt field\n");
213 ReadMReg((dt3155_lbase
[ minor
] + INT_CSR
), int_csr_r
.reg
);
215 /* Handle the even field ... */
216 if (int_csr_r
.fld
.FLD_END_EVE
)
218 if ( (dt3155_status
[ minor
].state
& DT3155_STATE_MODE
) ==
221 dt3155_fbuffer
[ minor
]->frame_count
++;
224 ReadI2C(dt3155_lbase
[ minor
], EVEN_CSR
, &i2c_even_csr
.reg
);
226 /* Clear the interrupt? */
227 int_csr_r
.fld
.FLD_END_EVE
= 1;
229 /* disable the interrupt if last field */
230 if (dt3155_fbuffer
[ minor
]->stop_acquire
)
232 printk("dt3155: even stopped.\n");
233 dt3155_fbuffer
[ minor
]->even_stopped
= 1;
234 if (i2c_even_csr
.fld
.SNGL_EVE
)
236 int_csr_r
.fld
.FLD_END_EVE_EN
= 0;
240 i2c_even_csr
.fld
.SNGL_EVE
= 1;
244 WriteMReg( (dt3155_lbase
[ minor
] + INT_CSR
), int_csr_r
.reg
);
246 /* Set up next DMA if we are doing FIELDS */
247 if ( (dt3155_status
[ minor
].state
& DT3155_STATE_MODE
) ==
250 /* GCS (Aug 2, 2002) -- In field mode, dma the odd field
251 into the lower half of the buffer */
252 const u32 stride
= dt3155_status
[ minor
].config
.cols
;
253 buffer_addr
= dt3155_fbuffer
[ minor
]->
254 frame_info
[ dt3155_fbuffer
[ minor
]->active_buf
].addr
255 + (DT3155_MAX_ROWS
/ 2) * stride
;
256 local_save_flags(flags
);
258 wake_up_interruptible( &dt3155_read_wait_queue
[ minor
] );
260 /* Set up the DMA address for the next field */
261 local_irq_restore(flags
);
262 WriteMReg((dt3155_lbase
[ minor
] + ODD_DMA_START
), buffer_addr
);
265 /* Check for errors. */
266 i2c_even_csr
.fld
.DONE_EVE
= 1;
267 if ( i2c_even_csr
.fld
.ERROR_EVE
)
268 dt3155_errno
= DT_ERR_OVERRUN
;
270 WriteI2C( dt3155_lbase
[ minor
], EVEN_CSR
, i2c_even_csr
.reg
);
272 /* Note that we actually saw an even field meaning */
273 /* that subsequent odd field complete the frame */
274 dt3155_fbuffer
[ minor
]->even_happened
= 1;
276 /* recording the time that the even field finished, this should be */
277 /* about time in the middle of the frame */
278 do_gettimeofday( &(dt3155_fbuffer
[ minor
]->
279 frame_info
[ dt3155_fbuffer
[ minor
]->
280 active_buf
].time
) );
284 /* ... now handle the odd field */
285 if ( int_csr_r
.fld
.FLD_END_ODD
)
287 ReadI2C( dt3155_lbase
[ minor
], ODD_CSR
, &i2c_odd_csr
.reg
);
289 /* Clear the interrupt? */
290 int_csr_r
.fld
.FLD_END_ODD
= 1;
292 if (dt3155_fbuffer
[ minor
]->even_happened
||
293 (dt3155_status
[ minor
].state
& DT3155_STATE_MODE
) ==
296 dt3155_fbuffer
[ minor
]->frame_count
++;
299 if ( dt3155_fbuffer
[ minor
]->stop_acquire
&&
300 dt3155_fbuffer
[ minor
]->even_stopped
)
302 printk(KERN_DEBUG
"dt3155: stopping odd..\n");
303 if ( i2c_odd_csr
.fld
.SNGL_ODD
)
305 /* disable interrupts */
306 int_csr_r
.fld
.FLD_END_ODD_EN
= 0;
307 dt3155_status
[ minor
].state
&= ~(DT3155_STATE_STOP
|0xff);
309 /* mark the system stopped: */
310 dt3155_status
[ minor
].state
|= DT3155_STATE_IDLE
;
311 dt3155_fbuffer
[ minor
]->stop_acquire
= 0;
312 dt3155_fbuffer
[ minor
]->even_stopped
= 0;
314 printk(KERN_DEBUG
"dt3155: state is now %x\n",
315 dt3155_status
[minor
].state
);
319 i2c_odd_csr
.fld
.SNGL_ODD
= 1;
323 WriteMReg( (dt3155_lbase
[ minor
] + INT_CSR
), int_csr_r
.reg
);
325 /* if the odd field has been acquired, then */
326 /* change the next dma location for both fields */
327 /* and wake up the process if sleeping */
328 if ( dt3155_fbuffer
[ minor
]->even_happened
||
329 (dt3155_status
[ minor
].state
& DT3155_STATE_MODE
) ==
333 local_save_flags(flags
);
339 if ( dt3155_fbuffer
[ minor
]->nbuffers
> 2 )
341 if ( !are_empty_buffers( minor
) )
343 /* The number of active + locked buffers is
344 * at most 2, and since there are none empty, there
345 * must be at least nbuffers-2 ready buffers.
346 * This is where we 'drop frames', oldest first. */
347 push_empty( pop_ready( minor
), minor
);
350 /* The ready_que can't be full, since we know
351 * there is one active buffer right now, so it's safe
352 * to push the active buf on the ready_que. */
353 push_ready( minor
, dt3155_fbuffer
[ minor
]->active_buf
);
354 /* There's at least 1 empty -- make it active */
355 dt3155_fbuffer
[ minor
]->active_buf
= pop_empty( minor
);
356 dt3155_fbuffer
[ minor
]->
357 frame_info
[ dt3155_fbuffer
[ minor
]->
358 active_buf
].tag
= ++unique_tag
;
360 else /* nbuffers == 2, special case */
361 { /* There is 1 active buffer.
362 * If there is a locked buffer, keep the active buffer
363 * the same -- that means we drop a frame.
365 if ( dt3155_fbuffer
[ minor
]->locked_buf
< 0 )
368 dt3155_fbuffer
[ minor
]->active_buf
);
369 if (are_empty_buffers( minor
) )
371 dt3155_fbuffer
[ minor
]->active_buf
=
375 { /* no empty or locked buffers, so use a readybuf */
376 dt3155_fbuffer
[ minor
]->active_buf
=
386 dt3155_fbuffer
[ minor
]->even_happened
= 0;
388 wake_up_interruptible( &dt3155_read_wait_queue
[ minor
] );
390 local_irq_restore(flags
);
394 /* Set up the DMA address for the next frame/field */
395 buffer_addr
= dt3155_fbuffer
[ minor
]->
396 frame_info
[ dt3155_fbuffer
[ minor
]->active_buf
].addr
;
397 if ( (dt3155_status
[ minor
].state
& DT3155_STATE_MODE
) ==
400 WriteMReg((dt3155_lbase
[ minor
] + EVEN_DMA_START
), buffer_addr
);
404 WriteMReg((dt3155_lbase
[ minor
] + EVEN_DMA_START
), buffer_addr
);
406 WriteMReg((dt3155_lbase
[ minor
] + ODD_DMA_START
), buffer_addr
407 + dt3155_status
[ minor
].config
.cols
);
410 /* Do error checking */
411 i2c_odd_csr
.fld
.DONE_ODD
= 1;
412 if ( i2c_odd_csr
.fld
.ERROR_ODD
)
413 dt3155_errno
= DT_ERR_OVERRUN
;
415 WriteI2C(dt3155_lbase
[ minor
], ODD_CSR
, i2c_odd_csr
.reg
);
419 /* If we get here, the Odd Field wasn't it either... */
420 printk( "neither even nor odd. shared perhaps?\n");
423 /*****************************************************
424 * init_isr(int minor)
425 * turns on interupt generation for the card
426 * designated by "minor".
427 * It is called *only* from inside ioctl().
428 *****************************************************/
429 static void dt3155_init_isr(int minor
)
431 const u32 stride
= dt3155_status
[ minor
].config
.cols
;
433 switch (dt3155_status
[ minor
].state
& DT3155_STATE_MODE
)
435 case DT3155_STATE_FLD
:
437 even_dma_start_r
= dt3155_status
[ minor
].
438 fbuffer
.frame_info
[ dt3155_status
[ minor
].fbuffer
.active_buf
].addr
;
439 even_dma_stride_r
= 0;
440 odd_dma_stride_r
= 0;
442 WriteMReg((dt3155_lbase
[ minor
] + EVEN_DMA_START
),
444 WriteMReg((dt3155_lbase
[ minor
] + EVEN_DMA_STRIDE
),
446 WriteMReg((dt3155_lbase
[ minor
] + ODD_DMA_STRIDE
),
451 case DT3155_STATE_FRAME
:
454 even_dma_start_r
= dt3155_status
[ minor
].
455 fbuffer
.frame_info
[ dt3155_status
[ minor
].fbuffer
.active_buf
].addr
;
456 odd_dma_start_r
= even_dma_start_r
+ stride
;
457 even_dma_stride_r
= stride
;
458 odd_dma_stride_r
= stride
;
460 WriteMReg((dt3155_lbase
[ minor
] + EVEN_DMA_START
),
462 WriteMReg((dt3155_lbase
[ minor
] + ODD_DMA_START
),
464 WriteMReg((dt3155_lbase
[ minor
] + EVEN_DMA_STRIDE
),
466 WriteMReg((dt3155_lbase
[ minor
] + ODD_DMA_STRIDE
),
472 /* 50/60 Hz should be set before this point but let's make sure it is */
475 ReadI2C(dt3155_lbase
[ minor
], CONFIG
, &i2c_csr2
.reg
);
476 i2c_csr2
.fld
.HZ50
= FORMAT50HZ
;
477 WriteI2C(dt3155_lbase
[ minor
], CONFIG
, i2c_config
.reg
);
479 /* enable busmaster chip, clear flags */
483 * shouldn't we be concered with continuous values of
484 * DT3155_SNAP & DT3155_ACQ here? (SS)
488 csr1_r
.fld
.CAP_CONT_EVE
= 1; /* use continuous capture bits to */
489 csr1_r
.fld
.CAP_CONT_ODD
= 1; /* enable */
490 csr1_r
.fld
.FLD_DN_EVE
= 1; /* writing a 1 clears flags */
491 csr1_r
.fld
.FLD_DN_ODD
= 1;
492 csr1_r
.fld
.SRST
= 1; /* reset - must be 1 */
493 csr1_r
.fld
.FIFO_EN
= 1; /* fifo control - must be 1 */
494 csr1_r
.fld
.FLD_CRPT_EVE
= 1; /* writing a 1 clears flags */
495 csr1_r
.fld
.FLD_CRPT_ODD
= 1;
497 WriteMReg((dt3155_lbase
[ minor
] + CSR1
),csr1_r
.reg
);
499 /* Enable interrupts at the end of each field */
502 int_csr_r
.fld
.FLD_END_EVE_EN
= 1;
503 int_csr_r
.fld
.FLD_END_ODD_EN
= 1;
504 int_csr_r
.fld
.FLD_START_EN
= 0;
506 WriteMReg((dt3155_lbase
[ minor
] + INT_CSR
), int_csr_r
.reg
);
508 /* start internal BUSY bits */
510 ReadI2C(dt3155_lbase
[ minor
], CSR2
, &i2c_csr2
.reg
);
511 i2c_csr2
.fld
.BUSY_ODD
= 1;
512 i2c_csr2
.fld
.BUSY_EVE
= 1;
513 WriteI2C(dt3155_lbase
[ minor
], CSR2
, i2c_csr2
.reg
);
515 /* Now its up to the interrupt routine!! */
521 /*****************************************************
524 *****************************************************/
525 static int dt3155_ioctl(struct inode
*inode
,
530 int minor
= MINOR(inode
->i_rdev
); /* What device are we ioctl()'ing? */
532 if ( minor
>= MAXBOARDS
|| minor
< 0 )
535 /* make sure it is valid command */
536 if (_IOC_NR(cmd
) > DT3155_IOC_MAXNR
)
538 printk("DT3155: invalid IOCTL(0x%x)\n",cmd
);
539 printk("DT3155: Valid commands (0x%x), (0x%x), (0x%x), (0x%x), (0x%x)\n",
540 (unsigned int)DT3155_GET_CONFIG
,
541 (unsigned int)DT3155_SET_CONFIG
,
542 (unsigned int)DT3155_START
,
543 (unsigned int)DT3155_STOP
,
544 (unsigned int)DT3155_FLUSH
);
550 case DT3155_SET_CONFIG
:
552 if (dt3155_status
[minor
].state
!= DT3155_STATE_IDLE
)
556 struct dt3155_config_s tmp
;
557 if (copy_from_user((void *)&tmp
, (void *) arg
, sizeof(tmp
)))
559 /* check for valid settings */
560 if (tmp
.rows
> DT3155_MAX_ROWS
||
561 tmp
.cols
> DT3155_MAX_COLS
||
562 (tmp
.acq_mode
!= DT3155_MODE_FRAME
&&
563 tmp
.acq_mode
!= DT3155_MODE_FIELD
) ||
564 (tmp
.continuous
!= DT3155_SNAP
&&
565 tmp
.continuous
!= DT3155_ACQ
))
569 dt3155_status
[minor
].config
= tmp
;
573 case DT3155_GET_CONFIG
:
575 if (copy_to_user((void *) arg
, (void *) &dt3155_status
[minor
],
576 sizeof(dt3155_status_t
) ))
580 case DT3155_FLUSH
: /* Flushes the buffers -- ensures fresh data */
582 if (dt3155_status
[minor
].state
!= DT3155_STATE_IDLE
)
584 return dt3155_flush(minor
);
588 if (dt3155_status
[minor
].state
& DT3155_STATE_STOP
||
589 dt3155_status
[minor
].fbuffer
.stop_acquire
)
592 if (dt3155_status
[minor
].state
== DT3155_STATE_IDLE
)
596 if (copy_to_user((void *) arg
, (void *) &dt3155_status
[minor
],
597 sizeof(dt3155_status_t
)))
603 if (dt3155_status
[minor
].state
!= DT3155_STATE_IDLE
)
606 dt3155_status
[minor
].fbuffer
.stop_acquire
= 0;
607 dt3155_status
[minor
].fbuffer
.frame_count
= 0;
609 /* Set the MODE in the status -- we default to FRAME */
610 if (dt3155_status
[minor
].config
.acq_mode
== DT3155_MODE_FIELD
)
612 dt3155_status
[minor
].state
= DT3155_STATE_FLD
;
616 dt3155_status
[minor
].state
= DT3155_STATE_FRAME
;
619 dt3155_init_isr(minor
);
620 if (copy_to_user( (void *) arg
, (void *) &dt3155_status
[minor
],
621 sizeof(dt3155_status_t
)))
627 printk("DT3155: invalid IOCTL(0x%x)\n",cmd
);
628 printk("DT3155: Valid commands (0x%x), (0x%x), (0x%x), (0x%x), (0x%x)\n",
629 (unsigned int)DT3155_GET_CONFIG
,
630 (unsigned int)DT3155_SET_CONFIG
,
631 DT3155_START
, DT3155_STOP
, DT3155_FLUSH
);
638 /*****************************************************
641 * only allow the user to mmap the registers and buffer
642 * It is quite possible that this is broken, since the
643 * addition of of the capacity for two cards!!!!!!!!
644 * It *looks* like it should work but since I'm not
645 * sure how to use it, I'm not actually sure. (NJC? ditto by SS)
646 *****************************************************/
647 static int dt3155_mmap (struct file
* file
, struct vm_area_struct
* vma
)
649 /* which device are we mmapping? */
650 int minor
= MINOR(file
->f_dentry
->d_inode
->i_rdev
);
651 unsigned long offset
;
652 offset
= vma
->vm_pgoff
<< PAGE_SHIFT
;
654 if (offset
>= __pa(high_memory
) || (file
->f_flags
& O_SYNC
))
655 vma
->vm_flags
|= VM_IO
;
657 /* Don't try to swap out physical pages.. */
658 vma
->vm_flags
|= VM_RESERVED
;
660 /* they are mapping the registers or the buffer */
661 if ((offset
== dt3155_status
[minor
].reg_addr
&&
662 vma
->vm_end
- vma
->vm_start
== PCI_PAGE_SIZE
) ||
663 (offset
== dt3155_status
[minor
].mem_addr
&&
664 vma
->vm_end
- vma
->vm_start
== dt3155_status
[minor
].mem_size
))
666 if (remap_pfn_range(vma
,
668 offset
>> PAGE_SHIFT
,
669 vma
->vm_end
- vma
->vm_start
,
670 vma
->vm_page_prot
)) {
671 printk("DT3155: remap_page_range() failed.\n");
677 printk("DT3155: dt3155_mmap() bad call.\n");
685 /*****************************************************
688 * Our special open code.
689 * MOD_INC_USE_COUNT make sure that the driver memory is not freed
690 * while the device is in use.
691 *****************************************************/
692 static int dt3155_open( struct inode
* inode
, struct file
* filep
)
694 int minor
= MINOR(inode
->i_rdev
); /* what device are we opening? */
695 if (dt3155_dev_open
[ minor
]) {
696 printk ("DT3155: Already opened by another process.\n");
700 if (dt3155_status
[ minor
].device_installed
==0)
702 printk("DT3155 Open Error: No such device dt3155 minor number %d\n",
707 if (dt3155_status
[ minor
].state
!= DT3155_STATE_IDLE
) {
708 printk ("DT3155: Not in idle state (state = %x)\n",
709 dt3155_status
[ minor
].state
);
713 printk("DT3155: Device opened.\n");
715 dt3155_dev_open
[ minor
] = 1 ;
717 dt3155_flush( minor
);
719 /* Disable ALL interrupts */
721 WriteMReg( (dt3155_lbase
[ minor
] + INT_CSR
), int_csr_r
.reg
);
723 init_waitqueue_head(&(dt3155_read_wait_queue
[minor
]));
729 /*****************************************************
732 * Now decrement the use count.
734 *****************************************************/
735 static int dt3155_close( struct inode
*inode
, struct file
*filep
)
739 minor
= MINOR(inode
->i_rdev
); /* which device are we closing */
740 if (!dt3155_dev_open
[ minor
])
742 printk("DT3155: attempt to CLOSE a not OPEN device\n");
746 dt3155_dev_open
[ minor
] = 0;
748 if (dt3155_status
[ minor
].state
!= DT3155_STATE_IDLE
)
756 /*****************************************************
759 *****************************************************/
760 static ssize_t
dt3155_read(struct file
*filep
, char __user
*buf
,
761 size_t count
, loff_t
*ppos
)
763 /* which device are we reading from? */
764 int minor
= MINOR(filep
->f_dentry
->d_inode
->i_rdev
);
767 frame_info_t
*frame_info_p
;
769 /* TODO: this should check the error flag and */
770 /* return an error on hardware failures */
771 if (count
!= sizeof(dt3155_read_t
))
773 printk("DT3155 ERROR (NJC): count is not right\n");
778 /* Hack here -- I'm going to allow reading even when idle.
779 * this is so that the frames can be read after STOP has
780 * been called. Leaving it here, commented out, as a reminder
781 * for a short while to make sure there are no problems.
782 * Note that if the driver is not opened in non_blocking mode,
783 * and the device is idle, then it could sit here forever! */
785 /* if (dt3155_status[minor].state == DT3155_STATE_IDLE)*/
788 /* non-blocking reads should return if no data */
789 if (filep
->f_flags
& O_NDELAY
)
791 if ((frame_index
= dt3155_get_ready_buffer(minor
)) < 0) {
792 /*printk( "dt3155: no buffers available (?)\n");*/
793 /* printques(minor); */
800 * sleep till data arrives , or we get interrupted.
801 * Note that wait_event_interruptible() does not actually
802 * sleep/wait if it's condition evaluates to true upon entry.
804 wait_event_interruptible(dt3155_read_wait_queue
[minor
],
805 (frame_index
= dt3155_get_ready_buffer(minor
))
810 printk ("DT3155: read: interrupted\n");
817 frame_info_p
= &dt3155_status
[minor
].fbuffer
.frame_info
[frame_index
];
819 /* make this an offset */
820 offset
= frame_info_p
->addr
- dt3155_status
[minor
].mem_addr
;
822 put_user(offset
, (unsigned int *) buf
);
824 put_user( dt3155_status
[minor
].fbuffer
.frame_count
, (unsigned int *) buf
);
826 put_user(dt3155_status
[minor
].state
, (unsigned int *) buf
);
828 if (copy_to_user(buf
, frame_info_p
, sizeof(frame_info_t
)))
831 return sizeof(dt3155_read_t
);
834 static unsigned int dt3155_poll (struct file
* filp
, poll_table
*wait
)
836 int minor
= MINOR(filp
->f_dentry
->d_inode
->i_rdev
);
838 if (!is_ready_buf_empty(minor
))
839 return POLLIN
| POLLRDNORM
;
841 poll_wait (filp
, &dt3155_read_wait_queue
[minor
], wait
);
847 /*****************************************************
848 * file operations supported by DT3155 driver
849 * needed by init_module
851 *****************************************************/
852 static struct file_operations dt3155_fops
= {
858 release
: dt3155_close
862 /*****************************************************
865 * PCI has been totally reworked in 2.1..
866 *****************************************************/
867 static int find_PCI (void)
869 struct pci_dev
*pci_dev
= NULL
;
870 int error
, pci_index
= 0;
871 unsigned short rev_device
;
875 while ((pci_dev
= pci_get_device
876 (DT3155_VENDORID
, DT3155_DEVICEID
, pci_dev
)) != NULL
)
880 /* Is it really there? */
882 pci_read_config_word(pci_dev
, PCI_CLASS_DEVICE
, &rev_device
)))
886 DT_3155_DEBUG_MSG("DT3155: Device number %d \n", pci_index
);
888 /* Make sure the driver was compiled with enough buffers to handle
890 if (pci_index
> MAXBOARDS
) {
891 printk("DT3155: ERROR - found %d devices, but driver only configured "
893 "DT3155: Please change MAXBOARDS in dt3155.h\n",
894 pci_index
, MAXBOARDS
);
898 /* Now, just go out and make sure that this/these device(s) is/are
899 actually mapped into the kernel address space */
900 if ((error
= pci_read_config_dword( pci_dev
, PCI_BASE_ADDRESS_0
,
903 printk("DT3155: Was not able to find device \n");
907 DT_3155_DEBUG_MSG("DT3155: Base address 0 for device is %lx \n", base
);
908 dt3155_status
[pci_index
-1].reg_addr
= base
;
910 /* Remap the base address to a logical address through which we
912 dt3155_lbase
[ pci_index
- 1 ] = ioremap(base
,PCI_PAGE_SIZE
);
913 dt3155_status
[ pci_index
- 1 ].reg_addr
= base
;
914 DT_3155_DEBUG_MSG("DT3155: New logical address is %p \n",
915 dt3155_lbase
[pci_index
-1]);
916 if ( !dt3155_lbase
[pci_index
-1] )
918 printk("DT3155: Unable to remap control registers\n");
922 if ( (error
= pci_read_config_byte( pci_dev
, PCI_INTERRUPT_LINE
, &irq
)) )
924 printk("DT3155: Was not able to find device \n");
928 DT_3155_DEBUG_MSG("DT3155: IRQ is %d \n",irq
);
929 dt3155_status
[ pci_index
-1 ].irq
= irq
;
930 /* Set flag: kth device found! */
931 dt3155_status
[ pci_index
-1 ].device_installed
= 1;
932 printk("DT3155: Installing device %d w/irq %d and address %p\n",
934 dt3155_status
[pci_index
-1].irq
,
935 dt3155_lbase
[pci_index
-1]);
938 ndevices
= pci_index
;
940 return DT_3155_SUCCESS
;
943 pci_dev_put(pci_dev
);
944 return DT_3155_FAILURE
;
947 u32 allocatorAddr
= 0;
949 /*****************************************************
951 *****************************************************/
952 int init_module(void)
956 char *devname
[ MAXBOARDS
];
958 devname
[ 0 ] = "dt3155a";
960 devname
[ 1 ] = "dt3155b";
963 printk("DT3155: Loading module...\n");
965 /* Register the device driver */
966 rcode
= register_chrdev( dt3155_major
, "dt3155", &dt3155_fops
);
969 printk( KERN_INFO
"DT3155: register_chrdev failed \n");
973 if( dt3155_major
== 0 )
974 dt3155_major
= rcode
; /* dynamic */
977 /* init the status variables. */
978 /* DMA memory is taken care of in setup_buffers() */
979 for ( index
= 0; index
< MAXBOARDS
; index
++ )
981 dt3155_status
[ index
].config
.acq_mode
= DT3155_MODE_FRAME
;
982 dt3155_status
[ index
].config
.continuous
= DT3155_ACQ
;
983 dt3155_status
[ index
].config
.cols
= DT3155_MAX_COLS
;
984 dt3155_status
[ index
].config
.rows
= DT3155_MAX_ROWS
;
985 dt3155_status
[ index
].state
= DT3155_STATE_IDLE
;
987 /* find_PCI() will check if devices are installed; */
988 /* first assume they're not: */
989 dt3155_status
[ index
].mem_addr
= 0;
990 dt3155_status
[ index
].mem_size
= 0;
991 dt3155_status
[ index
].state
= DT3155_STATE_IDLE
;
992 dt3155_status
[ index
].device_installed
= 0;
995 /* Now let's find the hardware. find_PCI() will set ndevices to the
996 * number of cards found in this machine. */
998 if ( (rcode
= find_PCI()) != DT_3155_SUCCESS
)
1000 printk("DT3155 error: find_PCI() failed to find dt3155 board(s)\n");
1001 unregister_chrdev( dt3155_major
, "dt3155" );
1006 /* Ok, time to setup the frame buffers */
1007 if( (rcode
= dt3155_setup_buffers(&allocatorAddr
)) < 0 )
1009 printk("DT3155: Error: setting up buffer not large enough.");
1010 unregister_chrdev( dt3155_major
, "dt3155" );
1014 /* If we are this far, then there is enough RAM */
1015 /* for the buffers: Print the configuration. */
1016 for( index
= 0; index
< ndevices
; index
++ )
1018 printk("DT3155: Device = %d; acq_mode = %d; "
1019 "continuous = %d; cols = %d; rows = %d;\n",
1021 dt3155_status
[ index
].config
.acq_mode
,
1022 dt3155_status
[ index
].config
.continuous
,
1023 dt3155_status
[ index
].config
.cols
,
1024 dt3155_status
[ index
].config
.rows
);
1025 printk("DT3155: m_addr = 0x%x; m_size = %ld; "
1026 "state = %d; device_installed = %d\n",
1027 dt3155_status
[ index
].mem_addr
,
1028 (long int)dt3155_status
[ index
].mem_size
,
1029 dt3155_status
[ index
].state
,
1030 dt3155_status
[ index
].device_installed
);
1033 /* Disable ALL interrupts */
1035 for( index
= 0; index
< ndevices
; index
++ )
1037 WriteMReg( (dt3155_lbase
[ index
] + INT_CSR
), int_csr_r
.reg
);
1038 if( dt3155_status
[ index
].device_installed
)
1041 * This driver *looks* like it can handle sharing interrupts,
1042 * but I can't actually test myself. I've had reports that it
1043 * DOES work so I'll enable it for now. This comment will remain
1044 * as a reminder in case any problems arise. (SS)
1046 /* in older kernels flags are: SA_SHIRQ | SA_INTERRUPT */
1047 rcode
= request_irq( dt3155_status
[ index
].irq
, (void *)dt3155_isr
,
1048 IRQF_SHARED
| IRQF_DISABLED
, devname
[ index
],
1049 (void*) &dt3155_status
[index
]);
1052 printk("DT3155: minor %d request_irq failed for IRQ %d\n",
1053 index
, dt3155_status
[index
].irq
);
1054 unregister_chrdev( dt3155_major
, "dt3155" );
1060 printk("DT3155: finished loading\n");
1065 /*****************************************************
1066 * cleanup_module(void)
1068 *****************************************************/
1069 void cleanup_module(void)
1073 printk("DT3155: cleanup_module called\n");
1075 /* removed DMA allocated with the allocator */
1076 #ifdef STANDALONE_ALLOCATOR
1077 if (allocatorAddr
!= 0)
1078 allocator_free_dma(allocatorAddr
);
1080 allocator_cleanup();
1083 unregister_chrdev( dt3155_major
, "dt3155" );
1085 for( index
= 0; index
< ndevices
; index
++ )
1087 if( dt3155_status
[ index
].device_installed
== 1 )
1089 printk( "DT3155: Freeing irq %d for device %d\n",
1090 dt3155_status
[ index
].irq
, index
);
1091 free_irq( dt3155_status
[ index
].irq
, (void*)&dt3155_status
[index
] );