2 * drivers/sbus/char/vfc_dev.c
4 * Driver for the Videopix Frame Grabber.
6 * In order to use the VFC you need to program the video controller
7 * chip. This chip is the Phillips SAA9051. You need to call their
8 * documentation ordering line to get the docs.
10 * There is very little documentation on the VFC itself. There is
11 * some useful info that can be found in the manuals that come with
12 * the card. I will hopefully write some better docs at a later date.
14 * Copyright (C) 1996 Manish Vachharajani (mvachhar@noc.rutgers.edu)
17 #include <linux/module.h>
18 #include <linux/kernel.h>
19 #include <linux/string.h>
20 #include <linux/malloc.h>
21 #include <linux/errno.h>
22 #include <linux/sched.h>
24 #include <linux/uaccess.h>
26 #include <asm/openprom.h>
27 #include <asm/oplib.h>
29 #include <asm/system.h>
31 #include <asm/delay.h>
33 #include <asm/pgtable.h>
35 #define VFC_MAJOR (60)
38 #define VFC_IOCTL_DEBUG
42 #include <asm/vfc_ioctls.h>
44 struct vfc_dev
**vfc_dev_lst
;
45 static char vfcstr
[]="vfc";
46 static unsigned char saa9051_init_array
[VFC_SAA9051_NR
]=
47 { 0x00, 0x64, 0x72, 0x52,
48 0x36, 0x18, 0xff, 0x20,
49 0xfc, 0x77, 0xe3, 0x50,
52 void vfc_lock_device(struct vfc_dev
*dev
) {
53 down(&dev
->device_lock_sem
);
56 void vfc_unlock_device(struct vfc_dev
*dev
) {
57 up(&dev
->device_lock_sem
);
61 void vfc_captstat_reset(struct vfc_dev
*dev
)
63 dev
->control_reg
|= VFC_CONTROL_CAPTRESET
;
64 dev
->regs
->control
=dev
->control_reg
;
65 dev
->control_reg
&= ~VFC_CONTROL_CAPTRESET
;
66 dev
->regs
->control
=dev
->control_reg
;
67 dev
->control_reg
|= VFC_CONTROL_CAPTRESET
;
68 dev
->regs
->control
=dev
->control_reg
;
72 void vfc_memptr_reset(struct vfc_dev
*dev
)
74 dev
->control_reg
|= VFC_CONTROL_MEMPTR
;
75 dev
->regs
->control
= dev
->control_reg
;
76 dev
->control_reg
&= ~VFC_CONTROL_MEMPTR
;
77 dev
->regs
->control
= dev
->control_reg
;
78 dev
->control_reg
|= VFC_CONTROL_MEMPTR
;
79 dev
->regs
->control
= dev
->control_reg
;
83 int vfc_csr_init(struct vfc_dev
*dev
)
85 dev
->control_reg
= 0x80000000;
86 dev
->regs
->control
= dev
->control_reg
;
88 dev
->control_reg
&= ~0x80000000;
89 dev
->regs
->control
= dev
->control_reg
;
91 dev
->regs
->i2c_magic2
= 0x0f000000;
93 vfc_memptr_reset(dev
);
95 dev
->control_reg
&= ~VFC_CONTROL_DIAGMODE
;
96 dev
->control_reg
&= ~VFC_CONTROL_CAPTURE
;
97 dev
->control_reg
|= 0x40000000;
98 dev
->regs
->control
=dev
->control_reg
;
100 vfc_captstat_reset(dev
);
105 int vfc_saa9051_init(struct vfc_dev
*dev
)
108 for(i
=0;i
<VFC_SAA9051_NR
;i
++) {
109 dev
->saa9051_state_array
[i
]=saa9051_init_array
[i
];
111 vfc_i2c_sendbuf(dev
,VFC_SAA9051_ADDR
,
112 dev
->saa9051_state_array
, VFC_SAA9051_NR
);
116 int init_vfc_hw(struct vfc_dev
*dev
)
118 vfc_lock_device(dev
);
121 vfc_pcf8584_init(dev
);
122 vfc_init_i2c_bus(dev
); /* hopefully this doesn't undo the magic
124 vfc_saa9051_init(dev
);
125 vfc_unlock_device(dev
);
129 int init_vfc_devstruct(struct vfc_dev
*dev
, int instance
)
131 dev
->instance
=instance
;
132 dev
->device_lock_sem
=MUTEX
;
139 int init_vfc_device(struct linux_sbus_device
*sdev
,struct vfc_dev
*dev
,
142 printk(KERN_ERR
"VFC: Bogus pointer passed\n");
145 printk("Initializing vfc%d\n",instance
);
147 prom_apply_sbus_ranges(sdev
->my_bus
, &sdev
->reg_addrs
[0], sdev
->num_registers
, sdev
);
148 dev
->regs
=sparc_alloc_io(sdev
->reg_addrs
[0].phys_addr
, 0,
149 sizeof(struct vfc_regs
), vfcstr
,
150 sdev
->reg_addrs
[0].which_io
, 0x0);
151 dev
->which_io
=sdev
->reg_addrs
[0].which_io
;
152 dev
->phys_regs
=(struct vfc_regs
*)sdev
->reg_addrs
[0].phys_addr
;
153 if(!dev
->regs
) return -EIO
;
155 printk("vfc%d: registers mapped at phys_addr: 0x%lx\n virt_addr: 0x%lx\n",
156 instance
,(unsigned long)sdev
->reg_addrs
[0].phys_addr
,(unsigned long)dev
->regs
);
158 if(init_vfc_devstruct(dev
,instance
)) return -EINVAL
;
159 if(init_vfc_hw(dev
)) return -EIO
;
165 struct vfc_dev
*vfc_get_dev_ptr(int instance
)
167 return vfc_dev_lst
[instance
];
170 static int vfc_open(struct inode
*inode
, struct file
*file
)
173 dev
=vfc_get_dev_ptr(MINOR(inode
->i_rdev
));
174 if(!dev
) return -ENODEV
;
175 if(dev
->busy
) return -EBUSY
;
178 vfc_lock_device(dev
);
181 vfc_pcf8584_init(dev
);
182 vfc_init_i2c_bus(dev
);
183 vfc_saa9051_init(dev
);
184 vfc_memptr_reset(dev
);
185 vfc_captstat_reset(dev
);
187 vfc_unlock_device(dev
);
191 static void vfc_release(struct inode
*inode
,struct file
*file
)
194 dev
=vfc_get_dev_ptr(MINOR(inode
->i_rdev
));
196 if(!dev
->busy
) return;
202 static int vfc_debug(struct vfc_dev
*dev
, int cmd
, unsigned long arg
)
204 struct vfc_debug_inout inout
;
205 unsigned char *buffer
;
208 if(!capable(CAP_SYS_ADMIN
)) return -EPERM
;
212 if(copy_from_user(&inout
, (void *)arg
, sizeof(inout
))) {
216 buffer
= kmalloc(inout
.len
*sizeof(char), GFP_KERNEL
);
220 if(copy_from_user(buffer
, inout
.buffer
,
221 inout
.len
*sizeof(char));) {
222 kfree_s(buffer
,inout
.len
*sizeof(char));
227 vfc_lock_device(dev
);
229 vfc_i2c_sendbuf(dev
,inout
.addr
& 0xff,
230 inout
.buffer
,inout
.len
);
232 if (copy_to_user((void *)arg
,&inout
,sizeof(inout
))) {
233 kfree_s(buffer
, inout
.len
);
236 vfc_unlock_device(dev
);
240 if (copy_from_user(&inout
, (void *)arg
, sizeof(inout
))) {
244 buffer
= kmalloc(inout
.len
, GFP_KERNEL
);
247 memset(buffer
,0,inout
.len
*sizeof(char));
248 vfc_lock_device(dev
);
250 vfc_i2c_recvbuf(dev
,inout
.addr
& 0xff
252 vfc_unlock_device(dev
);
254 if (copy_to_user(inout
.buffer
, buffer
, inout
.len
)) {
255 kfree_s(buffer
,inout
.len
);
258 if (copy_to_user((void *)arg
,&inout
,sizeof(inout
))) {
259 kfree_s(buffer
,inout
.len
);
262 kfree_s(buffer
,inout
.len
);
270 int vfc_capture_start(struct vfc_dev
*dev
)
272 vfc_captstat_reset(dev
);
273 dev
->control_reg
=dev
->regs
->control
;
274 if((dev
->control_reg
& VFC_STATUS_CAPTURE
)) {
275 printk(KERN_ERR
"vfc%d: vfc capture status not reset\n",
280 vfc_lock_device(dev
);
281 dev
->control_reg
&= ~VFC_CONTROL_CAPTURE
;
282 dev
->regs
->control
=dev
->control_reg
;
283 dev
->control_reg
|= VFC_CONTROL_CAPTURE
;
284 dev
->regs
->control
=dev
->control_reg
;
285 dev
->control_reg
&= ~VFC_CONTROL_CAPTURE
;
286 dev
->regs
->control
=dev
->control_reg
;
287 vfc_unlock_device(dev
);
292 int vfc_capture_poll(struct vfc_dev
*dev
)
296 if((dev
->regs
->control
& VFC_STATUS_CAPTURE
)) break;
297 vfc_i2c_delay_no_busy(dev
,100);
300 printk(KERN_WARNING
"vfc%d: capture timed out\n", dev
->instance
);
308 static int vfc_set_control_ioctl(struct inode
*inode
, struct file
*file
,
309 struct vfc_dev
*dev
, unsigned long arg
)
312 if (copy_from_user(&setcmd
,(void *)arg
,sizeof(unsigned int)))
314 VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCSCTRL) arg=0x%x\n",
315 dev
->instance
,setcmd
));
318 vfc_lock_device(dev
);
319 vfc_memptr_reset(dev
);
320 vfc_unlock_device(dev
);
324 vfc_capture_start(dev
);
325 vfc_capture_poll(dev
);
329 vfc_lock_device(dev
);
330 dev
->control_reg
|= VFC_CONTROL_DIAGMODE
;
331 dev
->regs
->control
= dev
->control_reg
;
332 vfc_unlock_device(dev
);
337 vfc_lock_device(dev
);
338 dev
->control_reg
&= ~VFC_CONTROL_DIAGMODE
;
339 dev
->regs
->control
= dev
->control_reg
;
340 vfc_unlock_device(dev
);
344 vfc_capture_start(dev
);
348 vfc_capture_poll(dev
);
358 int vfc_port_change_ioctl(struct inode
*inode
, struct file
*file
,
359 struct vfc_dev
*dev
, unsigned long arg
)
364 if(copy_from_user(&cmd
, (void *)arg
, sizeof(unsigned int))) {
365 VFC_IOCTL_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to "
366 "vfc_port_change_ioctl\n",dev
->instance
));
370 VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCPORTCHG) arg=0x%x\n",
376 VFC_SAA9051_SA(dev
,VFC_SAA9051_HSY_START
) = 0x72;
377 VFC_SAA9051_SA(dev
,VFC_SAA9051_HSY_STOP
) = 0x52;
378 VFC_SAA9051_SA(dev
,VFC_SAA9051_HC_START
) = 0x36;
379 VFC_SAA9051_SA(dev
,VFC_SAA9051_HC_STOP
) = 0x18;
380 VFC_SAA9051_SA(dev
,VFC_SAA9051_HORIZ_PEAK
) = VFC_SAA9051_BP2
;
381 VFC_SAA9051_SA(dev
,VFC_SAA9051_C3
) = VFC_SAA9051_CT
| VFC_SAA9051_SS3
;
382 VFC_SAA9051_SA(dev
,VFC_SAA9051_SECAM_DELAY
) = 0x3e;
385 VFC_SAA9051_SA(dev
,VFC_SAA9051_HSY_START
) = 0x3a;
386 VFC_SAA9051_SA(dev
,VFC_SAA9051_HSY_STOP
) = 0x17;
387 VFC_SAA9051_SA(dev
,VFC_SAA9051_HC_START
) = 0xfa;
388 VFC_SAA9051_SA(dev
,VFC_SAA9051_HC_STOP
) = 0xde;
389 VFC_SAA9051_SA(dev
,VFC_SAA9051_HORIZ_PEAK
) = VFC_SAA9051_BY
| VFC_SAA9051_PF
| VFC_SAA9051_BP2
;
390 VFC_SAA9051_SA(dev
,VFC_SAA9051_C3
) = VFC_SAA9051_YC
;
391 VFC_SAA9051_SA(dev
,VFC_SAA9051_SECAM_DELAY
) = 0;
392 VFC_SAA9051_SA(dev
,VFC_SAA9051_C2
) &= ~(VFC_SAA9051_SS0
| VFC_SAA9051_SS1
);
402 VFC_SAA9051_SA(dev
,VFC_SAA9051_C2
) |= VFC_SAA9051_SS0
| VFC_SAA9051_SS1
;
405 VFC_SAA9051_SA(dev
,VFC_SAA9051_C2
) &= ~(VFC_SAA9051_SS0
| VFC_SAA9051_SS1
);
406 VFC_SAA9051_SA(dev
,VFC_SAA9051_C2
) |= VFC_SAA9051_SS0
;
415 VFC_SAA9051_SA(dev
,VFC_SAA9051_C3
) &= ~(VFC_SAA9051_SS2
);
416 ret
=vfc_update_saa9051(dev
);
418 VFC_SAA9051_SA(dev
,VFC_SAA9051_C3
) |= (VFC_SAA9051_SS2
);
419 ret
=vfc_update_saa9051(dev
);
423 int vfc_set_video_ioctl(struct inode
*inode
, struct file
*file
,
424 struct vfc_dev
*dev
, unsigned long arg
)
428 if(copy_from_user(&cmd
, (void *)arg
, sizeof(unsigned int))) {
429 VFC_IOCTL_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to "
430 "vfc_set_video_ioctl\n",dev
->instance
));
434 VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCSVID) arg=0x%x\n",
439 VFC_SAA9051_SA(dev
,VFC_SAA9051_C1
) &= ~VFC_SAA9051_ALT
;
440 VFC_SAA9051_SA(dev
,VFC_SAA9051_C1
) |= VFC_SAA9051_YPN
|
441 VFC_SAA9051_CCFR0
| VFC_SAA9051_CCFR1
| VFC_SAA9051_FS
;
442 ret
=vfc_update_saa9051(dev
);
445 VFC_SAA9051_SA(dev
,VFC_SAA9051_C1
) &= ~(VFC_SAA9051_YPN
|
449 VFC_SAA9051_SA(dev
,VFC_SAA9051_C1
) |= VFC_SAA9051_ALT
;
450 ret
=vfc_update_saa9051(dev
);
454 VFC_SAA9051_SA(dev
,VFC_SAA9051_C1
) |= VFC_SAA9051_CO
;
455 VFC_SAA9051_SA(dev
,VFC_SAA9051_HORIZ_PEAK
) &= ~(VFC_SAA9051_BY
| VFC_SAA9051_PF
);
456 ret
=vfc_update_saa9051(dev
);
459 VFC_SAA9051_SA(dev
,VFC_SAA9051_C1
) &= ~(VFC_SAA9051_CO
);
460 VFC_SAA9051_SA(dev
,VFC_SAA9051_HORIZ_PEAK
) |= VFC_SAA9051_BY
| VFC_SAA9051_PF
;
461 ret
=vfc_update_saa9051(dev
);
470 int vfc_get_video_ioctl(struct inode
*inode
, struct file
*file
,
471 struct vfc_dev
*dev
, unsigned long arg
)
474 unsigned int status
=NO_LOCK
;
475 unsigned char buf
[1];
477 if(vfc_i2c_recvbuf(dev
,VFC_SAA9051_ADDR
,buf
,1)) {
478 printk(KERN_ERR
"vfc%d: Unable to get status\n",dev
->instance
);
482 if(buf
[0] & VFC_SAA9051_HLOCK
) {
484 } else if(buf
[0] & VFC_SAA9051_FD
) {
485 if(buf
[0] & VFC_SAA9051_CD
)
490 if(buf
[0] & VFC_SAA9051_CD
)
495 VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCGVID) returning status 0x%x; buf[0]=%x\n",dev
->instance
,
497 if (copy_to_user((void *)arg
,&status
,sizeof(unsigned int))) {
498 VFC_IOCTL_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to "
499 "vfc_get_video_ioctl\n",dev
->instance
));
505 static int vfc_ioctl(struct inode
*inode
, struct file
*file
, unsigned int cmd
,
512 dev
=vfc_get_dev_ptr(MINOR(inode
->i_rdev
));
513 if(!dev
) return -ENODEV
;
515 switch(cmd
& 0x0000ffff) {
518 VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCGCTRL)\n",dev
->instance
));
520 tmp
=dev
->regs
->control
;
521 if(copy_to_user((void *)arg
,&tmp
, sizeof(unsigned int))) {
528 ret
=vfc_set_control_ioctl(inode
, file
, dev
, arg
);
531 ret
=vfc_get_video_ioctl(inode
,file
,dev
,arg
);
534 ret
=vfc_set_video_ioctl(inode
,file
,dev
,arg
);
537 VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCHUE)\n",dev
->instance
));
538 if(copy_from_user(&tmp
,(void *)arg
,sizeof(unsigned int))) {
539 VFC_IOCTL_DEBUG_PRINTK(("vfc%d: User passed bogus pointer "
540 "to IOCTL(VFCHUE)",dev
->instance
));
543 VFC_SAA9051_SA(dev
,VFC_SAA9051_HUE
)=tmp
;
544 vfc_update_saa9051(dev
);
549 ret
=vfc_port_change_ioctl(inode
, file
, dev
, arg
);
553 VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCRDINFO)\n",dev
->instance
));
556 ret
=vfc_debug(vfc_get_dev_ptr(MINOR(inode
->i_rdev
)),
563 static int vfc_mmap(struct inode
*inode
, struct file
*file
,
564 struct vm_area_struct
*vma
)
566 unsigned int map_size
,ret
,map_offset
;
569 dev
=vfc_get_dev_ptr(MINOR(inode
->i_rdev
));
570 if(!dev
) return -ENODEV
;
572 map_size
=vma
->vm_end
- vma
->vm_start
;
573 if(map_size
> sizeof(struct vfc_regs
))
574 map_size
=sizeof(struct vfc_regs
);
577 if(vma
->vm_offset
& ~PAGE_MASK
) return -ENXIO
;
578 vma
->vm_flags
|= VM_SHM
| VM_LOCKED
| VM_IO
| VM_MAYREAD
| VM_MAYWRITE
| VM_MAYSHARE
;
579 map_offset
=(unsigned int)dev
->phys_regs
;
580 ret
= io_remap_page_range(vma
->vm_start
,map_offset
,map_size
,
581 vma
->vm_page_prot
, dev
->which_io
);
591 static int vfc_lseek(struct inode
*inode
, struct file
*file
,
592 off_t offset
, int origin
)
597 static struct file_operations vfc_fops
= {
598 vfc_lseek
, /* vfc_lseek */
599 NULL
, /* vfc_write */
601 NULL
, /* vfc_readdir */
602 NULL
, /* vfc_select */
610 static int vfc_probe(void)
612 struct linux_sbus
*bus
;
613 struct linux_sbus_device
*sdev
= NULL
;
615 int instance
=0,cards
=0;
617 for_all_sbusdev(sdev
,bus
) {
618 if (strcmp(sdev
->prom_name
,"vfc") == 0) {
627 vfc_dev_lst
=(struct vfc_dev
**)kmalloc(sizeof(struct vfc_dev
*)*
632 memset(vfc_dev_lst
,0,sizeof(struct vfc_dev
*)*(cards
+1));
633 vfc_dev_lst
[cards
]=NULL
;
635 ret
=register_chrdev(VFC_MAJOR
,vfcstr
,&vfc_fops
);
637 printk(KERN_ERR
"Unable to get major number %d\n",VFC_MAJOR
);
643 for_all_sbusdev(sdev
,bus
) {
644 if (strcmp(sdev
->prom_name
,"vfc") == 0) {
645 vfc_dev_lst
[instance
]=(struct vfc_dev
*)
646 kmalloc(sizeof(struct vfc_dev
), GFP_KERNEL
);
647 if(vfc_dev_lst
[instance
] == NULL
) return -ENOMEM
;
648 ret
=init_vfc_device(sdev
,
649 vfc_dev_lst
[instance
],
652 printk(KERN_ERR
"Unable to initialize"
653 " vfc%d device\n",instance
);
666 int init_module(void)
675 static void deinit_vfc_device(struct vfc_dev
*dev
)
678 sparc_free_io((void *)dev
->regs
,sizeof(struct vfc_regs
));
682 void cleanup_module(void)
684 struct vfc_dev
**devp
;
685 unregister_chrdev(VFC_MAJOR
,vfcstr
);
686 for(devp
=vfc_dev_lst
;*devp
;devp
++) {
687 deinit_vfc_device(*devp
);