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/version.h>
63 #include <linux/interrupt.h>
66 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,10)
67 MODULE_LICENSE("GPL");
73 #error "DT3155 : Kernel PCI support not enabled (DT3155 drive requires PCI)"
76 #include <linux/pci.h>
77 #include <linux/types.h>
78 #include <linux/poll.h>
79 #include <linux/sched.h>
82 #include <asm/uaccess.h>
85 #include "dt3155_drv.h"
86 #include "dt3155_isr.h"
87 #include "dt3155_io.h"
88 #include "allocator.h"
90 /* Error variable. Zero means no error. */
93 #ifndef PCI_DEVICE_ID_INTEL_7116
94 #define PCI_DEVICE_ID_INTEL_7116 0x1223
97 #define DT3155_VENDORID PCI_VENDOR_ID_INTEL
98 #define DT3155_DEVICEID PCI_DEVICE_ID_INTEL_7116
102 #define DT_3155_DEBUG_MSG(x,y) printk(x,y)
104 #define DT_3155_DEBUG_MSG(x,y)
107 /* wait queue for interrupts */
108 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,1)
109 wait_queue_head_t dt3155_read_wait_queue[ MAXBOARDS ];
111 struct wait_queue *dt3155_read_wait_queue[ MAXBOARDS ];
114 #define DT_3155_SUCCESS 0
115 #define DT_3155_FAILURE -EIO
117 /* set to dynamicaly allocate, but it is tunable: */
118 /* insmod DT_3155 dt3155 dt3155_major=XX */
119 int dt3155_major = 0;
121 /* The minor numbers are 0 and 1 ... they are not tunable.
122 * They are used as the indices for the structure vectors,
123 * and register address vectors
126 /* Global structures and variables */
128 /* Status of each device */
129 struct dt3155_status_s dt3155_status[ MAXBOARDS ];
131 /* kernel logical address of the board */
132 u_char *dt3155_lbase[ MAXBOARDS ] = { NULL
137 /* DT3155 registers */
138 u_char *dt3155_bbase = NULL; /* kernel logical address of the *
140 u_int dt3155_dev_open[ MAXBOARDS ] = {0
147 u_long unique_tag = 0;;
151 * Stops interrupt generation right away and resets the status
152 * to idle. I don't know why this works and the other way doesn't.
155 static void quick_stop (int minor)
157 // TODO: scott was here
159 ReadMReg((dt3155_lbase[ minor ] + INT_CSR), int_csr_r.reg);
160 /* disable interrupts */
161 int_csr_r.fld.FLD_END_EVE_EN = 0;
162 int_csr_r.fld.FLD_END_ODD_EN = 0;
163 WriteMReg((dt3155_lbase[ minor ] + INT_CSR), int_csr_r.reg );
165 dt3155_status[ minor ].state &= ~(DT3155_STATE_STOP|0xff);
166 /* mark the system stopped: */
167 dt3155_status[ minor ].state |= DT3155_STATE_IDLE;
168 dt3155_fbuffer[ minor ]->stop_acquire = 0;
169 dt3155_fbuffer[ minor ]->even_stopped = 0;
171 dt3155_status[minor].state |= DT3155_STATE_STOP;
172 dt3155_status[minor].fbuffer.stop_acquire = 1;
178 /*****************************************************
179 * dt3155_isr() Interrupt service routien
181 * - looks like this isr supports IRQ sharing (or could) JML
182 * - Assumes irq's are disabled, via SA_INTERRUPT flag
183 * being set in request_irq() call from init_module()
184 *****************************************************/
185 static inline void dt3155_isr( int irq, void *dev_id, struct pt_regs *regs )
189 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
196 /* find out who issued the interrupt */
197 for ( index = 0; index < ndevices; index++ ) {
198 if( dev_id == (void*) &dt3155_status[ index ])
205 /* hopefully we should not get here */
206 if ( minor < 0 || minor >= MAXBOARDS ) {
207 printk(KERN_ERR "dt3155_isr called with invalid dev_id\n");
211 /* Check for corruption and set a flag if so */
212 ReadMReg( (dt3155_lbase[ minor ] + CSR1), csr1_r.reg );
214 if ( (csr1_r.fld.FLD_CRPT_EVE) || (csr1_r.fld.FLD_CRPT_ODD) )
216 /* TODO: this should probably stop acquisition */
217 /* and set some flags so that dt3155_read */
218 /* returns an error next time it is called */
219 dt3155_errno = DT_ERR_CORRUPT;
220 printk("dt3155: corrupt field\n");
224 ReadMReg((dt3155_lbase[ minor ] + INT_CSR), int_csr_r.reg);
226 /* Handle the even field ... */
227 if (int_csr_r.fld.FLD_END_EVE)
229 if ( (dt3155_status[ minor ].state & DT3155_STATE_MODE) ==
232 dt3155_fbuffer[ minor ]->frame_count++;
235 ReadI2C(dt3155_lbase[ minor ], EVEN_CSR, &i2c_even_csr.reg);
237 /* Clear the interrupt? */
238 int_csr_r.fld.FLD_END_EVE = 1;
240 /* disable the interrupt if last field */
241 if (dt3155_fbuffer[ minor ]->stop_acquire)
243 printk("dt3155: even stopped.\n");
244 dt3155_fbuffer[ minor ]->even_stopped = 1;
245 if (i2c_even_csr.fld.SNGL_EVE)
247 int_csr_r.fld.FLD_END_EVE_EN = 0;
251 i2c_even_csr.fld.SNGL_EVE = 1;
255 WriteMReg( (dt3155_lbase[ minor ] + INT_CSR), int_csr_r.reg );
257 /* Set up next DMA if we are doing FIELDS */
258 if ( (dt3155_status[ minor ].state & DT3155_STATE_MODE ) ==
261 /* GCS (Aug 2, 2002) -- In field mode, dma the odd field
262 into the lower half of the buffer */
263 const u_long stride = dt3155_status[ minor ].config.cols;
264 buffer_addr = dt3155_fbuffer[ minor ]->
265 frame_info[ dt3155_fbuffer[ minor ]->active_buf ].addr
266 + (DT3155_MAX_ROWS / 2) * stride;
267 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
268 local_save_flags(flags);
274 wake_up_interruptible( &dt3155_read_wait_queue[ minor ] );
276 /* Set up the DMA address for the next field */
277 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
278 local_irq_restore(flags);
280 restore_flags( flags );
282 WriteMReg((dt3155_lbase[ minor ] + ODD_DMA_START), buffer_addr);
285 /* Check for errors. */
286 i2c_even_csr.fld.DONE_EVE = 1;
287 if ( i2c_even_csr.fld.ERROR_EVE )
288 dt3155_errno = DT_ERR_OVERRUN;
290 WriteI2C( dt3155_lbase[ minor ], EVEN_CSR, i2c_even_csr.reg );
292 /* Note that we actually saw an even field meaning */
293 /* that subsequent odd field complete the frame */
294 dt3155_fbuffer[ minor ]->even_happened = 1;
296 /* recording the time that the even field finished, this should be */
297 /* about time in the middle of the frame */
298 do_gettimeofday( &(dt3155_fbuffer[ minor ]->
299 frame_info[ dt3155_fbuffer[ minor ]->
300 active_buf ].time) );
304 /* ... now handle the odd field */
305 if ( int_csr_r.fld.FLD_END_ODD )
307 ReadI2C( dt3155_lbase[ minor ], ODD_CSR, &i2c_odd_csr.reg );
309 /* Clear the interrupt? */
310 int_csr_r.fld.FLD_END_ODD = 1;
312 if (dt3155_fbuffer[ minor ]->even_happened ||
313 (dt3155_status[ minor ].state & DT3155_STATE_MODE) ==
316 dt3155_fbuffer[ minor ]->frame_count++;
319 if ( dt3155_fbuffer[ minor ]->stop_acquire &&
320 dt3155_fbuffer[ minor ]->even_stopped )
322 printk(KERN_DEBUG "dt3155: stopping odd..\n");
323 if ( i2c_odd_csr.fld.SNGL_ODD )
325 /* disable interrupts */
326 int_csr_r.fld.FLD_END_ODD_EN = 0;
327 dt3155_status[ minor ].state &= ~(DT3155_STATE_STOP|0xff);
329 /* mark the system stopped: */
330 dt3155_status[ minor ].state |= DT3155_STATE_IDLE;
331 dt3155_fbuffer[ minor ]->stop_acquire = 0;
332 dt3155_fbuffer[ minor ]->even_stopped = 0;
334 printk(KERN_DEBUG "dt3155: state is now %lx\n",
335 dt3155_status[minor].state);
339 i2c_odd_csr.fld.SNGL_ODD = 1;
343 WriteMReg( (dt3155_lbase[ minor ] + INT_CSR), int_csr_r.reg );
345 /* if the odd field has been acquired, then */
346 /* change the next dma location for both fields */
347 /* and wake up the process if sleeping */
348 if ( dt3155_fbuffer[ minor ]->even_happened ||
349 (dt3155_status[ minor ].state & DT3155_STATE_MODE) ==
353 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
354 local_save_flags(flags);
364 if ( dt3155_fbuffer[ minor ]->nbuffers > 2 )
366 if ( !are_empty_buffers( minor ) )
368 /* The number of active + locked buffers is
369 * at most 2, and since there are none empty, there
370 * must be at least nbuffers-2 ready buffers.
371 * This is where we 'drop frames', oldest first. */
372 push_empty( pop_ready( minor ), minor );
375 /* The ready_que can't be full, since we know
376 * there is one active buffer right now, so it's safe
377 * to push the active buf on the ready_que. */
378 push_ready( minor, dt3155_fbuffer[ minor ]->active_buf );
379 /* There's at least 1 empty -- make it active */
380 dt3155_fbuffer[ minor ]->active_buf = pop_empty( minor );
381 dt3155_fbuffer[ minor ]->
382 frame_info[ dt3155_fbuffer[ minor ]->
383 active_buf ].tag = ++unique_tag;
385 else /* nbuffers == 2, special case */
386 { /* There is 1 active buffer.
387 * If there is a locked buffer, keep the active buffer
388 * the same -- that means we drop a frame.
390 if ( dt3155_fbuffer[ minor ]->locked_buf < 0 )
393 dt3155_fbuffer[ minor ]->active_buf );
394 if (are_empty_buffers( minor ) )
396 dt3155_fbuffer[ minor ]->active_buf =
400 { /* no empty or locked buffers, so use a readybuf */
401 dt3155_fbuffer[ minor ]->active_buf =
411 dt3155_fbuffer[ minor ]->even_happened = 0;
413 wake_up_interruptible( &dt3155_read_wait_queue[ minor ] );
415 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
416 local_irq_restore(flags);
418 restore_flags( flags );
423 /* Set up the DMA address for the next frame/field */
424 buffer_addr = dt3155_fbuffer[ minor ]->
425 frame_info[ dt3155_fbuffer[ minor ]->active_buf ].addr;
426 if ( (dt3155_status[ minor ].state & DT3155_STATE_MODE) ==
429 WriteMReg((dt3155_lbase[ minor ] + EVEN_DMA_START), buffer_addr);
433 WriteMReg((dt3155_lbase[ minor ] + EVEN_DMA_START), buffer_addr);
435 WriteMReg((dt3155_lbase[ minor ] + ODD_DMA_START), buffer_addr
436 + dt3155_status[ minor ].config.cols);
439 /* Do error checking */
440 i2c_odd_csr.fld.DONE_ODD = 1;
441 if ( i2c_odd_csr.fld.ERROR_ODD )
442 dt3155_errno = DT_ERR_OVERRUN;
444 WriteI2C(dt3155_lbase[ minor ], ODD_CSR, i2c_odd_csr.reg );
448 /* If we get here, the Odd Field wasn't it either... */
449 printk( "neither even nor odd. shared perhaps?\n");
452 /*****************************************************
453 * init_isr(int minor)
454 * turns on interupt generation for the card
455 * designated by "minor".
456 * It is called *only* from inside ioctl().
457 *****************************************************/
458 static void dt3155_init_isr(int minor)
460 const u_long stride = dt3155_status[ minor ].config.cols;
462 switch (dt3155_status[ minor ].state & DT3155_STATE_MODE)
464 case DT3155_STATE_FLD:
466 even_dma_start_r = dt3155_status[ minor ].
467 fbuffer.frame_info[ dt3155_status[ minor ].fbuffer.active_buf ].addr;
468 even_dma_stride_r = 0;
469 odd_dma_stride_r = 0;
471 WriteMReg((dt3155_lbase[ minor ] + EVEN_DMA_START),
473 WriteMReg((dt3155_lbase[ minor ] + EVEN_DMA_STRIDE),
475 WriteMReg((dt3155_lbase[ minor ] + ODD_DMA_STRIDE),
480 case DT3155_STATE_FRAME:
483 even_dma_start_r = dt3155_status[ minor ].
484 fbuffer.frame_info[ dt3155_status[ minor ].fbuffer.active_buf ].addr;
485 odd_dma_start_r = even_dma_start_r + stride;
486 even_dma_stride_r = stride;
487 odd_dma_stride_r = stride;
489 WriteMReg((dt3155_lbase[ minor ] + EVEN_DMA_START),
491 WriteMReg((dt3155_lbase[ minor ] + ODD_DMA_START),
493 WriteMReg((dt3155_lbase[ minor ] + EVEN_DMA_STRIDE),
495 WriteMReg((dt3155_lbase[ minor ] + ODD_DMA_STRIDE),
501 /* 50/60 Hz should be set before this point but let's make sure it is */
504 ReadI2C(dt3155_lbase[ minor ], CONFIG, &i2c_csr2.reg);
505 i2c_csr2.fld.HZ50 = FORMAT50HZ;
506 WriteI2C(dt3155_lbase[ minor ], CONFIG, i2c_config.reg);
508 /* enable busmaster chip, clear flags */
512 * shouldn't we be concered with continuous values of
513 * DT3155_SNAP & DT3155_ACQ here? (SS)
517 csr1_r.fld.CAP_CONT_EVE = 1; /* use continuous capture bits to */
518 csr1_r.fld.CAP_CONT_ODD = 1; /* enable */
519 csr1_r.fld.FLD_DN_EVE = 1; /* writing a 1 clears flags */
520 csr1_r.fld.FLD_DN_ODD = 1;
521 csr1_r.fld.SRST = 1; /* reset - must be 1 */
522 csr1_r.fld.FIFO_EN = 1; /* fifo control - must be 1 */
523 csr1_r.fld.FLD_CRPT_EVE = 1; /* writing a 1 clears flags */
524 csr1_r.fld.FLD_CRPT_ODD = 1;
526 WriteMReg((dt3155_lbase[ minor ] + CSR1),csr1_r.reg);
528 /* Enable interrupts at the end of each field */
531 int_csr_r.fld.FLD_END_EVE_EN = 1;
532 int_csr_r.fld.FLD_END_ODD_EN = 1;
533 int_csr_r.fld.FLD_START_EN = 0;
535 WriteMReg((dt3155_lbase[ minor ] + INT_CSR), int_csr_r.reg);
537 /* start internal BUSY bits */
539 ReadI2C(dt3155_lbase[ minor ], CSR2, &i2c_csr2.reg);
540 i2c_csr2.fld.BUSY_ODD = 1;
541 i2c_csr2.fld.BUSY_EVE = 1;
542 WriteI2C(dt3155_lbase[ minor ], CSR2, i2c_csr2.reg);
544 /* Now its up to the interrupt routine!! */
550 /*****************************************************
553 *****************************************************/
554 static int dt3155_ioctl (
560 int minor = MINOR(inode->i_rdev); /* What device are we ioctl()'ing? */
562 if ( minor >= MAXBOARDS || minor < 0 )
565 /* make sure it is valid command */
566 if (_IOC_NR(cmd) > DT3155_IOC_MAXNR)
568 printk("DT3155: invalid IOCTL(0x%x)\n",cmd);
569 printk("DT3155: Valid commands (0x%x), (0x%x), (0x%x), (0x%x), (0x%x)\n",
570 DT3155_GET_CONFIG, DT3155_SET_CONFIG,
571 DT3155_START, DT3155_STOP, DT3155_FLUSH);
577 case DT3155_SET_CONFIG:
579 if (dt3155_status[minor].state != DT3155_STATE_IDLE)
583 struct dt3155_config_s tmp;
584 if (copy_from_user((void *)&tmp, (void *) arg, sizeof(tmp)))
586 /* check for valid settings */
587 if (tmp.rows > DT3155_MAX_ROWS ||
588 tmp.cols > DT3155_MAX_COLS ||
589 (tmp.acq_mode != DT3155_MODE_FRAME &&
590 tmp.acq_mode != DT3155_MODE_FIELD) ||
591 (tmp.continuous != DT3155_SNAP &&
592 tmp.continuous != DT3155_ACQ))
596 dt3155_status[minor].config = tmp;
600 case DT3155_GET_CONFIG:
602 if (copy_to_user((void *) arg, (void *) &dt3155_status[minor],
603 sizeof(dt3155_status_t) ))
607 case DT3155_FLUSH: /* Flushes the buffers -- ensures fresh data */
609 if (dt3155_status[minor].state != DT3155_STATE_IDLE)
611 return dt3155_flush(minor);
615 if (dt3155_status[minor].state & DT3155_STATE_STOP ||
616 dt3155_status[minor].fbuffer.stop_acquire)
619 if (dt3155_status[minor].state == DT3155_STATE_IDLE)
623 if (copy_to_user((void *) arg, (void *) &dt3155_status[minor],
624 sizeof(dt3155_status_t)))
630 if (dt3155_status[minor].state != DT3155_STATE_IDLE)
633 dt3155_status[minor].fbuffer.stop_acquire = 0;
634 dt3155_status[minor].fbuffer.frame_count = 0;
636 /* Set the MODE in the status -- we default to FRAME */
637 if (dt3155_status[minor].config.acq_mode == DT3155_MODE_FIELD)
639 dt3155_status[minor].state = DT3155_STATE_FLD;
643 dt3155_status[minor].state = DT3155_STATE_FRAME;
646 dt3155_init_isr(minor);
647 if (copy_to_user( (void *) arg, (void *) &dt3155_status[minor],
648 sizeof(dt3155_status_t)))
654 printk("DT3155: invalid IOCTL(0x%x)\n",cmd);
655 printk("DT3155: Valid commands (0x%x), (0x%x), (0x%x), (0x%x), (0x%x)\n",
656 DT3155_GET_CONFIG, DT3155_SET_CONFIG,
657 DT3155_START, DT3155_STOP, DT3155_FLUSH);
664 /*****************************************************
667 * only allow the user to mmap the registers and buffer
668 * It is quite possible that this is broken, since the
669 * addition of of the capacity for two cards!!!!!!!!
670 * It *looks* like it should work but since I'm not
671 * sure how to use it, I'm not actually sure. (NJC? ditto by SS)
672 *****************************************************/
673 static int dt3155_mmap (struct file * file, struct vm_area_struct * vma)
675 /* which device are we mmapping? */
676 int minor = MINOR(file->f_dentry->d_inode->i_rdev);
677 unsigned long offset;
679 /* not actually sure when vm_area_struct changed,
680 but it was in 2.3 sometime */
681 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,20)
683 offset = vma->vm_pgoff << PAGE_SHIFT;
685 if (offset >= __pa(high_memory) || (file->f_flags & O_SYNC))
686 vma->vm_flags |= VM_IO;
688 /* Don't try to swap out physical pages.. */
689 vma->vm_flags |= VM_RESERVED;
693 if (vma->vm_offset & ~PAGE_MASK)
696 offset = vma->vm_offset;
700 /* they are mapping the registers or the buffer */
701 if ((offset == dt3155_status[minor].reg_addr &&
702 vma->vm_end - vma->vm_start == PCI_PAGE_SIZE) ||
703 (offset == dt3155_status[minor].mem_addr &&
704 vma->vm_end - vma->vm_start == dt3155_status[minor].mem_size))
706 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
707 if (remap_pfn_range(vma,
709 offset >> PAGE_SHIFT,
710 vma->vm_end - vma->vm_start,
713 if (remap_page_range(vma->vm_start,
715 vma->vm_end - vma->vm_start,
719 printk("DT3155: remap_page_range() failed.\n");
725 printk("DT3155: dt3155_mmap() bad call.\n");
733 /*****************************************************
736 * Our special open code.
737 * MOD_INC_USE_COUNT make sure that the driver memory is not freed
738 * while the device is in use.
739 *****************************************************/
740 static int dt3155_open( struct inode* inode, struct file* filep)
742 int minor = MINOR(inode->i_rdev); /* what device are we opening? */
743 if (dt3155_dev_open[ minor ]) {
744 printk ("DT3155: Already opened by another process.\n");
748 if (dt3155_status[ minor ].device_installed==0)
750 printk("DT3155 Open Error: No such device dt3155 minor number %d\n",
755 if (dt3155_status[ minor ].state != DT3155_STATE_IDLE) {
756 printk ("DT3155: Not in idle state (state = %lx)\n",
757 dt3155_status[ minor ].state);
761 printk("DT3155: Device opened.\n");
763 dt3155_dev_open[ minor ] = 1 ;
764 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
768 dt3155_flush( minor );
770 /* Disable ALL interrupts */
772 WriteMReg( (dt3155_lbase[ minor ] + INT_CSR), int_csr_r.reg );
774 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,1)
775 init_waitqueue_head(&(dt3155_read_wait_queue[minor]));
777 dt3155_read_wait_queue[minor] = NULL;
784 /*****************************************************
787 * Now decrement the use count.
789 *****************************************************/
790 static int dt3155_close( struct inode *inode, struct file *filep)
794 minor = MINOR(inode->i_rdev); /* which device are we closing */
795 if (!dt3155_dev_open[ minor ])
797 printk("DT3155: attempt to CLOSE a not OPEN device\n");
801 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
804 dt3155_dev_open[ minor ] = 0;
806 if (dt3155_status[ minor ].state != DT3155_STATE_IDLE)
814 /*****************************************************
817 *****************************************************/
818 static int dt3155_read (
824 /* which device are we reading from? */
825 int minor = MINOR(filep->f_dentry->d_inode->i_rdev);
828 frame_info_t *frame_info_p;
830 /* TODO: this should check the error flag and */
831 /* return an error on hardware failures */
832 if (count != sizeof(dt3155_read_t))
834 printk("DT3155 ERROR (NJC): count is not right\n");
839 /* Hack here -- I'm going to allow reading even when idle.
840 * this is so that the frames can be read after STOP has
841 * been called. Leaving it here, commented out, as a reminder
842 * for a short while to make sure there are no problems.
843 * Note that if the driver is not opened in non_blocking mode,
844 * and the device is idle, then it could sit here forever! */
846 /* if (dt3155_status[minor].state == DT3155_STATE_IDLE)*/
849 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,1)
851 /* non-blocking reads should return if no data */
852 if (filep->f_flags & O_NDELAY)
854 if ((frame_index = dt3155_get_ready_buffer(minor)) < 0) {
855 /*printk( "dt3155: no buffers available (?)\n");*/
856 /* printques(minor); */
863 * sleep till data arrives , or we get interrupted.
864 * Note that wait_event_interruptible() does not actually
865 * sleep/wait if it's condition evaluates to true upon entry.
867 wait_event_interruptible(dt3155_read_wait_queue[minor],
868 (frame_index = dt3155_get_ready_buffer(minor))
873 printk ("DT3155: read: interrupted\n");
881 while ((frame_index = dt3155_get_ready_buffer(minor)) < 0 )
884 if (filep->f_flags & O_NDELAY)
887 /* sleep till data arrives , or we get interrupted */
888 interruptible_sleep_on(&dt3155_read_wait_queue[minor]);
889 for (index = 0; index < _NSIG_WORDS; index++)
892 * Changing the next line of code below to this:
893 * if (current->pending.signal.sig[index] &
894 * ~current->blocked.sig[index])
895 * would also work on a 2.4 kernel, however, the above
896 * method is preferred & more portable.
898 if (current->signal.sig[index] & ~current->blocked.sig[index])
900 printk ("DT3155: read: interrupted\n");
908 frame_info_p = &dt3155_status[minor].fbuffer.frame_info[frame_index];
910 /* make this an offset */
911 offset = frame_info_p->addr - dt3155_status[minor].mem_addr;
913 put_user(offset, (unsigned int *) buf);
914 buf += sizeof(u_long);
915 put_user( dt3155_status[minor].fbuffer.frame_count, (unsigned int *) buf);
916 buf += sizeof(u_long);
917 put_user(dt3155_status[minor].state, (unsigned int *) buf);
918 buf += sizeof(u_long);
919 if (copy_to_user(buf, frame_info_p, sizeof(frame_info_t)))
922 return sizeof(dt3155_read_t);
925 static unsigned int dt3155_poll (struct file * filp, poll_table *wait)
927 int minor = MINOR(filp->f_dentry->d_inode->i_rdev);
929 if (!is_ready_buf_empty(minor))
930 return POLLIN | POLLRDNORM;
932 poll_wait (filp, &dt3155_read_wait_queue[minor], wait);
938 /*****************************************************
939 * file operations supported by DT3155 driver
940 * needed by init_module
942 *****************************************************/
943 static struct file_operations dt3155_fops = {
949 release: dt3155_close
953 /*****************************************************
956 * PCI has been totally reworked in 2.1..
957 *****************************************************/
958 static int find_PCI (void)
960 struct pci_dev *pci_dev = NULL;
961 int error, pci_index = 0;
962 unsigned short rev_device;
966 while ((pci_dev = pci_find_device
967 (DT3155_VENDORID, DT3155_DEVICEID, pci_dev)) != NULL)
971 /* Is it really there? */
973 pci_read_config_word(pci_dev, PCI_CLASS_DEVICE, &rev_device)))
977 DT_3155_DEBUG_MSG("DT3155: Device number %d \n", pci_index);
979 /* Make sure the driver was compiled with enough buffers to handle
981 if (pci_index > MAXBOARDS) {
982 printk("DT3155: ERROR - found %d devices, but driver only configured "
984 "DT3155: Please change MAXBOARDS in dt3155.h\n",
985 pci_index, MAXBOARDS);
986 return DT_3155_FAILURE;
989 /* Now, just go out and make sure that this/these device(s) is/are
990 actually mapped into the kernel address space */
991 if ((error = pci_read_config_dword( pci_dev, PCI_BASE_ADDRESS_0,
994 printk("DT3155: Was not able to find device \n");
995 return DT_3155_FAILURE;
998 DT_3155_DEBUG_MSG("DT3155: Base address 0 for device is %lx \n", base);
999 dt3155_status[pci_index-1].reg_addr = base;
1001 /* Remap the base address to a logical address through which we
1003 dt3155_lbase[ pci_index - 1 ] = ioremap(base,PCI_PAGE_SIZE);
1004 dt3155_status[ pci_index - 1 ].reg_addr = base;
1005 DT_3155_DEBUG_MSG("DT3155: New logical address is x%x \n",
1006 (u_int)dt3155_lbase[pci_index-1]);
1007 if ( !dt3155_lbase[pci_index-1] )
1009 printk("DT3155: Unable to remap control registers\n");
1010 return DT_3155_FAILURE;
1013 if ( (error = pci_read_config_byte( pci_dev, PCI_INTERRUPT_LINE, &irq)) )
1015 printk("DT3155: Was not able to find device \n");
1016 return DT_3155_FAILURE;
1019 DT_3155_DEBUG_MSG("DT3155: IRQ is %d \n",irq);
1020 dt3155_status[ pci_index-1 ].irq = irq;
1021 /* Set flag: kth device found! */
1022 dt3155_status[ pci_index-1 ].device_installed = 1;
1023 printk("DT3155: Installing device %d w/irq %d and address 0x%x\n",
1025 (u_int)dt3155_status[pci_index-1].irq,
1026 (u_int)dt3155_lbase[pci_index-1]);
1029 ndevices = pci_index;
1031 return DT_3155_SUCCESS;
1034 u_long allocatorAddr = 0;
1036 /*****************************************************
1038 *****************************************************/
1039 int init_module(void)
1043 char *devname[ MAXBOARDS ];
1045 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,1)
1046 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
1047 SET_MODULE_OWNER(&dt3155_fops);
1051 devname[ 0 ] = "dt3155a";
1053 devname[ 1 ] = "dt3155b";
1056 printk("DT3155: Loading module...\n");
1058 /* Register the device driver */
1059 rcode = register_chrdev( dt3155_major, "dt3155", &dt3155_fops );
1062 printk( KERN_INFO "DT3155: register_chrdev failed \n");
1066 if( dt3155_major == 0 )
1067 dt3155_major = rcode; /* dynamic */
1070 /* init the status variables. */
1071 /* DMA memory is taken care of in setup_buffers() */
1072 for ( index = 0; index < MAXBOARDS; index++ )
1074 dt3155_status[ index ].config.acq_mode = DT3155_MODE_FRAME;
1075 dt3155_status[ index ].config.continuous = DT3155_ACQ;
1076 dt3155_status[ index ].config.cols = DT3155_MAX_COLS;
1077 dt3155_status[ index ].config.rows = DT3155_MAX_ROWS;
1078 dt3155_status[ index ].state = DT3155_STATE_IDLE;
1080 /* find_PCI() will check if devices are installed; */
1081 /* first assume they're not: */
1082 dt3155_status[ index ].mem_addr = 0;
1083 dt3155_status[ index ].mem_size = 0;
1084 dt3155_status[ index ].state = DT3155_STATE_IDLE;
1085 dt3155_status[ index ].device_installed = 0;
1088 /* Now let's find the hardware. find_PCI() will set ndevices to the
1089 * number of cards found in this machine. */
1090 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
1091 if ( !(pcibios_present()) )
1093 printk("DT3155: Error: No PCI bios on this machine \n");
1094 if( unregister_chrdev( dt3155_major, "dt3155" ) != 0 )
1095 printk("DT3155: cleanup_module failed\n");
1097 return DT_3155_FAILURE;
1102 if ( (rcode = find_PCI()) != DT_3155_SUCCESS )
1104 printk("DT3155 error: find_PCI() failed to find dt3155 board(s)\n");
1105 unregister_chrdev( dt3155_major, "dt3155" );
1110 /* Ok, time to setup the frame buffers */
1111 if( (rcode = dt3155_setup_buffers(&allocatorAddr)) < 0 )
1113 printk("DT3155: Error: setting up buffer not large enough.");
1114 unregister_chrdev( dt3155_major, "dt3155" );
1118 /* If we are this far, then there is enough RAM */
1119 /* for the buffers: Print the configuration. */
1120 for( index = 0; index < ndevices; index++ )
1122 printk("DT3155: Device = %d; acq_mode = %d; "
1123 "continuous = %d; cols = %d; rows = %d;\n",
1125 dt3155_status[ index ].config.acq_mode,
1126 dt3155_status[ index ].config.continuous,
1127 dt3155_status[ index ].config.cols,
1128 dt3155_status[ index ].config.rows);
1129 printk("DT3155: m_addr = 0x%x; m_size = %ld; "
1130 "state = %ld; device_installed = %d\n",
1131 (u_int)dt3155_status[ index ].mem_addr,
1132 dt3155_status[ index ].mem_size,
1133 dt3155_status[ index ].state,
1134 dt3155_status[ index ].device_installed);
1137 /* Disable ALL interrupts */
1139 for( index = 0; index < ndevices; index++ )
1141 WriteMReg( (dt3155_lbase[ index ] + INT_CSR), int_csr_r.reg );
1142 if( dt3155_status[ index ].device_installed )
1145 * This driver *looks* like it can handle sharing interrupts,
1146 * but I can't actually test myself. I've had reports that it
1147 * DOES work so I'll enable it for now. This comment will remain
1148 * as a reminder in case any problems arise. (SS)
1150 /* in older kernels flags are: SA_SHIRQ | SA_INTERRUPT */
1151 rcode = request_irq( dt3155_status[ index ].irq, (void *)dt3155_isr,
1152 IRQF_SHARED | IRQF_DISABLED, devname[ index ],
1153 (void*) &dt3155_status[index]);
1156 printk("DT3155: minor %d request_irq failed for IRQ %d\n",
1157 index, dt3155_status[index].irq);
1158 unregister_chrdev( dt3155_major, "dt3155" );
1164 printk("DT3155: finished loading\n");
1169 /*****************************************************
1170 * cleanup_module(void)
1172 *****************************************************/
1173 void cleanup_module(void)
1177 printk("DT3155: cleanup_module called\n");
1179 /* removed DMA allocated with the allocator */
1180 #ifdef STANDALONE_ALLOCATOR
1181 if (allocatorAddr != 0)
1182 allocator_free_dma(allocatorAddr);
1184 allocator_cleanup();
1187 unregister_chrdev( dt3155_major, "dt3155" );
1189 for( index = 0; index < ndevices; index++ )
1191 if( dt3155_status[ index ].device_installed == 1 )
1193 printk( "DT3155: Freeing irq %d for device %d\n",
1194 dt3155_status[ index ].irq, index );
1195 free_irq( dt3155_status[ index ].irq, (void*)&dt3155_status[index] );
1199 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
1201 printk("DT3155: device busy, remove delayed\n");