Staging: dt3155: add needed #include
[GitHub/mt8127/android_kernel_alcatel_ttab.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/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