3efdeb9953ff6bb72b9fd414a276b7a57ebe7174
[safe/jmp/linux-2.6] / drivers / staging / dt3155 / dt3155_drv.c
1 /*
2
3 Copyright 1996,2002,2005 Gregory D. Hager, Alfred A. Rizzi, Noah J. Cowan,
4                          Jason Lapenta, Scott Smedley, Greg Sharp
5
6 This file is part of the DT3155 Device Driver.
7
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.
12
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.
17
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,
21 MA 02111-1307 USA
22
23 -- Changes --
24
25   Date     Programmer   Description of changes made
26   -------------------------------------------------------------------
27   03-Jul-2000 JML       n/a
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.
40
41 -- Notes --
42
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)
46
47  + might want to get rid of MAXboards for allocating initial buffer.
48     confusing and not necessary
49
50  + in cleanup_module the MOD_IN_USE looks like it is check after it should
51
52  * GFP_DMA should not be set with a PCI system (pg 291)
53
54  - NJC why are only two buffers allowed? (see isr, approx line 358)
55
56 */
57
58 extern void printques(int);
59
60 #ifdef MODULE
61 #include <linux/module.h>
62 #include <linux/version.h>
63 #include <linux/interrupt.h>
64
65
66 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,10)
67 MODULE_LICENSE("GPL");
68 #endif
69
70 #endif
71
72 #ifndef CONFIG_PCI
73 #error  "DT3155 :  Kernel PCI support not enabled (DT3155 drive requires PCI)"
74 #endif
75
76 #include <linux/pci.h>
77 #include <linux/types.h>
78 #include <linux/poll.h>
79 #include <linux/sched.h>
80
81 #include <asm/io.h>
82 #include <asm/uaccess.h>
83
84 #include "dt3155.h"
85 #include "dt3155_drv.h"
86 #include "dt3155_isr.h"
87 #include "dt3155_io.h"
88 #include "allocator.h"
89
90 /* Error variable.  Zero means no error. */
91 int dt3155_errno = 0;
92
93 #ifndef PCI_DEVICE_ID_INTEL_7116
94 #define PCI_DEVICE_ID_INTEL_7116 0x1223
95 #endif
96
97 #define DT3155_VENDORID    PCI_VENDOR_ID_INTEL
98 #define DT3155_DEVICEID    PCI_DEVICE_ID_INTEL_7116
99 #define MAXPCI    16
100
101 #ifdef DT_DEBUG
102 #define DT_3155_DEBUG_MSG(x,y) printk(x,y)
103 #else
104 #define DT_3155_DEBUG_MSG(x,y)
105 #endif
106
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 ];
110 #else
111 struct wait_queue *dt3155_read_wait_queue[ MAXBOARDS ];
112 #endif
113
114 #define DT_3155_SUCCESS 0
115 #define DT_3155_FAILURE -EIO
116
117 /* set to dynamicaly allocate, but it is tunable: */
118 /* insmod DT_3155 dt3155 dt3155_major=XX */
119 int dt3155_major = 0;
120
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
124  */
125
126 /* Global structures and variables */
127
128 /* Status of each device */
129 struct dt3155_status_s dt3155_status[ MAXBOARDS ];
130
131 /* kernel logical address of the board */
132 u_char *dt3155_lbase[ MAXBOARDS ] = { NULL
133 #if MAXBOARDS == 2
134                                       , NULL
135 #endif
136 };
137 /* DT3155 registers              */
138 u_char *dt3155_bbase = NULL;              /* kernel logical address of the *
139                                            * buffer region                 */
140 u_int  dt3155_dev_open[ MAXBOARDS ] = {0
141 #if MAXBOARDS == 2
142                                        , 0
143 #endif
144 };
145
146 u_int  ndevices = 0;
147 u_long unique_tag = 0;;
148
149
150 /*
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.
153  * (James Rose)
154  */
155 static void quick_stop (int minor)
156 {
157   // TODO: scott was here
158 #if 1
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 );
164
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;
170 #else
171   dt3155_status[minor].state |= DT3155_STATE_STOP;
172   dt3155_status[minor].fbuffer.stop_acquire = 1;
173 #endif
174
175 }
176
177
178 /*****************************************************
179  *  dt3155_isr() Interrupt service routien
180  *
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 )
186 {
187   int    minor = -1;
188   int    index;
189 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
190   unsigned long flags;
191 #else
192   int    flags;
193 #endif
194   u_long buffer_addr;
195
196   /* find out who issued the interrupt */
197   for ( index = 0; index < ndevices; index++ ) {
198     if( dev_id == (void*) &dt3155_status[ index ])
199       {
200         minor = index;
201         break;
202       }
203   }
204
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");
208     return;
209   }
210
211   /* Check for corruption and set a flag if so */
212   ReadMReg( (dt3155_lbase[ minor ] + CSR1), csr1_r.reg );
213
214   if ( (csr1_r.fld.FLD_CRPT_EVE) || (csr1_r.fld.FLD_CRPT_ODD) )
215     {
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");
221       return;
222     }
223
224   ReadMReg((dt3155_lbase[ minor ] + INT_CSR), int_csr_r.reg);
225
226   /* Handle the even field ... */
227   if (int_csr_r.fld.FLD_END_EVE)
228     {
229       if ( (dt3155_status[ minor ].state & DT3155_STATE_MODE) ==
230            DT3155_STATE_FLD )
231         {
232           dt3155_fbuffer[ minor ]->frame_count++;
233         }
234
235       ReadI2C(dt3155_lbase[ minor ], EVEN_CSR, &i2c_even_csr.reg);
236
237       /* Clear the interrupt? */
238       int_csr_r.fld.FLD_END_EVE = 1;
239
240       /* disable the interrupt if last field */
241       if (dt3155_fbuffer[ minor ]->stop_acquire)
242         {
243           printk("dt3155:  even stopped.\n");
244           dt3155_fbuffer[ minor ]->even_stopped = 1;
245           if (i2c_even_csr.fld.SNGL_EVE)
246             {
247               int_csr_r.fld.FLD_END_EVE_EN = 0;
248             }
249           else
250             {
251               i2c_even_csr.fld.SNGL_EVE  = 1;
252             }
253         }
254
255       WriteMReg( (dt3155_lbase[ minor ] + INT_CSR), int_csr_r.reg );
256
257       /* Set up next DMA if we are doing FIELDS */
258       if ( (dt3155_status[ minor ].state & DT3155_STATE_MODE ) ==
259            DT3155_STATE_FLD)
260         {
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);
269           local_irq_disable();
270 #else
271           save_flags( flags );
272           cli();
273 #endif
274           wake_up_interruptible( &dt3155_read_wait_queue[ minor ] );
275
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);
279 #else
280           restore_flags( flags );
281 #endif
282           WriteMReg((dt3155_lbase[ minor ] + ODD_DMA_START), buffer_addr);
283         }
284
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;
289
290       WriteI2C( dt3155_lbase[ minor ], EVEN_CSR, i2c_even_csr.reg );
291
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;
295
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) );
301       return;
302     }
303
304   /* ... now handle the odd field */
305   if ( int_csr_r.fld.FLD_END_ODD )
306     {
307       ReadI2C( dt3155_lbase[ minor ], ODD_CSR, &i2c_odd_csr.reg );
308
309       /* Clear the interrupt? */
310       int_csr_r.fld.FLD_END_ODD = 1;
311
312       if (dt3155_fbuffer[ minor ]->even_happened ||
313           (dt3155_status[ minor ].state & DT3155_STATE_MODE) ==
314           DT3155_STATE_FLD)
315         {
316           dt3155_fbuffer[ minor ]->frame_count++;
317         }
318
319       if ( dt3155_fbuffer[ minor ]->stop_acquire &&
320            dt3155_fbuffer[ minor ]->even_stopped )
321         {
322           printk(KERN_DEBUG "dt3155:  stopping odd..\n");
323           if ( i2c_odd_csr.fld.SNGL_ODD )
324             {
325               /* disable interrupts */
326               int_csr_r.fld.FLD_END_ODD_EN = 0;
327               dt3155_status[ minor ].state &= ~(DT3155_STATE_STOP|0xff);
328
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;
333
334               printk(KERN_DEBUG "dt3155:  state is now %lx\n",
335                      dt3155_status[minor].state);
336             }
337           else
338             {
339               i2c_odd_csr.fld.SNGL_ODD  = 1;
340             }
341         }
342
343       WriteMReg( (dt3155_lbase[ minor ] + INT_CSR), int_csr_r.reg );
344
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) ==
350            DT3155_STATE_FLD )
351         {
352
353 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
354           local_save_flags(flags);
355           local_irq_disable();
356 #else
357           save_flags( flags );
358           cli();
359 #endif
360
361 #ifdef DEBUG_QUES_B
362           printques( minor );
363 #endif
364           if ( dt3155_fbuffer[ minor ]->nbuffers > 2 )
365             {
366               if ( !are_empty_buffers( minor ) )
367                 {
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 );
373                 }
374
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;
384             }
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.
389                */
390               if ( dt3155_fbuffer[ minor ]->locked_buf < 0 )
391                 {
392                   push_ready( minor,
393                               dt3155_fbuffer[ minor ]->active_buf );
394                   if (are_empty_buffers( minor ) )
395                     {
396                       dt3155_fbuffer[ minor ]->active_buf =
397                         pop_empty( minor );
398                     }
399                   else
400                     { /* no empty or locked buffers, so use a readybuf */
401                       dt3155_fbuffer[ minor ]->active_buf =
402                         pop_ready( minor );
403                     }
404                 }
405             }
406
407 #ifdef DEBUG_QUES_B
408           printques( minor );
409 #endif
410
411           dt3155_fbuffer[ minor ]->even_happened = 0;
412
413           wake_up_interruptible( &dt3155_read_wait_queue[ minor ] );
414
415 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
416           local_irq_restore(flags);
417 #else
418           restore_flags( flags );
419 #endif
420         }
421
422
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) ==
427            DT3155_STATE_FLD )
428         {
429           WriteMReg((dt3155_lbase[ minor ] + EVEN_DMA_START), buffer_addr);
430         }
431       else
432         {
433           WriteMReg((dt3155_lbase[ minor ] + EVEN_DMA_START), buffer_addr);
434
435           WriteMReg((dt3155_lbase[ minor ] + ODD_DMA_START), buffer_addr
436                     + dt3155_status[ minor ].config.cols);
437         }
438
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;
443
444       WriteI2C(dt3155_lbase[ minor ], ODD_CSR, i2c_odd_csr.reg );
445
446       return;
447     }
448   /* If we get here, the Odd Field wasn't it either... */
449   printk( "neither even nor odd.  shared perhaps?\n");
450 }
451
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)
459 {
460   const u_long stride =  dt3155_status[ minor ].config.cols;
461
462   switch (dt3155_status[ minor ].state & DT3155_STATE_MODE)
463     {
464     case DT3155_STATE_FLD:
465       {
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;
470
471         WriteMReg((dt3155_lbase[ minor ] + EVEN_DMA_START),
472                   even_dma_start_r);
473         WriteMReg((dt3155_lbase[ minor ] + EVEN_DMA_STRIDE),
474                   even_dma_stride_r);
475         WriteMReg((dt3155_lbase[ minor ] + ODD_DMA_STRIDE),
476                   odd_dma_stride_r);
477         break;
478       }
479
480     case DT3155_STATE_FRAME:
481     default:
482       {
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;
488
489         WriteMReg((dt3155_lbase[ minor ] + EVEN_DMA_START),
490                   even_dma_start_r);
491         WriteMReg((dt3155_lbase[ minor ] + ODD_DMA_START),
492                   odd_dma_start_r);
493         WriteMReg((dt3155_lbase[ minor ] + EVEN_DMA_STRIDE),
494                   even_dma_stride_r);
495         WriteMReg((dt3155_lbase[ minor ] + ODD_DMA_STRIDE),
496                   odd_dma_stride_r);
497         break;
498       }
499     }
500
501   /* 50/60 Hz should be set before this point but let's make sure it is */
502   /* right anyway */
503
504   ReadI2C(dt3155_lbase[ minor ], CONFIG, &i2c_csr2.reg);
505   i2c_csr2.fld.HZ50 = FORMAT50HZ;
506   WriteI2C(dt3155_lbase[ minor ], CONFIG, i2c_config.reg);
507
508   /* enable busmaster chip, clear flags */
509
510   /*
511    * TODO:
512    * shouldn't we be concered with continuous values of
513    * DT3155_SNAP & DT3155_ACQ here? (SS)
514    */
515
516   csr1_r.reg                = 0;
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;
525
526   WriteMReg((dt3155_lbase[ minor ] + CSR1),csr1_r.reg);
527
528   /* Enable interrupts at the end of each field */
529
530   int_csr_r.reg = 0;
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;
534
535   WriteMReg((dt3155_lbase[ minor ] + INT_CSR), int_csr_r.reg);
536
537   /* start internal BUSY bits */
538
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);
543
544   /* Now its up to the interrupt routine!! */
545
546   return;
547 }
548
549
550 /*****************************************************
551  * ioctl()
552  *
553  *****************************************************/
554 static int dt3155_ioctl (
555                          struct inode   *inode,
556                          struct file            *file,
557                          u_int                  cmd,
558                          u_long                 arg)
559 {
560   int minor = MINOR(inode->i_rdev); /* What device are we ioctl()'ing? */
561
562   if ( minor >= MAXBOARDS || minor < 0 )
563     return -ENODEV;
564
565   /* make sure it is valid command */
566   if (_IOC_NR(cmd) > DT3155_IOC_MAXNR)
567     {
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);
572       return -EINVAL;
573     }
574
575   switch (cmd)
576     {
577     case DT3155_SET_CONFIG:
578       {
579         if (dt3155_status[minor].state != DT3155_STATE_IDLE)
580           return -EBUSY;
581
582         {
583           struct dt3155_config_s tmp;
584           if (copy_from_user((void *)&tmp, (void *) arg, sizeof(tmp)))
585               return -EFAULT;
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))
593             {
594               return -EINVAL;
595             }
596           dt3155_status[minor].config = tmp;
597         }
598         return 0;
599       }
600     case DT3155_GET_CONFIG:
601       {
602         if (copy_to_user((void *) arg, (void *) &dt3155_status[minor],
603                      sizeof(dt3155_status_t) ))
604             return -EFAULT;
605         return 0;
606       }
607     case DT3155_FLUSH: /* Flushes the buffers -- ensures fresh data */
608       {
609         if (dt3155_status[minor].state != DT3155_STATE_IDLE)
610           return -EBUSY;
611         return dt3155_flush(minor);
612       }
613     case DT3155_STOP:
614       {
615         if (dt3155_status[minor].state & DT3155_STATE_STOP ||
616             dt3155_status[minor].fbuffer.stop_acquire)
617           return -EBUSY;
618
619         if (dt3155_status[minor].state == DT3155_STATE_IDLE)
620           return 0;
621
622         quick_stop(minor);
623         if (copy_to_user((void *) arg, (void *) &dt3155_status[minor],
624                      sizeof(dt3155_status_t)))
625             return -EFAULT;
626         return 0;
627       }
628     case DT3155_START:
629       {
630         if (dt3155_status[minor].state != DT3155_STATE_IDLE)
631           return -EBUSY;
632
633         dt3155_status[minor].fbuffer.stop_acquire = 0;
634         dt3155_status[minor].fbuffer.frame_count = 0;
635
636         /* Set the MODE in the status -- we default to FRAME */
637         if (dt3155_status[minor].config.acq_mode == DT3155_MODE_FIELD)
638           {
639             dt3155_status[minor].state = DT3155_STATE_FLD;
640           }
641         else
642           {
643             dt3155_status[minor].state = DT3155_STATE_FRAME;
644           }
645
646         dt3155_init_isr(minor);
647         if (copy_to_user( (void *) arg, (void *) &dt3155_status[minor],
648                       sizeof(dt3155_status_t)))
649             return -EFAULT;
650         return 0;
651       }
652     default:
653       {
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);
658         return -ENOSYS;
659       }
660     }
661   return -ENOSYS;
662 }
663
664 /*****************************************************
665  * mmap()
666  *
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)
674 {
675   /* which device are we mmapping? */
676   int                           minor = MINOR(file->f_dentry->d_inode->i_rdev);
677   unsigned long offset;
678
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)
682
683   offset = vma->vm_pgoff << PAGE_SHIFT;
684
685   if (offset >= __pa(high_memory) || (file->f_flags & O_SYNC))
686     vma->vm_flags |= VM_IO;
687
688   /* Don't try to swap out physical pages.. */
689   vma->vm_flags |= VM_RESERVED;
690
691 #else
692
693   if (vma->vm_offset & ~PAGE_MASK)
694     return -ENXIO;
695
696   offset = vma->vm_offset;
697
698 #endif
699
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))
705     {
706 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
707       if (remap_pfn_range(vma,
708                         vma->vm_start,
709                         offset >> PAGE_SHIFT,
710                         vma->vm_end - vma->vm_start,
711                         vma->vm_page_prot))
712 #else
713       if (remap_page_range(vma->vm_start,
714                            offset,
715                            vma->vm_end - vma->vm_start,
716                            vma->vm_page_prot))
717 #endif
718         {
719           printk("DT3155: remap_page_range() failed.\n");
720           return -EAGAIN;
721         }
722     }
723   else
724     {
725       printk("DT3155: dt3155_mmap() bad call.\n");
726       return -ENXIO;
727     }
728
729   return 0;
730 }
731
732
733 /*****************************************************
734  * open()
735  *
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)
741 {
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");
745     return -EBUSY;
746   }
747
748   if (dt3155_status[ minor ].device_installed==0)
749     {
750       printk("DT3155 Open Error: No such device dt3155 minor number %d\n",
751              minor);
752       return -EIO;
753     }
754
755   if (dt3155_status[ minor ].state != DT3155_STATE_IDLE) {
756     printk ("DT3155:  Not in idle state (state = %lx)\n",
757             dt3155_status[ minor ].state);
758     return -EBUSY;
759   }
760
761   printk("DT3155: Device opened.\n");
762
763   dt3155_dev_open[ minor ] = 1 ;
764 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
765   MOD_INC_USE_COUNT;
766 #endif
767
768   dt3155_flush( minor );
769
770   /* Disable ALL interrupts */
771   int_csr_r.reg = 0;
772   WriteMReg( (dt3155_lbase[ minor ] + INT_CSR), int_csr_r.reg );
773
774 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,1)
775   init_waitqueue_head(&(dt3155_read_wait_queue[minor]));
776 #else
777   dt3155_read_wait_queue[minor] = NULL;
778 #endif
779
780   return 0;
781 }
782
783
784 /*****************************************************
785  * close()
786  *
787  * Now decrement the use count.
788  *
789  *****************************************************/
790 static int dt3155_close( struct inode *inode, struct file *filep)
791 {
792   int minor;
793
794   minor = MINOR(inode->i_rdev); /* which device are we closing */
795   if (!dt3155_dev_open[ minor ])
796     {
797       printk("DT3155: attempt to CLOSE a not OPEN device\n");
798     }
799   else
800     {
801 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
802       MOD_DEC_USE_COUNT;
803 #endif
804       dt3155_dev_open[ minor ] = 0;
805
806       if (dt3155_status[ minor ].state != DT3155_STATE_IDLE)
807         {
808           quick_stop(minor);
809         }
810     }
811   return 0;
812 }
813
814 /*****************************************************
815  * read()
816  *
817  *****************************************************/
818 static int dt3155_read (
819                         struct file     *filep,
820                         char            *buf,
821                         size_t          count,
822                         loff_t          *ppos)
823 {
824   /* which device are we reading from? */
825   int           minor = MINOR(filep->f_dentry->d_inode->i_rdev);
826   u_long                offset;
827   int           frame_index;
828   frame_info_t  *frame_info_p;
829
830   /* TODO: this should check the error flag and */
831   /*   return an error on hardware failures */
832   if (count != sizeof(dt3155_read_t))
833     {
834       printk("DT3155 ERROR (NJC): count is not right\n");
835       return -EINVAL;
836     }
837
838
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! */
845
846   /*  if (dt3155_status[minor].state == DT3155_STATE_IDLE)*/
847   /*    return -EBUSY;*/
848
849 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,1)
850
851   /* non-blocking reads should return if no data */
852   if (filep->f_flags & O_NDELAY)
853     {
854       if ((frame_index = dt3155_get_ready_buffer(minor)) < 0) {
855         /*printk( "dt3155:  no buffers available (?)\n");*/
856         /*              printques(minor); */
857         return -EAGAIN;
858       }
859     }
860   else
861     {
862       /*
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.
866        */
867       wait_event_interruptible(dt3155_read_wait_queue[minor],
868                                (frame_index = dt3155_get_ready_buffer(minor))
869                                >= 0);
870
871       if (frame_index < 0)
872         {
873           printk ("DT3155: read: interrupted\n");
874           quick_stop (minor);
875           printques(minor);
876           return -EINTR;
877         }
878     }
879
880 #else
881   while ((frame_index = dt3155_get_ready_buffer(minor)) < 0 )
882     {
883       int index;
884       if (filep->f_flags & O_NDELAY)
885         return 0;
886
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++)
890         {
891           /*
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.
897            */
898           if (current->signal.sig[index] & ~current->blocked.sig[index])
899             {
900               printk ("DT3155: read: interrupted\n");
901               return -EINTR;
902             }
903         }
904     }
905
906 #endif
907
908   frame_info_p = &dt3155_status[minor].fbuffer.frame_info[frame_index];
909
910   /* make this an offset */
911   offset = frame_info_p->addr - dt3155_status[minor].mem_addr;
912
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)))
920       return -EFAULT;
921
922   return sizeof(dt3155_read_t);
923 }
924
925 static unsigned int dt3155_poll (struct file * filp, poll_table *wait)
926 {
927   int minor = MINOR(filp->f_dentry->d_inode->i_rdev);
928
929   if (!is_ready_buf_empty(minor))
930     return POLLIN | POLLRDNORM;
931
932   poll_wait (filp, &dt3155_read_wait_queue[minor], wait);
933
934   return 0;
935 }
936
937
938 /*****************************************************
939  * file operations supported by DT3155 driver
940  *  needed by init_module
941  *  register_chrdev
942  *****************************************************/
943 static struct file_operations dt3155_fops = {
944   read:         dt3155_read,
945   ioctl:                dt3155_ioctl,
946   mmap:         dt3155_mmap,
947   poll:           dt3155_poll,
948   open:         dt3155_open,
949   release:      dt3155_close
950 };
951
952
953 /*****************************************************
954  * find_PCI();
955  *
956  * PCI has been totally reworked in 2.1..
957  *****************************************************/
958 static int find_PCI (void)
959 {
960   struct pci_dev *pci_dev = NULL;
961   int error, pci_index = 0;
962   unsigned short rev_device;
963   unsigned long base;
964   unsigned char irq;
965
966   while ((pci_dev = pci_find_device
967           (DT3155_VENDORID, DT3155_DEVICEID, pci_dev)) != NULL)
968     {
969       pci_index ++;
970
971       /* Is it really there? */
972       if ((error =
973            pci_read_config_word(pci_dev, PCI_CLASS_DEVICE, &rev_device)))
974         continue;
975
976       /* Found a board */
977       DT_3155_DEBUG_MSG("DT3155: Device number %d \n", pci_index);
978
979       /* Make sure the driver was compiled with enough buffers to handle
980          this many boards */
981       if (pci_index > MAXBOARDS) {
982         printk("DT3155: ERROR - found %d devices, but driver only configured "
983                "for %d devices\n"
984                "DT3155: Please change MAXBOARDS in dt3155.h\n",
985                pci_index, MAXBOARDS);
986         return DT_3155_FAILURE;
987       }
988
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,
992                                           (u_int *) &base)))
993         {
994           printk("DT3155: Was not able to find device \n");
995           return DT_3155_FAILURE;
996         }
997
998       DT_3155_DEBUG_MSG("DT3155: Base address 0 for device is %lx \n", base);
999       dt3155_status[pci_index-1].reg_addr = base;
1000
1001       /* Remap the base address to a logical address through which we
1002        * can access it. */
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] )
1008         {
1009           printk("DT3155: Unable to remap control registers\n");
1010           return DT_3155_FAILURE;
1011         }
1012
1013       if ( (error = pci_read_config_byte( pci_dev, PCI_INTERRUPT_LINE, &irq)) )
1014         {
1015           printk("DT3155: Was not able to find device \n");
1016           return DT_3155_FAILURE;
1017         }
1018
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",
1024              pci_index,
1025              (u_int)dt3155_status[pci_index-1].irq,
1026              (u_int)dt3155_lbase[pci_index-1]);
1027
1028     }
1029   ndevices = pci_index;
1030
1031   return DT_3155_SUCCESS;
1032 }
1033
1034 u_long allocatorAddr = 0;
1035
1036 /*****************************************************
1037  * init_module()
1038  *****************************************************/
1039 int init_module(void)
1040 {
1041   int index;
1042   int rcode = 0;
1043   char *devname[ MAXBOARDS ];
1044
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);
1048 #endif
1049 #endif
1050
1051   devname[ 0 ] = "dt3155a";
1052 #if MAXBOARDS == 2
1053   devname[ 1 ] = "dt3155b";
1054 #endif
1055
1056   printk("DT3155: Loading module...\n");
1057
1058   /* Register the device driver */
1059   rcode = register_chrdev( dt3155_major, "dt3155", &dt3155_fops );
1060   if( rcode < 0 )
1061     {
1062       printk( KERN_INFO "DT3155: register_chrdev failed \n");
1063       return rcode;
1064     }
1065
1066   if( dt3155_major == 0 )
1067     dt3155_major = rcode; /* dynamic */
1068
1069
1070   /* init the status variables.                     */
1071   /* DMA memory is taken care of in setup_buffers() */
1072   for ( index = 0; index < MAXBOARDS; index++ )
1073     {
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;
1079
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;
1086     }
1087
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()) )
1092     {
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");
1096
1097       return DT_3155_FAILURE;
1098     }
1099   else
1100 #endif
1101     {
1102       if ( (rcode = find_PCI()) !=  DT_3155_SUCCESS )
1103         {
1104           printk("DT3155 error: find_PCI() failed to find dt3155 board(s)\n");
1105           unregister_chrdev( dt3155_major, "dt3155" );
1106           return rcode;
1107         }
1108     }
1109
1110   /* Ok, time to setup the frame buffers */
1111   if( (rcode = dt3155_setup_buffers(&allocatorAddr)) < 0 )
1112     {
1113       printk("DT3155: Error: setting up buffer not large enough.");
1114       unregister_chrdev( dt3155_major, "dt3155" );
1115       return rcode;
1116     }
1117
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++ )
1121     {
1122       printk("DT3155: Device = %d; acq_mode = %d; "
1123              "continuous = %d; cols = %d; rows = %d;\n",
1124              index ,
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);
1135     }
1136
1137   /* Disable ALL interrupts */
1138   int_csr_r.reg = 0;
1139   for(  index = 0;  index < ndevices;  index++ )
1140     {
1141       WriteMReg( (dt3155_lbase[ index ] + INT_CSR), int_csr_r.reg );
1142       if( dt3155_status[ index ].device_installed )
1143         {
1144           /*
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)
1149            */
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]);
1154           if( rcode < 0 )
1155             {
1156               printk("DT3155: minor %d request_irq failed for IRQ %d\n",
1157                      index, dt3155_status[index].irq);
1158               unregister_chrdev( dt3155_major, "dt3155" );
1159               return rcode;
1160             }
1161         }
1162     }
1163
1164   printk("DT3155: finished loading\n");
1165
1166   return 0;
1167 }
1168
1169 /*****************************************************
1170  * cleanup_module(void)
1171  *
1172  *****************************************************/
1173 void cleanup_module(void)
1174 {
1175   int index;
1176
1177   printk("DT3155:  cleanup_module called\n");
1178
1179   /* removed DMA allocated with the allocator */
1180 #ifdef STANDALONE_ALLOCATOR
1181   if (allocatorAddr != 0)
1182     allocator_free_dma(allocatorAddr);
1183 #else
1184   allocator_cleanup();
1185 #endif
1186
1187   unregister_chrdev( dt3155_major, "dt3155" );
1188
1189   for( index = 0; index < ndevices; index++ )
1190     {
1191       if( dt3155_status[ index ].device_installed == 1 )
1192         {
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] );
1196         }
1197     }
1198
1199 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
1200   if (MOD_IN_USE)
1201     printk("DT3155: device busy, remove delayed\n");
1202 #endif
1203 }
1204