Staging: dt3155: fix build warnings
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / staging / dt3155 / dt3155_drv.c
CommitLineData
aa337ef1
SS
1/*
2
3Copyright 1996,2002,2005 Gregory D. Hager, Alfred A. Rizzi, Noah J. Cowan,
4 Jason Lapenta, Scott Smedley, Greg Sharp
5
6This file is part of the DT3155 Device Driver.
7
8The DT3155 Device Driver is free software; you can redistribute it
9and/or modify it under the terms of the GNU General Public License as
10published by the Free Software Foundation; either version 2 of the
11License, or (at your option) any later version.
12
13The DT3155 Device Driver is distributed in the hope that it will be
14useful, but WITHOUT ANY WARRANTY; without even the implied warranty
15of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License
19along with the DT3155 Device Driver; if not, write to the Free
20Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21MA 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
58extern void printques(int);
59
60#ifdef MODULE
61#include <linux/module.h>
aa337ef1
SS
62#include <linux/interrupt.h>
63
64
aa337ef1 65MODULE_LICENSE("GPL");
aa337ef1
SS
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>
ae7fd7b8 76#include <linux/sched.h>
aa337ef1
SS
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. */
88int 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 */
aa337ef1 105wait_queue_head_t dt3155_read_wait_queue[ MAXBOARDS ];
aa337ef1
SS
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 */
112int 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 */
122struct dt3155_status_s dt3155_status[ MAXBOARDS ];
123
124/* kernel logical address of the board */
125u_char *dt3155_lbase[ MAXBOARDS ] = { NULL
126#if MAXBOARDS == 2
127 , NULL
128#endif
129};
130/* DT3155 registers */
131u_char *dt3155_bbase = NULL; /* kernel logical address of the *
132 * buffer region */
133u_int dt3155_dev_open[ MAXBOARDS ] = {0
134#if MAXBOARDS == 2
135 , 0
136#endif
137};
138
139u_int ndevices = 0;
140u_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 */
148static 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 *****************************************************/
178static inline void dt3155_isr( int irq, void *dev_id, struct pt_regs *regs )
179{
180 int minor = -1;
181 int index;
aa337ef1 182 unsigned long flags;
aa337ef1
SS
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;
aa337ef1
SS
256 local_save_flags(flags);
257 local_irq_disable();
aa337ef1
SS
258 wake_up_interruptible( &dt3155_read_wait_queue[ minor ] );
259
260 /* Set up the DMA address for the next field */
aa337ef1 261 local_irq_restore(flags);
aa337ef1
SS
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
aa337ef1
SS
333 local_save_flags(flags);
334 local_irq_disable();
aa337ef1
SS
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
aa337ef1 390 local_irq_restore(flags);
aa337ef1
SS
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 *****************************************************/
429static 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 *****************************************************/
525static 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",
f721ad7a
GKH
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);
aa337ef1
SS
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",
f721ad7a
GKH
630 (unsigned int)DT3155_GET_CONFIG,
631 (unsigned int)DT3155_SET_CONFIG,
aa337ef1
SS
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 *****************************************************/
648static 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;
aa337ef1
SS
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
aa337ef1
SS
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 {
aa337ef1
SS
667 if (remap_pfn_range(vma,
668 vma->vm_start,
669 offset >> PAGE_SHIFT,
670 vma->vm_end - vma->vm_start,
2141ec62 671 vma->vm_page_prot)) {
aa337ef1
SS
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 *****************************************************/
693static 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 ;
aa337ef1
SS
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
aa337ef1 724 init_waitqueue_head(&(dt3155_read_wait_queue[minor]));
aa337ef1
SS
725
726 return 0;
727}
728
729
730/*****************************************************
731 * close()
732 *
733 * Now decrement the use count.
734 *
735 *****************************************************/
736static 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 {
aa337ef1
SS
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 *****************************************************/
f721ad7a
GKH
761static ssize_t dt3155_read(struct file *filep, char __user *buf,
762 size_t count, loff_t *ppos)
aa337ef1
SS
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
aa337ef1
SS
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
aa337ef1
SS
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
835static 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 *****************************************************/
853static 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 *****************************************************/
868static 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
6910dadf 876 while ((pci_dev = pci_get_device
aa337ef1
SS
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);
6910dadf 896 goto err;
aa337ef1
SS
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");
6910dadf 905 goto err;
aa337ef1
SS
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;
f721ad7a
GKH
915 DT_3155_DEBUG_MSG("DT3155: New logical address is %p \n",
916 dt3155_lbase[pci_index-1]);
aa337ef1
SS
917 if ( !dt3155_lbase[pci_index-1] )
918 {
919 printk("DT3155: Unable to remap control registers\n");
6910dadf 920 goto err;
aa337ef1
SS
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");
6910dadf 926 goto err;
aa337ef1
SS
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;
f721ad7a 933 printk("DT3155: Installing device %d w/irq %d and address %p\n",
aa337ef1
SS
934 pci_index,
935 (u_int)dt3155_status[pci_index-1].irq,
f721ad7a 936 dt3155_lbase[pci_index-1]);
aa337ef1
SS
937
938 }
939 ndevices = pci_index;
940
941 return DT_3155_SUCCESS;
6910dadf
SH
942
943err:
944 pci_dev_put(pci_dev);
945 return DT_3155_FAILURE;
aa337ef1
SS
946}
947
948u_long allocatorAddr = 0;
949
950/*****************************************************
951 * init_module()
952 *****************************************************/
953int init_module(void)
954{
955 int index;
956 int rcode = 0;
957 char *devname[ MAXBOARDS ];
958
aa337ef1
SS
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. */
aa337ef1
SS
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 *****************************************************/
1070void 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 }
aa337ef1
SS
1095}
1096