File: /usr/src/linux/drivers/sbus/char/vfc_dev.c

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