blob: 7a103698fa3c3a3ea1e9023cbb55b5d7f4b8e1ab [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * drivers/sbus/char/vfc_dev.c
3 *
4 * Driver for the Videopix Frame Grabber.
5 *
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.
9 *
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.
13 *
14 * Copyright (C) 1996 Manish Vachharajani (mvachhar@noc.rutgers.edu)
15 * */
16
17#include <linux/module.h>
18#include <linux/kernel.h>
19#include <linux/string.h>
20#include <linux/slab.h>
21#include <linux/errno.h>
22#include <linux/sched.h>
23#include <linux/fs.h>
24#include <linux/smp_lock.h>
25#include <linux/delay.h>
26#include <linux/spinlock.h>
27#include <linux/mm.h>
28
29#include <asm/openprom.h>
30#include <asm/oplib.h>
31#include <asm/io.h>
32#include <asm/system.h>
33#include <asm/sbus.h>
34#include <asm/page.h>
35#include <asm/pgtable.h>
36#include <asm/uaccess.h>
37
38#define VFC_MAJOR (60)
39
40#if 0
41#define VFC_IOCTL_DEBUG
42#endif
43
44#include "vfc.h"
45#include <asm/vfc_ioctls.h>
46
47static struct file_operations vfc_fops;
48struct vfc_dev **vfc_dev_lst;
49static char vfcstr[]="vfc";
50static unsigned char saa9051_init_array[VFC_SAA9051_NR] = {
51 0x00, 0x64, 0x72, 0x52,
52 0x36, 0x18, 0xff, 0x20,
53 0xfc, 0x77, 0xe3, 0x50,
54 0x3e
55};
56
57void vfc_lock_device(struct vfc_dev *dev)
58{
59 down(&dev->device_lock_sem);
60}
61
62void vfc_unlock_device(struct vfc_dev *dev)
63{
64 up(&dev->device_lock_sem);
65}
66
67
68void vfc_captstat_reset(struct vfc_dev *dev)
69{
70 dev->control_reg |= VFC_CONTROL_CAPTRESET;
71 sbus_writel(dev->control_reg, &dev->regs->control);
72 dev->control_reg &= ~VFC_CONTROL_CAPTRESET;
73 sbus_writel(dev->control_reg, &dev->regs->control);
74 dev->control_reg |= VFC_CONTROL_CAPTRESET;
75 sbus_writel(dev->control_reg, &dev->regs->control);
76}
77
78void vfc_memptr_reset(struct vfc_dev *dev)
79{
80 dev->control_reg |= VFC_CONTROL_MEMPTR;
81 sbus_writel(dev->control_reg, &dev->regs->control);
82 dev->control_reg &= ~VFC_CONTROL_MEMPTR;
83 sbus_writel(dev->control_reg, &dev->regs->control);
84 dev->control_reg |= VFC_CONTROL_MEMPTR;
85 sbus_writel(dev->control_reg, &dev->regs->control);
86}
87
88int vfc_csr_init(struct vfc_dev *dev)
89{
90 dev->control_reg = 0x80000000;
91 sbus_writel(dev->control_reg, &dev->regs->control);
92 udelay(200);
93 dev->control_reg &= ~0x80000000;
94 sbus_writel(dev->control_reg, &dev->regs->control);
95 udelay(100);
96 sbus_writel(0x0f000000, &dev->regs->i2c_magic2);
97
98 vfc_memptr_reset(dev);
99
100 dev->control_reg &= ~VFC_CONTROL_DIAGMODE;
101 dev->control_reg &= ~VFC_CONTROL_CAPTURE;
102 dev->control_reg |= 0x40000000;
103 sbus_writel(dev->control_reg, &dev->regs->control);
104
105 vfc_captstat_reset(dev);
106
107 return 0;
108}
109
110int vfc_saa9051_init(struct vfc_dev *dev)
111{
112 int i;
113
114 for (i = 0; i < VFC_SAA9051_NR; i++)
115 dev->saa9051_state_array[i] = saa9051_init_array[i];
116
117 vfc_i2c_sendbuf(dev,VFC_SAA9051_ADDR,
118 dev->saa9051_state_array, VFC_SAA9051_NR);
119 return 0;
120}
121
122int init_vfc_hw(struct vfc_dev *dev)
123{
124 vfc_lock_device(dev);
125 vfc_csr_init(dev);
126
127 vfc_pcf8584_init(dev);
128 vfc_init_i2c_bus(dev); /* hopefully this doesn't undo the magic
129 sun code above*/
130 vfc_saa9051_init(dev);
131 vfc_unlock_device(dev);
132 return 0;
133}
134
135int init_vfc_devstruct(struct vfc_dev *dev, int instance)
136{
137 dev->instance=instance;
138 init_MUTEX(&dev->device_lock_sem);
139 dev->control_reg=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140 dev->busy=0;
141 return 0;
142}
143
144int init_vfc_device(struct sbus_dev *sdev,struct vfc_dev *dev, int instance)
145{
146 if(dev == NULL) {
147 printk(KERN_ERR "VFC: Bogus pointer passed\n");
148 return -ENOMEM;
149 }
150 printk("Initializing vfc%d\n",instance);
151 dev->regs = NULL;
152 dev->regs = (volatile struct vfc_regs *)
153 sbus_ioremap(&sdev->resource[0], 0,
154 sizeof(struct vfc_regs), vfcstr);
155 dev->which_io = sdev->reg_addrs[0].which_io;
156 dev->phys_regs = (struct vfc_regs *) sdev->reg_addrs[0].phys_addr;
157 if (dev->regs == NULL)
158 return -EIO;
159
160 printk("vfc%d: registers mapped at phys_addr: 0x%lx\n virt_addr: 0x%lx\n",
161 instance,(unsigned long)sdev->reg_addrs[0].phys_addr,(unsigned long)dev->regs);
162
163 if (init_vfc_devstruct(dev, instance))
164 return -EINVAL;
165 if (init_vfc_hw(dev))
166 return -EIO;
167
168 devfs_mk_cdev(MKDEV(VFC_MAJOR, instance),
169 S_IFCHR | S_IRUSR | S_IWUSR,
170 "vfc/%d", instance);
171 return 0;
172}
173
174
175struct vfc_dev *vfc_get_dev_ptr(int instance)
176{
177 return vfc_dev_lst[instance];
178}
179
180static DEFINE_SPINLOCK(vfc_dev_lock);
181
182static int vfc_open(struct inode *inode, struct file *file)
183{
184 struct vfc_dev *dev;
185
186 spin_lock(&vfc_dev_lock);
187 dev = vfc_get_dev_ptr(iminor(inode));
188 if (dev == NULL) {
189 spin_unlock(&vfc_dev_lock);
190 return -ENODEV;
191 }
192 if (dev->busy) {
193 spin_unlock(&vfc_dev_lock);
194 return -EBUSY;
195 }
196
197 dev->busy = 1;
198 spin_unlock(&vfc_dev_lock);
199
200 vfc_lock_device(dev);
201
202 vfc_csr_init(dev);
203 vfc_pcf8584_init(dev);
204 vfc_init_i2c_bus(dev);
205 vfc_saa9051_init(dev);
206 vfc_memptr_reset(dev);
207 vfc_captstat_reset(dev);
208
209 vfc_unlock_device(dev);
210 return 0;
211}
212
213static int vfc_release(struct inode *inode,struct file *file)
214{
215 struct vfc_dev *dev;
216
217 spin_lock(&vfc_dev_lock);
218 dev = vfc_get_dev_ptr(iminor(inode));
219 if (!dev || !dev->busy) {
220 spin_unlock(&vfc_dev_lock);
221 return -EINVAL;
222 }
223 dev->busy = 0;
224 spin_unlock(&vfc_dev_lock);
225 return 0;
226}
227
228static int vfc_debug(struct vfc_dev *dev, int cmd, void __user *argp)
229{
230 struct vfc_debug_inout inout;
231 unsigned char *buffer;
232
233 if (!capable(CAP_SYS_ADMIN))
234 return -EPERM;
235
236 switch(cmd) {
237 case VFC_I2C_SEND:
238 if(copy_from_user(&inout, argp, sizeof(inout)))
239 return -EFAULT;
240
241 buffer = kmalloc(inout.len, GFP_KERNEL);
242 if (buffer == NULL)
243 return -ENOMEM;
244
245 if(copy_from_user(buffer, inout.buffer, inout.len)) {
246 kfree(buffer);
247 return -EFAULT;
248 }
249
250
251 vfc_lock_device(dev);
252 inout.ret=
253 vfc_i2c_sendbuf(dev,inout.addr & 0xff,
254 buffer,inout.len);
255
256 if (copy_to_user(argp,&inout,sizeof(inout))) {
257 kfree(buffer);
258 return -EFAULT;
259 }
260 vfc_unlock_device(dev);
261
262 break;
263 case VFC_I2C_RECV:
264 if (copy_from_user(&inout, argp, sizeof(inout)))
265 return -EFAULT;
266
267 buffer = kmalloc(inout.len, GFP_KERNEL);
268 if (buffer == NULL)
269 return -ENOMEM;
270
271 memset(buffer,0,inout.len);
272 vfc_lock_device(dev);
273 inout.ret=
274 vfc_i2c_recvbuf(dev,inout.addr & 0xff
275 ,buffer,inout.len);
276 vfc_unlock_device(dev);
277
278 if (copy_to_user(inout.buffer, buffer, inout.len)) {
279 kfree(buffer);
280 return -EFAULT;
281 }
282 if (copy_to_user(argp,&inout,sizeof(inout))) {
283 kfree(buffer);
284 return -EFAULT;
285 }
286 kfree(buffer);
287 break;
288 default:
289 return -EINVAL;
290 };
291
292 return 0;
293}
294
295int vfc_capture_start(struct vfc_dev *dev)
296{
297 vfc_captstat_reset(dev);
298 dev->control_reg = sbus_readl(&dev->regs->control);
299 if((dev->control_reg & VFC_STATUS_CAPTURE)) {
300 printk(KERN_ERR "vfc%d: vfc capture status not reset\n",
301 dev->instance);
302 return -EIO;
303 }
304
305 vfc_lock_device(dev);
306 dev->control_reg &= ~VFC_CONTROL_CAPTURE;
307 sbus_writel(dev->control_reg, &dev->regs->control);
308 dev->control_reg |= VFC_CONTROL_CAPTURE;
309 sbus_writel(dev->control_reg, &dev->regs->control);
310 dev->control_reg &= ~VFC_CONTROL_CAPTURE;
311 sbus_writel(dev->control_reg, &dev->regs->control);
312 vfc_unlock_device(dev);
313
314 return 0;
315}
316
317int vfc_capture_poll(struct vfc_dev *dev)
318{
319 int timeout = 1000;
320
321 while (!timeout--) {
322 if (dev->regs->control & VFC_STATUS_CAPTURE)
323 break;
324 vfc_i2c_delay_no_busy(dev, 100);
325 }
326 if(!timeout) {
327 printk(KERN_WARNING "vfc%d: capture timed out\n",
328 dev->instance);
329 return -ETIMEDOUT;
330 }
331 return 0;
332}
333
334
335
336static int vfc_set_control_ioctl(struct inode *inode, struct file *file,
337 struct vfc_dev *dev, unsigned long arg)
338{
339 int setcmd, ret = 0;
340
341 if (copy_from_user(&setcmd,(void __user *)arg,sizeof(unsigned int)))
342 return -EFAULT;
343
344 VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCSCTRL) arg=0x%x\n",
345 dev->instance,setcmd));
346
347 switch(setcmd) {
348 case MEMPRST:
349 vfc_lock_device(dev);
350 vfc_memptr_reset(dev);
351 vfc_unlock_device(dev);
352 ret=0;
353 break;
354 case CAPTRCMD:
355 vfc_capture_start(dev);
356 vfc_capture_poll(dev);
357 break;
358 case DIAGMODE:
359 if(capable(CAP_SYS_ADMIN)) {
360 vfc_lock_device(dev);
361 dev->control_reg |= VFC_CONTROL_DIAGMODE;
362 sbus_writel(dev->control_reg, &dev->regs->control);
363 vfc_unlock_device(dev);
364 ret = 0;
365 } else {
366 ret = -EPERM;
367 }
368 break;
369 case NORMMODE:
370 vfc_lock_device(dev);
371 dev->control_reg &= ~VFC_CONTROL_DIAGMODE;
372 sbus_writel(dev->control_reg, &dev->regs->control);
373 vfc_unlock_device(dev);
374 ret = 0;
375 break;
376 case CAPTRSTR:
377 vfc_capture_start(dev);
378 ret = 0;
379 break;
380 case CAPTRWAIT:
381 vfc_capture_poll(dev);
382 ret = 0;
383 break;
384 default:
385 ret = -EINVAL;
386 break;
387 };
388
389 return ret;
390}
391
392
393int vfc_port_change_ioctl(struct inode *inode, struct file *file,
394 struct vfc_dev *dev, unsigned long arg)
395{
396 int ret = 0;
397 int cmd;
398
399 if(copy_from_user(&cmd, (void __user *)arg, sizeof(unsigned int))) {
400 VFC_IOCTL_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to "
401 "vfc_port_change_ioctl\n",
402 dev->instance));
403 return -EFAULT;
404 }
405
406 VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCPORTCHG) arg=0x%x\n",
407 dev->instance, cmd));
408
409 switch(cmd) {
410 case 1:
411 case 2:
412 VFC_SAA9051_SA(dev,VFC_SAA9051_HSY_START) = 0x72;
413 VFC_SAA9051_SA(dev,VFC_SAA9051_HSY_STOP) = 0x52;
414 VFC_SAA9051_SA(dev,VFC_SAA9051_HC_START) = 0x36;
415 VFC_SAA9051_SA(dev,VFC_SAA9051_HC_STOP) = 0x18;
416 VFC_SAA9051_SA(dev,VFC_SAA9051_HORIZ_PEAK) = VFC_SAA9051_BP2;
417 VFC_SAA9051_SA(dev,VFC_SAA9051_C3) = VFC_SAA9051_CT | VFC_SAA9051_SS3;
418 VFC_SAA9051_SA(dev,VFC_SAA9051_SECAM_DELAY) = 0x3e;
419 break;
420 case 3:
421 VFC_SAA9051_SA(dev,VFC_SAA9051_HSY_START) = 0x3a;
422 VFC_SAA9051_SA(dev,VFC_SAA9051_HSY_STOP) = 0x17;
423 VFC_SAA9051_SA(dev,VFC_SAA9051_HC_START) = 0xfa;
424 VFC_SAA9051_SA(dev,VFC_SAA9051_HC_STOP) = 0xde;
425 VFC_SAA9051_SA(dev,VFC_SAA9051_HORIZ_PEAK) =
426 VFC_SAA9051_BY | VFC_SAA9051_PF | VFC_SAA9051_BP2;
427 VFC_SAA9051_SA(dev,VFC_SAA9051_C3) = VFC_SAA9051_YC;
428 VFC_SAA9051_SA(dev,VFC_SAA9051_SECAM_DELAY) = 0;
429 VFC_SAA9051_SA(dev,VFC_SAA9051_C2) &=
430 ~(VFC_SAA9051_SS0 | VFC_SAA9051_SS1);
431 break;
432 default:
433 ret = -EINVAL;
434 return ret;
435 break;
436 }
437
438 switch(cmd) {
439 case 1:
440 VFC_SAA9051_SA(dev,VFC_SAA9051_C2) |=
441 (VFC_SAA9051_SS0 | VFC_SAA9051_SS1);
442 break;
443 case 2:
444 VFC_SAA9051_SA(dev,VFC_SAA9051_C2) &=
445 ~(VFC_SAA9051_SS0 | VFC_SAA9051_SS1);
446 VFC_SAA9051_SA(dev,VFC_SAA9051_C2) |= VFC_SAA9051_SS0;
447 break;
448 case 3:
449 break;
450 default:
451 ret = -EINVAL;
452 return ret;
453 break;
454 }
455 VFC_SAA9051_SA(dev,VFC_SAA9051_C3) &= ~(VFC_SAA9051_SS2);
456 ret=vfc_update_saa9051(dev);
457 udelay(500);
458 VFC_SAA9051_SA(dev,VFC_SAA9051_C3) |= (VFC_SAA9051_SS2);
459 ret=vfc_update_saa9051(dev);
460 return ret;
461}
462
463int vfc_set_video_ioctl(struct inode *inode, struct file *file,
464 struct vfc_dev *dev, unsigned long arg)
465{
466 int ret = 0;
467 int cmd;
468
469 if(copy_from_user(&cmd, (void __user *)arg, sizeof(unsigned int))) {
470 VFC_IOCTL_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to "
471 "vfc_set_video_ioctl\n",
472 dev->instance));
473 return ret;
474 }
475
476 VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCSVID) arg=0x%x\n",
477 dev->instance, cmd));
478 switch(cmd) {
479 case STD_NTSC:
480 VFC_SAA9051_SA(dev,VFC_SAA9051_C1) &= ~VFC_SAA9051_ALT;
481 VFC_SAA9051_SA(dev,VFC_SAA9051_C1) |= VFC_SAA9051_YPN |
482 VFC_SAA9051_CCFR0 | VFC_SAA9051_CCFR1 | VFC_SAA9051_FS;
483 ret = vfc_update_saa9051(dev);
484 break;
485 case STD_PAL:
486 VFC_SAA9051_SA(dev,VFC_SAA9051_C1) &= ~(VFC_SAA9051_YPN |
487 VFC_SAA9051_CCFR1 |
488 VFC_SAA9051_CCFR0 |
489 VFC_SAA9051_FS);
490 VFC_SAA9051_SA(dev,VFC_SAA9051_C1) |= VFC_SAA9051_ALT;
491 ret = vfc_update_saa9051(dev);
492 break;
493
494 case COLOR_ON:
495 VFC_SAA9051_SA(dev,VFC_SAA9051_C1) |= VFC_SAA9051_CO;
496 VFC_SAA9051_SA(dev,VFC_SAA9051_HORIZ_PEAK) &=
497 ~(VFC_SAA9051_BY | VFC_SAA9051_PF);
498 ret = vfc_update_saa9051(dev);
499 break;
500 case MONO:
501 VFC_SAA9051_SA(dev,VFC_SAA9051_C1) &= ~(VFC_SAA9051_CO);
502 VFC_SAA9051_SA(dev,VFC_SAA9051_HORIZ_PEAK) |=
503 (VFC_SAA9051_BY | VFC_SAA9051_PF);
504 ret = vfc_update_saa9051(dev);
505 break;
506 default:
507 ret = -EINVAL;
508 break;
509 };
510
511 return ret;
512}
513
514int vfc_get_video_ioctl(struct inode *inode, struct file *file,
515 struct vfc_dev *dev, unsigned long arg)
516{
517 int ret = 0;
518 unsigned int status = NO_LOCK;
519 unsigned char buf[1];
520
521 if(vfc_i2c_recvbuf(dev, VFC_SAA9051_ADDR, buf, 1)) {
522 printk(KERN_ERR "vfc%d: Unable to get status\n",
523 dev->instance);
524 return -EIO;
525 }
526
527 if(buf[0] & VFC_SAA9051_HLOCK) {
528 status = NO_LOCK;
529 } else if(buf[0] & VFC_SAA9051_FD) {
530 if(buf[0] & VFC_SAA9051_CD)
531 status = NTSC_COLOR;
532 else
533 status = NTSC_NOCOLOR;
534 } else {
535 if(buf[0] & VFC_SAA9051_CD)
536 status = PAL_COLOR;
537 else
538 status = PAL_NOCOLOR;
539 }
540 VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCGVID) returning status 0x%x; "
541 "buf[0]=%x\n", dev->instance, status, buf[0]));
542
543 if (copy_to_user((void __user *)arg,&status,sizeof(unsigned int))) {
544 VFC_IOCTL_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to "
545 "vfc_get_video_ioctl\n",
546 dev->instance));
547 return ret;
548 }
549 return ret;
550}
551
552static int vfc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
553 unsigned long arg)
554{
555 int ret = 0;
556 unsigned int tmp;
557 struct vfc_dev *dev;
558 void __user *argp = (void __user *)arg;
559
560 dev = vfc_get_dev_ptr(iminor(inode));
561 if(dev == NULL)
562 return -ENODEV;
563
564 switch(cmd & 0x0000ffff) {
565 case VFCGCTRL:
566#if 0
567 VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCGCTRL)\n", dev->instance));
568#endif
569 tmp = sbus_readl(&dev->regs->control);
570 if(copy_to_user(argp, &tmp, sizeof(unsigned int))) {
571 ret = -EFAULT;
572 break;
573 }
574 ret = 0;
575 break;
576 case VFCSCTRL:
577 ret = vfc_set_control_ioctl(inode, file, dev, arg);
578 break;
579 case VFCGVID:
580 ret = vfc_get_video_ioctl(inode, file, dev, arg);
581 break;
582 case VFCSVID:
583 ret = vfc_set_video_ioctl(inode, file, dev, arg);
584 break;
585 case VFCHUE:
586 VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCHUE)\n", dev->instance));
587 if(copy_from_user(&tmp,argp,sizeof(unsigned int))) {
588 VFC_IOCTL_DEBUG_PRINTK(("vfc%d: User passed bogus pointer "
589 "to IOCTL(VFCHUE)", dev->instance));
590 ret = -EFAULT;
591 } else {
592 VFC_SAA9051_SA(dev,VFC_SAA9051_HUE) = tmp;
593 vfc_update_saa9051(dev);
594 ret = 0;
595 }
596 break;
597 case VFCPORTCHG:
598 ret = vfc_port_change_ioctl(inode, file, dev, arg);
599 break;
600 case VFCRDINFO:
601 ret = -EINVAL;
602 VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCRDINFO)\n", dev->instance));
603 break;
604 default:
605 ret = vfc_debug(vfc_get_dev_ptr(iminor(inode)), cmd, argp);
606 break;
607 };
608
609 return ret;
610}
611
612static int vfc_mmap(struct file *file, struct vm_area_struct *vma)
613{
614 unsigned int map_size, ret, map_offset;
615 struct vfc_dev *dev;
616
617 dev = vfc_get_dev_ptr(iminor(file->f_dentry->d_inode));
618 if(dev == NULL)
619 return -ENODEV;
620
621 map_size = vma->vm_end - vma->vm_start;
622 if(map_size > sizeof(struct vfc_regs))
623 map_size = sizeof(struct vfc_regs);
624
625 vma->vm_flags |=
626 (VM_SHM | VM_LOCKED | VM_IO | VM_MAYREAD | VM_MAYWRITE | VM_MAYSHARE);
627 map_offset = (unsigned int) (long)dev->phys_regs;
628 ret = io_remap_pfn_range(vma, vma->vm_start,
629 MK_IOSPACE_PFN(dev->which_io,
630 map_offset >> PAGE_SHIFT),
631 map_size, vma->vm_page_prot);
632
633 if(ret)
634 return -EAGAIN;
635
636 return 0;
637}
638
639
640static struct file_operations vfc_fops = {
641 .owner = THIS_MODULE,
642 .llseek = no_llseek,
643 .ioctl = vfc_ioctl,
644 .mmap = vfc_mmap,
645 .open = vfc_open,
646 .release = vfc_release,
647};
648
649static int vfc_probe(void)
650{
651 struct sbus_bus *sbus;
652 struct sbus_dev *sdev = NULL;
653 int ret;
654 int instance = 0, cards = 0;
655
656 for_all_sbusdev(sdev, sbus) {
657 if (strcmp(sdev->prom_name, "vfc") == 0) {
658 cards++;
659 continue;
660 }
661 }
662
663 if (!cards)
664 return -ENODEV;
665
666 vfc_dev_lst = (struct vfc_dev **)kmalloc(sizeof(struct vfc_dev *) *
667 (cards+1),
668 GFP_KERNEL);
669 if (vfc_dev_lst == NULL)
670 return -ENOMEM;
671 memset(vfc_dev_lst, 0, sizeof(struct vfc_dev *) * (cards + 1));
672 vfc_dev_lst[cards] = NULL;
673
674 ret = register_chrdev(VFC_MAJOR, vfcstr, &vfc_fops);
675 if(ret) {
676 printk(KERN_ERR "Unable to get major number %d\n", VFC_MAJOR);
677 kfree(vfc_dev_lst);
678 return -EIO;
679 }
680 devfs_mk_dir("vfc");
681 instance = 0;
682 for_all_sbusdev(sdev, sbus) {
683 if (strcmp(sdev->prom_name, "vfc") == 0) {
684 vfc_dev_lst[instance]=(struct vfc_dev *)
685 kmalloc(sizeof(struct vfc_dev), GFP_KERNEL);
686 if (vfc_dev_lst[instance] == NULL)
687 return -ENOMEM;
688 ret = init_vfc_device(sdev,
689 vfc_dev_lst[instance],
690 instance);
691 if(ret) {
692 printk(KERN_ERR "Unable to initialize"
693 " vfc%d device\n",
694 instance);
695 } else {
696 }
697
698 instance++;
699 continue;
700 }
701 }
702
703 return 0;
704}
705
706#ifdef MODULE
707int init_module(void)
708#else
709int vfc_init(void)
710#endif
711{
712 return vfc_probe();
713}
714
715#ifdef MODULE
716static void deinit_vfc_device(struct vfc_dev *dev)
717{
718 if(dev == NULL)
719 return;
720 devfs_remove("vfc/%d", dev->instance);
721 sbus_iounmap((unsigned long)dev->regs, sizeof(struct vfc_regs));
722 kfree(dev);
723}
724
725void cleanup_module(void)
726{
727 struct vfc_dev **devp;
728
729 unregister_chrdev(VFC_MAJOR,vfcstr);
730
731 for (devp = vfc_dev_lst; *devp; devp++)
732 deinit_vfc_device(*devp);
733
734 devfs_remove("vfc");
735 kfree(vfc_dev_lst);
736 return;
737}
738#endif
739
740MODULE_LICENSE("GPL");
741