Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v2.6.13 741 lines 17 kB view raw
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#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; 140 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