]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/staging/dt3155/dt3155_drv.c
Staging: dt3155: replace u_char usage
[karo-tx-linux.git] / 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/interrupt.h>
63
64
65 MODULE_LICENSE("GPL");
66
67 #endif
68
69 #ifndef CONFIG_PCI
70 #error  "DT3155 :  Kernel PCI support not enabled (DT3155 drive requires PCI)"
71 #endif
72
73 #include <linux/pci.h>
74 #include <linux/types.h>
75 #include <linux/poll.h>
76 #include <linux/sched.h>
77
78 #include <asm/io.h>
79 #include <asm/uaccess.h>
80
81 #include "dt3155.h"
82 #include "dt3155_drv.h"
83 #include "dt3155_isr.h"
84 #include "dt3155_io.h"
85 #include "allocator.h"
86
87 /* Error variable.  Zero means no error. */
88 int dt3155_errno = 0;
89
90 #ifndef PCI_DEVICE_ID_INTEL_7116
91 #define PCI_DEVICE_ID_INTEL_7116 0x1223
92 #endif
93
94 #define DT3155_VENDORID    PCI_VENDOR_ID_INTEL
95 #define DT3155_DEVICEID    PCI_DEVICE_ID_INTEL_7116
96 #define MAXPCI    16
97
98 #ifdef DT_DEBUG
99 #define DT_3155_DEBUG_MSG(x,y) printk(x,y)
100 #else
101 #define DT_3155_DEBUG_MSG(x,y)
102 #endif
103
104 /* wait queue for interrupts */
105 wait_queue_head_t dt3155_read_wait_queue[ MAXBOARDS ];
106
107 #define DT_3155_SUCCESS 0
108 #define DT_3155_FAILURE -EIO
109
110 /* set to dynamicaly allocate, but it is tunable: */
111 /* insmod DT_3155 dt3155 dt3155_major=XX */
112 int dt3155_major = 0;
113
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
117  */
118
119 /* Global structures and variables */
120
121 /* Status of each device */
122 struct dt3155_status_s dt3155_status[ MAXBOARDS ];
123
124 /* kernel logical address of the board */
125 u8 *dt3155_lbase[ MAXBOARDS ] = { NULL
126 #if MAXBOARDS == 2
127                                       , NULL
128 #endif
129 };
130 /* DT3155 registers              */
131 u8 *dt3155_bbase = NULL;                  /* kernel logical address of the *
132                                            * buffer region                 */
133 u_int  dt3155_dev_open[ MAXBOARDS ] = {0
134 #if MAXBOARDS == 2
135                                        , 0
136 #endif
137 };
138
139 u_int  ndevices = 0;
140 u_long unique_tag = 0;;
141
142
143 /*
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.
146  * (James Rose)
147  */
148 static void quick_stop (int minor)
149 {
150   // TODO: scott was here
151 #if 1
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 );
157
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;
163 #else
164   dt3155_status[minor].state |= DT3155_STATE_STOP;
165   dt3155_status[minor].fbuffer.stop_acquire = 1;
166 #endif
167
168 }
169
170
171 /*****************************************************
172  *  dt3155_isr() Interrupt service routien
173  *
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 )
179 {
180   int    minor = -1;
181   int    index;
182   unsigned long flags;
183   u_long buffer_addr;
184
185   /* find out who issued the interrupt */
186   for ( index = 0; index < ndevices; index++ ) {
187     if( dev_id == (void*) &dt3155_status[ index ])
188       {
189         minor = index;
190         break;
191       }
192   }
193
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");
197     return;
198   }
199
200   /* Check for corruption and set a flag if so */
201   ReadMReg( (dt3155_lbase[ minor ] + CSR1), csr1_r.reg );
202
203   if ( (csr1_r.fld.FLD_CRPT_EVE) || (csr1_r.fld.FLD_CRPT_ODD) )
204     {
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");
210       return;
211     }
212
213   ReadMReg((dt3155_lbase[ minor ] + INT_CSR), int_csr_r.reg);
214
215   /* Handle the even field ... */
216   if (int_csr_r.fld.FLD_END_EVE)
217     {
218       if ( (dt3155_status[ minor ].state & DT3155_STATE_MODE) ==
219            DT3155_STATE_FLD )
220         {
221           dt3155_fbuffer[ minor ]->frame_count++;
222         }
223
224       ReadI2C(dt3155_lbase[ minor ], EVEN_CSR, &i2c_even_csr.reg);
225
226       /* Clear the interrupt? */
227       int_csr_r.fld.FLD_END_EVE = 1;
228
229       /* disable the interrupt if last field */
230       if (dt3155_fbuffer[ minor ]->stop_acquire)
231         {
232           printk("dt3155:  even stopped.\n");
233           dt3155_fbuffer[ minor ]->even_stopped = 1;
234           if (i2c_even_csr.fld.SNGL_EVE)
235             {
236               int_csr_r.fld.FLD_END_EVE_EN = 0;
237             }
238           else
239             {
240               i2c_even_csr.fld.SNGL_EVE  = 1;
241             }
242         }
243
244       WriteMReg( (dt3155_lbase[ minor ] + INT_CSR), int_csr_r.reg );
245
246       /* Set up next DMA if we are doing FIELDS */
247       if ( (dt3155_status[ minor ].state & DT3155_STATE_MODE ) ==
248            DT3155_STATE_FLD)
249         {
250           /* GCS (Aug 2, 2002) -- In field mode, dma the odd field
251              into the lower half of the buffer */
252           const u_long 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);
257           local_irq_disable();
258           wake_up_interruptible( &dt3155_read_wait_queue[ minor ] );
259
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);
263         }
264
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;
269
270       WriteI2C( dt3155_lbase[ minor ], EVEN_CSR, i2c_even_csr.reg );
271
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;
275
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) );
281       return;
282     }
283
284   /* ... now handle the odd field */
285   if ( int_csr_r.fld.FLD_END_ODD )
286     {
287       ReadI2C( dt3155_lbase[ minor ], ODD_CSR, &i2c_odd_csr.reg );
288
289       /* Clear the interrupt? */
290       int_csr_r.fld.FLD_END_ODD = 1;
291
292       if (dt3155_fbuffer[ minor ]->even_happened ||
293           (dt3155_status[ minor ].state & DT3155_STATE_MODE) ==
294           DT3155_STATE_FLD)
295         {
296           dt3155_fbuffer[ minor ]->frame_count++;
297         }
298
299       if ( dt3155_fbuffer[ minor ]->stop_acquire &&
300            dt3155_fbuffer[ minor ]->even_stopped )
301         {
302           printk(KERN_DEBUG "dt3155:  stopping odd..\n");
303           if ( i2c_odd_csr.fld.SNGL_ODD )
304             {
305               /* disable interrupts */
306               int_csr_r.fld.FLD_END_ODD_EN = 0;
307               dt3155_status[ minor ].state &= ~(DT3155_STATE_STOP|0xff);
308
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;
313
314               printk(KERN_DEBUG "dt3155:  state is now %lx\n",
315                      dt3155_status[minor].state);
316             }
317           else
318             {
319               i2c_odd_csr.fld.SNGL_ODD  = 1;
320             }
321         }
322
323       WriteMReg( (dt3155_lbase[ minor ] + INT_CSR), int_csr_r.reg );
324
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) ==
330            DT3155_STATE_FLD )
331         {
332
333           local_save_flags(flags);
334           local_irq_disable();
335
336 #ifdef DEBUG_QUES_B
337           printques( minor );
338 #endif
339           if ( dt3155_fbuffer[ minor ]->nbuffers > 2 )
340             {
341               if ( !are_empty_buffers( minor ) )
342                 {
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 );
348                 }
349
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;
359             }
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.
364                */
365               if ( dt3155_fbuffer[ minor ]->locked_buf < 0 )
366                 {
367                   push_ready( minor,
368                               dt3155_fbuffer[ minor ]->active_buf );
369                   if (are_empty_buffers( minor ) )
370                     {
371                       dt3155_fbuffer[ minor ]->active_buf =
372                         pop_empty( minor );
373                     }
374                   else
375                     { /* no empty or locked buffers, so use a readybuf */
376                       dt3155_fbuffer[ minor ]->active_buf =
377                         pop_ready( minor );
378                     }
379                 }
380             }
381
382 #ifdef DEBUG_QUES_B
383           printques( minor );
384 #endif
385
386           dt3155_fbuffer[ minor ]->even_happened = 0;
387
388           wake_up_interruptible( &dt3155_read_wait_queue[ minor ] );
389
390           local_irq_restore(flags);
391         }
392
393
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) ==
398            DT3155_STATE_FLD )
399         {
400           WriteMReg((dt3155_lbase[ minor ] + EVEN_DMA_START), buffer_addr);
401         }
402       else
403         {
404           WriteMReg((dt3155_lbase[ minor ] + EVEN_DMA_START), buffer_addr);
405
406           WriteMReg((dt3155_lbase[ minor ] + ODD_DMA_START), buffer_addr
407                     + dt3155_status[ minor ].config.cols);
408         }
409
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;
414
415       WriteI2C(dt3155_lbase[ minor ], ODD_CSR, i2c_odd_csr.reg );
416
417       return;
418     }
419   /* If we get here, the Odd Field wasn't it either... */
420   printk( "neither even nor odd.  shared perhaps?\n");
421 }
422
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)
430 {
431   const u_long stride =  dt3155_status[ minor ].config.cols;
432
433   switch (dt3155_status[ minor ].state & DT3155_STATE_MODE)
434     {
435     case DT3155_STATE_FLD:
436       {
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;
441
442         WriteMReg((dt3155_lbase[ minor ] + EVEN_DMA_START),
443                   even_dma_start_r);
444         WriteMReg((dt3155_lbase[ minor ] + EVEN_DMA_STRIDE),
445                   even_dma_stride_r);
446         WriteMReg((dt3155_lbase[ minor ] + ODD_DMA_STRIDE),
447                   odd_dma_stride_r);
448         break;
449       }
450
451     case DT3155_STATE_FRAME:
452     default:
453       {
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;
459
460         WriteMReg((dt3155_lbase[ minor ] + EVEN_DMA_START),
461                   even_dma_start_r);
462         WriteMReg((dt3155_lbase[ minor ] + ODD_DMA_START),
463                   odd_dma_start_r);
464         WriteMReg((dt3155_lbase[ minor ] + EVEN_DMA_STRIDE),
465                   even_dma_stride_r);
466         WriteMReg((dt3155_lbase[ minor ] + ODD_DMA_STRIDE),
467                   odd_dma_stride_r);
468         break;
469       }
470     }
471
472   /* 50/60 Hz should be set before this point but let's make sure it is */
473   /* right anyway */
474
475   ReadI2C(dt3155_lbase[ minor ], CONFIG, &i2c_csr2.reg);
476   i2c_csr2.fld.HZ50 = FORMAT50HZ;
477   WriteI2C(dt3155_lbase[ minor ], CONFIG, i2c_config.reg);
478
479   /* enable busmaster chip, clear flags */
480
481   /*
482    * TODO:
483    * shouldn't we be concered with continuous values of
484    * DT3155_SNAP & DT3155_ACQ here? (SS)
485    */
486
487   csr1_r.reg                = 0;
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;
496
497   WriteMReg((dt3155_lbase[ minor ] + CSR1),csr1_r.reg);
498
499   /* Enable interrupts at the end of each field */
500
501   int_csr_r.reg = 0;
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;
505
506   WriteMReg((dt3155_lbase[ minor ] + INT_CSR), int_csr_r.reg);
507
508   /* start internal BUSY bits */
509
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);
514
515   /* Now its up to the interrupt routine!! */
516
517   return;
518 }
519
520
521 /*****************************************************
522  * ioctl()
523  *
524  *****************************************************/
525 static int dt3155_ioctl (
526                          struct inode   *inode,
527                          struct file            *file,
528                          u_int                  cmd,
529                          u_long                 arg)
530 {
531   int minor = MINOR(inode->i_rdev); /* What device are we ioctl()'ing? */
532
533   if ( minor >= MAXBOARDS || minor < 0 )
534     return -ENODEV;
535
536   /* make sure it is valid command */
537   if (_IOC_NR(cmd) > DT3155_IOC_MAXNR)
538     {
539       printk("DT3155: invalid IOCTL(0x%x)\n",cmd);
540       printk("DT3155: Valid commands (0x%x), (0x%x), (0x%x), (0x%x), (0x%x)\n",
541              (unsigned int)DT3155_GET_CONFIG,
542              (unsigned int)DT3155_SET_CONFIG,
543              (unsigned int)DT3155_START,
544              (unsigned int)DT3155_STOP,
545              (unsigned int)DT3155_FLUSH);
546       return -EINVAL;
547     }
548
549   switch (cmd)
550     {
551     case DT3155_SET_CONFIG:
552       {
553         if (dt3155_status[minor].state != DT3155_STATE_IDLE)
554           return -EBUSY;
555
556         {
557           struct dt3155_config_s tmp;
558           if (copy_from_user((void *)&tmp, (void *) arg, sizeof(tmp)))
559               return -EFAULT;
560           /* check for valid settings */
561           if (tmp.rows > DT3155_MAX_ROWS ||
562               tmp.cols > DT3155_MAX_COLS ||
563               (tmp.acq_mode != DT3155_MODE_FRAME &&
564                tmp.acq_mode != DT3155_MODE_FIELD) ||
565               (tmp.continuous != DT3155_SNAP &&
566                tmp.continuous != DT3155_ACQ))
567             {
568               return -EINVAL;
569             }
570           dt3155_status[minor].config = tmp;
571         }
572         return 0;
573       }
574     case DT3155_GET_CONFIG:
575       {
576         if (copy_to_user((void *) arg, (void *) &dt3155_status[minor],
577                      sizeof(dt3155_status_t) ))
578             return -EFAULT;
579         return 0;
580       }
581     case DT3155_FLUSH: /* Flushes the buffers -- ensures fresh data */
582       {
583         if (dt3155_status[minor].state != DT3155_STATE_IDLE)
584           return -EBUSY;
585         return dt3155_flush(minor);
586       }
587     case DT3155_STOP:
588       {
589         if (dt3155_status[minor].state & DT3155_STATE_STOP ||
590             dt3155_status[minor].fbuffer.stop_acquire)
591           return -EBUSY;
592
593         if (dt3155_status[minor].state == DT3155_STATE_IDLE)
594           return 0;
595
596         quick_stop(minor);
597         if (copy_to_user((void *) arg, (void *) &dt3155_status[minor],
598                      sizeof(dt3155_status_t)))
599             return -EFAULT;
600         return 0;
601       }
602     case DT3155_START:
603       {
604         if (dt3155_status[minor].state != DT3155_STATE_IDLE)
605           return -EBUSY;
606
607         dt3155_status[minor].fbuffer.stop_acquire = 0;
608         dt3155_status[minor].fbuffer.frame_count = 0;
609
610         /* Set the MODE in the status -- we default to FRAME */
611         if (dt3155_status[minor].config.acq_mode == DT3155_MODE_FIELD)
612           {
613             dt3155_status[minor].state = DT3155_STATE_FLD;
614           }
615         else
616           {
617             dt3155_status[minor].state = DT3155_STATE_FRAME;
618           }
619
620         dt3155_init_isr(minor);
621         if (copy_to_user( (void *) arg, (void *) &dt3155_status[minor],
622                       sizeof(dt3155_status_t)))
623             return -EFAULT;
624         return 0;
625       }
626     default:
627       {
628         printk("DT3155: invalid IOCTL(0x%x)\n",cmd);
629       printk("DT3155: Valid commands (0x%x), (0x%x), (0x%x), (0x%x), (0x%x)\n",
630              (unsigned int)DT3155_GET_CONFIG,
631              (unsigned int)DT3155_SET_CONFIG,
632              DT3155_START, DT3155_STOP, DT3155_FLUSH);
633         return -ENOSYS;
634       }
635     }
636   return -ENOSYS;
637 }
638
639 /*****************************************************
640  * mmap()
641  *
642  * only allow the user to mmap the registers and buffer
643  * It is quite possible that this is broken, since the
644  * addition of of the capacity for two cards!!!!!!!!
645  * It *looks* like it should work but since I'm not
646  * sure how to use it, I'm not actually sure. (NJC? ditto by SS)
647  *****************************************************/
648 static int dt3155_mmap (struct file * file, struct vm_area_struct * vma)
649 {
650   /* which device are we mmapping? */
651   int                           minor = MINOR(file->f_dentry->d_inode->i_rdev);
652   unsigned long offset;
653   offset = vma->vm_pgoff << PAGE_SHIFT;
654
655   if (offset >= __pa(high_memory) || (file->f_flags & O_SYNC))
656     vma->vm_flags |= VM_IO;
657
658   /* Don't try to swap out physical pages.. */
659   vma->vm_flags |= VM_RESERVED;
660
661   /* they are mapping the registers or the buffer */
662   if ((offset == dt3155_status[minor].reg_addr &&
663        vma->vm_end - vma->vm_start == PCI_PAGE_SIZE) ||
664       (offset == dt3155_status[minor].mem_addr &&
665        vma->vm_end - vma->vm_start == dt3155_status[minor].mem_size))
666     {
667       if (remap_pfn_range(vma,
668                         vma->vm_start,
669                         offset >> PAGE_SHIFT,
670                         vma->vm_end - vma->vm_start,
671                         vma->vm_page_prot)) {
672           printk("DT3155: remap_page_range() failed.\n");
673           return -EAGAIN;
674         }
675     }
676   else
677     {
678       printk("DT3155: dt3155_mmap() bad call.\n");
679       return -ENXIO;
680     }
681
682   return 0;
683 }
684
685
686 /*****************************************************
687  * open()
688  *
689  * Our special open code.
690  * MOD_INC_USE_COUNT make sure that the driver memory is not freed
691  * while the device is in use.
692  *****************************************************/
693 static int dt3155_open( struct inode* inode, struct file* filep)
694 {
695   int minor = MINOR(inode->i_rdev); /* what device are we opening? */
696   if (dt3155_dev_open[ minor ]) {
697     printk ("DT3155:  Already opened by another process.\n");
698     return -EBUSY;
699   }
700
701   if (dt3155_status[ minor ].device_installed==0)
702     {
703       printk("DT3155 Open Error: No such device dt3155 minor number %d\n",
704              minor);
705       return -EIO;
706     }
707
708   if (dt3155_status[ minor ].state != DT3155_STATE_IDLE) {
709     printk ("DT3155:  Not in idle state (state = %lx)\n",
710             dt3155_status[ minor ].state);
711     return -EBUSY;
712   }
713
714   printk("DT3155: Device opened.\n");
715
716   dt3155_dev_open[ minor ] = 1 ;
717
718   dt3155_flush( minor );
719
720   /* Disable ALL interrupts */
721   int_csr_r.reg = 0;
722   WriteMReg( (dt3155_lbase[ minor ] + INT_CSR), int_csr_r.reg );
723
724   init_waitqueue_head(&(dt3155_read_wait_queue[minor]));
725
726   return 0;
727 }
728
729
730 /*****************************************************
731  * close()
732  *
733  * Now decrement the use count.
734  *
735  *****************************************************/
736 static int dt3155_close( struct inode *inode, struct file *filep)
737 {
738   int minor;
739
740   minor = MINOR(inode->i_rdev); /* which device are we closing */
741   if (!dt3155_dev_open[ minor ])
742     {
743       printk("DT3155: attempt to CLOSE a not OPEN device\n");
744     }
745   else
746     {
747       dt3155_dev_open[ minor ] = 0;
748
749       if (dt3155_status[ minor ].state != DT3155_STATE_IDLE)
750         {
751           quick_stop(minor);
752         }
753     }
754   return 0;
755 }
756
757 /*****************************************************
758  * read()
759  *
760  *****************************************************/
761 static ssize_t dt3155_read(struct file *filep, char __user *buf,
762                            size_t count, loff_t *ppos)
763 {
764   /* which device are we reading from? */
765   int           minor = MINOR(filep->f_dentry->d_inode->i_rdev);
766   u_long                offset;
767   int           frame_index;
768   frame_info_t  *frame_info_p;
769
770   /* TODO: this should check the error flag and */
771   /*   return an error on hardware failures */
772   if (count != sizeof(dt3155_read_t))
773     {
774       printk("DT3155 ERROR (NJC): count is not right\n");
775       return -EINVAL;
776     }
777
778
779   /* Hack here -- I'm going to allow reading even when idle.
780    * this is so that the frames can be read after STOP has
781    * been called.  Leaving it here, commented out, as a reminder
782    * for a short while to make sure there are no problems.
783    * Note that if the driver is not opened in non_blocking mode,
784    * and the device is idle, then it could sit here forever! */
785
786   /*  if (dt3155_status[minor].state == DT3155_STATE_IDLE)*/
787   /*    return -EBUSY;*/
788
789   /* non-blocking reads should return if no data */
790   if (filep->f_flags & O_NDELAY)
791     {
792       if ((frame_index = dt3155_get_ready_buffer(minor)) < 0) {
793         /*printk( "dt3155:  no buffers available (?)\n");*/
794         /*              printques(minor); */
795         return -EAGAIN;
796       }
797     }
798   else
799     {
800       /*
801        * sleep till data arrives , or we get interrupted.
802        * Note that wait_event_interruptible() does not actually
803        * sleep/wait if it's condition evaluates to true upon entry.
804        */
805       wait_event_interruptible(dt3155_read_wait_queue[minor],
806                                (frame_index = dt3155_get_ready_buffer(minor))
807                                >= 0);
808
809       if (frame_index < 0)
810         {
811           printk ("DT3155: read: interrupted\n");
812           quick_stop (minor);
813           printques(minor);
814           return -EINTR;
815         }
816     }
817
818   frame_info_p = &dt3155_status[minor].fbuffer.frame_info[frame_index];
819
820   /* make this an offset */
821   offset = frame_info_p->addr - dt3155_status[minor].mem_addr;
822
823   put_user(offset, (unsigned int *) buf);
824   buf += sizeof(u_long);
825   put_user( dt3155_status[minor].fbuffer.frame_count, (unsigned int *) buf);
826   buf += sizeof(u_long);
827   put_user(dt3155_status[minor].state, (unsigned int *) buf);
828   buf += sizeof(u_long);
829   if (copy_to_user(buf, frame_info_p, sizeof(frame_info_t)))
830       return -EFAULT;
831
832   return sizeof(dt3155_read_t);
833 }
834
835 static unsigned int dt3155_poll (struct file * filp, poll_table *wait)
836 {
837   int minor = MINOR(filp->f_dentry->d_inode->i_rdev);
838
839   if (!is_ready_buf_empty(minor))
840     return POLLIN | POLLRDNORM;
841
842   poll_wait (filp, &dt3155_read_wait_queue[minor], wait);
843
844   return 0;
845 }
846
847
848 /*****************************************************
849  * file operations supported by DT3155 driver
850  *  needed by init_module
851  *  register_chrdev
852  *****************************************************/
853 static struct file_operations dt3155_fops = {
854   read:         dt3155_read,
855   ioctl:                dt3155_ioctl,
856   mmap:         dt3155_mmap,
857   poll:           dt3155_poll,
858   open:         dt3155_open,
859   release:      dt3155_close
860 };
861
862
863 /*****************************************************
864  * find_PCI();
865  *
866  * PCI has been totally reworked in 2.1..
867  *****************************************************/
868 static int find_PCI (void)
869 {
870   struct pci_dev *pci_dev = NULL;
871   int error, pci_index = 0;
872   unsigned short rev_device;
873   unsigned long base;
874   unsigned char irq;
875
876   while ((pci_dev = pci_get_device
877           (DT3155_VENDORID, DT3155_DEVICEID, pci_dev)) != NULL)
878     {
879       pci_index ++;
880
881       /* Is it really there? */
882       if ((error =
883            pci_read_config_word(pci_dev, PCI_CLASS_DEVICE, &rev_device)))
884         continue;
885
886       /* Found a board */
887       DT_3155_DEBUG_MSG("DT3155: Device number %d \n", pci_index);
888
889       /* Make sure the driver was compiled with enough buffers to handle
890          this many boards */
891       if (pci_index > MAXBOARDS) {
892         printk("DT3155: ERROR - found %d devices, but driver only configured "
893                "for %d devices\n"
894                "DT3155: Please change MAXBOARDS in dt3155.h\n",
895                pci_index, MAXBOARDS);
896         goto err;
897       }
898
899       /* Now, just go out and make sure that this/these device(s) is/are
900          actually mapped into the kernel address space */
901       if ((error = pci_read_config_dword( pci_dev, PCI_BASE_ADDRESS_0,
902                                           (u_int *) &base)))
903         {
904           printk("DT3155: Was not able to find device \n");
905           goto err;
906         }
907
908       DT_3155_DEBUG_MSG("DT3155: Base address 0 for device is %lx \n", base);
909       dt3155_status[pci_index-1].reg_addr = base;
910
911       /* Remap the base address to a logical address through which we
912        * can access it. */
913       dt3155_lbase[ pci_index - 1 ] = ioremap(base,PCI_PAGE_SIZE);
914       dt3155_status[ pci_index - 1 ].reg_addr = base;
915       DT_3155_DEBUG_MSG("DT3155: New logical address is %p \n",
916                         dt3155_lbase[pci_index-1]);
917       if ( !dt3155_lbase[pci_index-1] )
918         {
919           printk("DT3155: Unable to remap control registers\n");
920           goto err;
921         }
922
923       if ( (error = pci_read_config_byte( pci_dev, PCI_INTERRUPT_LINE, &irq)) )
924         {
925           printk("DT3155: Was not able to find device \n");
926           goto err;
927         }
928
929       DT_3155_DEBUG_MSG("DT3155: IRQ is %d \n",irq);
930       dt3155_status[ pci_index-1 ].irq = irq;
931       /* Set flag: kth device found! */
932       dt3155_status[ pci_index-1 ].device_installed = 1;
933       printk("DT3155: Installing device %d w/irq %d and address %p\n",
934              pci_index,
935              (u_int)dt3155_status[pci_index-1].irq,
936              dt3155_lbase[pci_index-1]);
937
938     }
939   ndevices = pci_index;
940
941   return DT_3155_SUCCESS;
942
943 err:
944   pci_dev_put(pci_dev);
945   return DT_3155_FAILURE;
946 }
947
948 u_long allocatorAddr = 0;
949
950 /*****************************************************
951  * init_module()
952  *****************************************************/
953 int init_module(void)
954 {
955   int index;
956   int rcode = 0;
957   char *devname[ MAXBOARDS ];
958
959   devname[ 0 ] = "dt3155a";
960 #if MAXBOARDS == 2
961   devname[ 1 ] = "dt3155b";
962 #endif
963
964   printk("DT3155: Loading module...\n");
965
966   /* Register the device driver */
967   rcode = register_chrdev( dt3155_major, "dt3155", &dt3155_fops );
968   if( rcode < 0 )
969     {
970       printk( KERN_INFO "DT3155: register_chrdev failed \n");
971       return rcode;
972     }
973
974   if( dt3155_major == 0 )
975     dt3155_major = rcode; /* dynamic */
976
977
978   /* init the status variables.                     */
979   /* DMA memory is taken care of in setup_buffers() */
980   for ( index = 0; index < MAXBOARDS; index++ )
981     {
982       dt3155_status[ index ].config.acq_mode   = DT3155_MODE_FRAME;
983       dt3155_status[ index ].config.continuous = DT3155_ACQ;
984       dt3155_status[ index ].config.cols       = DT3155_MAX_COLS;
985       dt3155_status[ index ].config.rows       = DT3155_MAX_ROWS;
986       dt3155_status[ index ].state = DT3155_STATE_IDLE;
987
988       /* find_PCI() will check if devices are installed; */
989       /* first assume they're not:                       */
990       dt3155_status[ index ].mem_addr          = 0;
991       dt3155_status[ index ].mem_size          = 0;
992       dt3155_status[ index ].state             = DT3155_STATE_IDLE;
993       dt3155_status[ index ].device_installed  = 0;
994     }
995
996   /* Now let's find the hardware.  find_PCI() will set ndevices to the
997    * number of cards found in this machine. */
998     {
999       if ( (rcode = find_PCI()) !=  DT_3155_SUCCESS )
1000         {
1001           printk("DT3155 error: find_PCI() failed to find dt3155 board(s)\n");
1002           unregister_chrdev( dt3155_major, "dt3155" );
1003           return rcode;
1004         }
1005     }
1006
1007   /* Ok, time to setup the frame buffers */
1008   if( (rcode = dt3155_setup_buffers(&allocatorAddr)) < 0 )
1009     {
1010       printk("DT3155: Error: setting up buffer not large enough.");
1011       unregister_chrdev( dt3155_major, "dt3155" );
1012       return rcode;
1013     }
1014
1015   /* If we are this far, then there is enough RAM */
1016   /* for the buffers: Print the configuration.    */
1017   for(  index = 0;  index < ndevices;  index++ )
1018     {
1019       printk("DT3155: Device = %d; acq_mode = %d; "
1020              "continuous = %d; cols = %d; rows = %d;\n",
1021              index ,
1022              dt3155_status[ index ].config.acq_mode,
1023              dt3155_status[ index ].config.continuous,
1024              dt3155_status[ index ].config.cols,
1025              dt3155_status[ index ].config.rows);
1026       printk("DT3155: m_addr = 0x%x; m_size = %ld; "
1027              "state = %ld; device_installed = %d\n",
1028              (u_int)dt3155_status[ index ].mem_addr,
1029              dt3155_status[ index ].mem_size,
1030              dt3155_status[ index ].state,
1031              dt3155_status[ index ].device_installed);
1032     }
1033
1034   /* Disable ALL interrupts */
1035   int_csr_r.reg = 0;
1036   for(  index = 0;  index < ndevices;  index++ )
1037     {
1038       WriteMReg( (dt3155_lbase[ index ] + INT_CSR), int_csr_r.reg );
1039       if( dt3155_status[ index ].device_installed )
1040         {
1041           /*
1042            * This driver *looks* like it can handle sharing interrupts,
1043            * but I can't actually test myself. I've had reports that it
1044            * DOES work so I'll enable it for now. This comment will remain
1045            * as a reminder in case any problems arise. (SS)
1046            */
1047           /* in older kernels flags are: SA_SHIRQ | SA_INTERRUPT */
1048           rcode = request_irq( dt3155_status[ index ].irq, (void *)dt3155_isr,
1049                                IRQF_SHARED | IRQF_DISABLED, devname[ index ],
1050                                (void*) &dt3155_status[index]);
1051           if( rcode < 0 )
1052             {
1053               printk("DT3155: minor %d request_irq failed for IRQ %d\n",
1054                      index, dt3155_status[index].irq);
1055               unregister_chrdev( dt3155_major, "dt3155" );
1056               return rcode;
1057             }
1058         }
1059     }
1060
1061   printk("DT3155: finished loading\n");
1062
1063   return 0;
1064 }
1065
1066 /*****************************************************
1067  * cleanup_module(void)
1068  *
1069  *****************************************************/
1070 void cleanup_module(void)
1071 {
1072   int index;
1073
1074   printk("DT3155:  cleanup_module called\n");
1075
1076   /* removed DMA allocated with the allocator */
1077 #ifdef STANDALONE_ALLOCATOR
1078   if (allocatorAddr != 0)
1079     allocator_free_dma(allocatorAddr);
1080 #else
1081   allocator_cleanup();
1082 #endif
1083
1084   unregister_chrdev( dt3155_major, "dt3155" );
1085
1086   for( index = 0; index < ndevices; index++ )
1087     {
1088       if( dt3155_status[ index ].device_installed == 1 )
1089         {
1090           printk( "DT3155: Freeing irq %d for device %d\n",
1091                   dt3155_status[ index ].irq, index );
1092           free_irq( dt3155_status[ index ].irq, (void*)&dt3155_status[index] );
1093         }
1094     }
1095 }
1096