/* * ht2020.c * * Copyright (C) 2001 Atmark Techno, Inc. */ #include #include #include #include #include #include #include "ht2020.h" #undef outb #define outb(v,p) __raw_writeb(v,__io(ISAIO8_BASE+p)) #undef inb #define inb(p) __raw_readb(__io(ISAIO8_BASE+p)) #define MAX_HT2020 16 static unsigned int ht2020_portlist[MAX_HT2020] __initdata = { 0x100, 0x104, 0x108, 0x10c, 0x110, 0x114, 0x118, 0x11c, 0x120, 0x124, 0x128, 0x12c, 0x130, 0x134, 0x138, 0x13c, }; static int ht2020_foundlist[MAX_HT2020] __initdata = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; #define CHRDEV "ht2020" #define VERSION CHRDEV ": HT2020 driver, (C) 2001 Atmark Techno, Inc." static ssize_t ht2020_read (struct file *file, char *buf, size_t count, loff_t *ppos) { unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev); int devno = minor / 4; int portno = minor % 4; char tmp; if (MAX_HT2020 <= devno || 3 <= portno) { return -ENODEV; } if (!ht2020_foundlist[devno]) { return -ENODEV; } tmp = inb (ht2020_portlist[devno] + portno); if (put_user (tmp, buf)) { return -EFAULT; } return 1; } static ssize_t ht2020_write (struct file *file, const char *buf, size_t count, loff_t *ppos) { unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev); int devno = minor / 4; int portno = minor % 4; if (MAX_HT2020 <= devno || 3 <= portno) { return -ENODEV; } if (!ht2020_foundlist[devno]) { return -ENODEV; } outb (buf[0], ht2020_portlist[devno] + portno); return 1; } static struct file_operations ht2020_fops = { owner: THIS_MODULE, read: ht2020_read, write: ht2020_write, }; static int ht2020_probe (unsigned int port) { if (inb (port)) { return -1; } if (inb (port + 1)) { return -1; } if (inb (port + 2)) { return -1; } if (inb (port + 3) != 0xff) { return -1; } return 0; } #ifdef MODULE static int io[MAX_HT2020]; MODULE_PARM(io, "1-" __MODULE_STRING(MAX_HT2020) "i"); #endif int __init ht2020_init (void) { int i, count = 0; #ifdef MODULE int j; #endif #ifdef MODULE if (!io[0]) { printk (KERN_WARNING CHRDEV ": Append io=0xNNN.\n"); return -ENXIO; } #endif for (i = 0; i < MAX_HT2020; i++) { #ifdef MODULE for (j = 0; j < MAX_HT2020; j++) { if (io[j] == ht2020_portlist[i]) { break; } } if (j >= MAX_HT2020) { continue; } #endif if (!ht2020_probe (ht2020_portlist[i])) { ht2020_foundlist[i] = 1; count++; } } if (!count) { printk (KERN_WARNING CHRDEV ": HT2020 is not found.\n"); return -EIO; } for (i = 0; i < MAX_HT2020; i++) { if (ht2020_foundlist[i]) { if (!request_region (ISAIO8_BASE + ht2020_portlist[i], 4, CHRDEV)) { #ifdef MODULE printk (KERN_WARNING CHRDEV ": I/O port 0x%x-0x%x is not free.\n", ISAIO8_BASE + ht2020_portlist[i], ISAIO8_BASE + ht2020_portlist[i] + 3); #endif ht2020_foundlist[i] = 0; count--; if (!count) { for (i--; i >= 0; i--) { if (ht2020_foundlist[i]) { release_region (ISAIO16_BASE + ht2020_portlist[i], 4); release_region (ISAIO8_BASE + ht2020_portlist[i], 4); } } return -EIO; } continue; } if (!request_region (ISAIO16_BASE + ht2020_portlist[i], 4, CHRDEV)) { #ifdef MODULE printk (KERN_WARNING CHRDEV ": I/O port 0x%x-0x%x is not free.\n", ISAIO16_BASE + ht2020_portlist[i], ISAIO16_BASE + ht2020_portlist[i] + 3); #endif release_region (ISAIO8_BASE + ht2020_portlist[i], 4); ht2020_foundlist[i] = 0; count--; if (!count) { for (i--; i >= 0; i--) { if (ht2020_foundlist[i]) { release_region (ISAIO16_BASE + ht2020_portlist[i], 4); release_region (ISAIO8_BASE + ht2020_portlist[i], 4); } } return -EIO; } } } } if (register_chrdev (HT2020_MAJOR, CHRDEV, &ht2020_fops)) { printk (KERN_WARNING CHRDEV ": Unable to get major %d.\n", HT2020_MAJOR); for (i = MAX_HT2020 - 1; i >= 0; i--) { if (ht2020_foundlist[i]) { release_region (ISAIO16_BASE + ht2020_portlist[i], 4); release_region (ISAIO8_BASE + ht2020_portlist[i], 4); } } return -EIO; } printk (KERN_INFO VERSION "\n"); return 0; } void __exit ht2020_cleanup (void) { int i; unregister_chrdev (HT2020_MAJOR, CHRDEV); for (i = MAX_HT2020 - 1; i >= 0; i--) { if (ht2020_foundlist[i]) { release_region (ISAIO16_BASE + ht2020_portlist[i], 4); release_region (ISAIO8_BASE + ht2020_portlist[i], 4); } } } module_init (ht2020_init); module_exit (ht2020_cleanup);