X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fchar%2Fscx200_gpio.c;fp=drivers%2Fchar%2Fscx200_gpio.c;h=664a6e97eb1a8012475625af6383825a3d885e20;hb=64ba3f394c830ec48a1c31b53dcae312c56f1604;hp=b956c7babd18a8a4933d6a99e74bd86ceb63c62d;hpb=be1e6109ac94a859551f8e1774eb9a8469fe055c;p=linux-2.6.git diff --git a/drivers/char/scx200_gpio.c b/drivers/char/scx200_gpio.c index b956c7bab..664a6e97e 100644 --- a/drivers/char/scx200_gpio.c +++ b/drivers/char/scx200_gpio.c @@ -1,57 +1,96 @@ -/* linux/drivers/char/scx200_gpio.c +/* linux/drivers/char/scx200_gpio.c National Semiconductor SCx200 GPIO driver. Allows a user space process to play with the GPIO pins. Copyright (c) 2001,2002 Christer Weinigel */ -#include +#include #include #include #include #include #include -#include #include #include -#include -#include - #include -#include - -#define DRVNAME "scx200_gpio" -static struct platform_device *pdev; +#define NAME "scx200_gpio" MODULE_AUTHOR("Christer Weinigel "); -MODULE_DESCRIPTION("NatSemi/AMD SCx200 GPIO Pin Driver"); +MODULE_DESCRIPTION("NatSemi SCx200 GPIO Pin Driver"); MODULE_LICENSE("GPL"); static int major = 0; /* default to dynamic major */ module_param(major, int, 0); MODULE_PARM_DESC(major, "Major device number"); -#define MAX_PINS 32 /* 64 later, when known ok */ +static ssize_t scx200_gpio_write(struct file *file, const char __user *data, + size_t len, loff_t *ppos) +{ + unsigned m = iminor(file->f_dentry->d_inode); + size_t i; + + for (i = 0; i < len; ++i) { + char c; + if (get_user(c, data+i)) + return -EFAULT; + switch (c) + { + case '0': + scx200_gpio_set(m, 0); + break; + case '1': + scx200_gpio_set(m, 1); + break; + case 'O': + printk(KERN_INFO NAME ": GPIO%d output enabled\n", m); + scx200_gpio_configure(m, ~1, 1); + break; + case 'o': + printk(KERN_INFO NAME ": GPIO%d output disabled\n", m); + scx200_gpio_configure(m, ~1, 0); + break; + case 'T': + printk(KERN_INFO NAME ": GPIO%d output is push pull\n", m); + scx200_gpio_configure(m, ~2, 2); + break; + case 't': + printk(KERN_INFO NAME ": GPIO%d output is open drain\n", m); + scx200_gpio_configure(m, ~2, 0); + break; + case 'P': + printk(KERN_INFO NAME ": GPIO%d pull up enabled\n", m); + scx200_gpio_configure(m, ~4, 4); + break; + case 'p': + printk(KERN_INFO NAME ": GPIO%d pull up disabled\n", m); + scx200_gpio_configure(m, ~4, 0); + break; + } + } -struct nsc_gpio_ops scx200_gpio_ops = { - .owner = THIS_MODULE, - .gpio_config = scx200_gpio_configure, - .gpio_dump = nsc_gpio_dump, - .gpio_get = scx200_gpio_get, - .gpio_set = scx200_gpio_set, - .gpio_change = scx200_gpio_change, - .gpio_current = scx200_gpio_current -}; -EXPORT_SYMBOL(scx200_gpio_ops); + return len; +} + +static ssize_t scx200_gpio_read(struct file *file, char __user *buf, + size_t len, loff_t *ppos) +{ + unsigned m = iminor(file->f_dentry->d_inode); + int value; + + value = scx200_gpio_get(m); + if (put_user(value ? '1' : '0', buf)) + return -EFAULT; + + return 1; +} static int scx200_gpio_open(struct inode *inode, struct file *file) { unsigned m = iminor(inode); - file->private_data = &scx200_gpio_ops; - - if (m >= MAX_PINS) + if (m > 63) return -EINVAL; return nonseekable_open(inode, file); } @@ -61,71 +100,50 @@ static int scx200_gpio_release(struct inode *inode, struct file *file) return 0; } -static const struct file_operations scx200_gpio_fileops = { + +static struct file_operations scx200_gpio_fops = { .owner = THIS_MODULE, - .write = nsc_gpio_write, - .read = nsc_gpio_read, + .write = scx200_gpio_write, + .read = scx200_gpio_read, .open = scx200_gpio_open, .release = scx200_gpio_release, }; -struct cdev scx200_gpio_cdev; /* use 1 cdev for all pins */ - static int __init scx200_gpio_init(void) { - int rc; - dev_t devid; + int r; + + printk(KERN_DEBUG NAME ": NatSemi SCx200 GPIO Driver\n"); if (!scx200_gpio_present()) { - printk(KERN_ERR DRVNAME ": no SCx200 gpio present\n"); + printk(KERN_ERR NAME ": no SCx200 gpio pins available\n"); return -ENODEV; } - /* support dev_dbg() with pdev->dev */ - pdev = platform_device_alloc(DRVNAME, 0); - if (!pdev) - return -ENOMEM; - - rc = platform_device_add(pdev); - if (rc) - goto undo_malloc; - - /* nsc_gpio uses dev_dbg(), so needs this */ - scx200_gpio_ops.dev = &pdev->dev; - - if (major) { - devid = MKDEV(major, 0); - rc = register_chrdev_region(devid, MAX_PINS, "scx200_gpio"); - } else { - rc = alloc_chrdev_region(&devid, 0, MAX_PINS, "scx200_gpio"); - major = MAJOR(devid); + r = register_chrdev(major, NAME, &scx200_gpio_fops); + if (r < 0) { + printk(KERN_ERR NAME ": unable to register character device\n"); + return r; } - if (rc < 0) { - dev_err(&pdev->dev, "SCx200 chrdev_region err: %d\n", rc); - goto undo_platform_device_add; + if (!major) { + major = r; + printk(KERN_DEBUG NAME ": got dynamic major %d\n", major); } - cdev_init(&scx200_gpio_cdev, &scx200_gpio_fileops); - cdev_add(&scx200_gpio_cdev, devid, MAX_PINS); - - return 0; /* succeed */ - -undo_platform_device_add: - platform_device_del(pdev); -undo_malloc: - platform_device_put(pdev); - - return rc; + return 0; } static void __exit scx200_gpio_cleanup(void) { - cdev_del(&scx200_gpio_cdev); - /* cdev_put(&scx200_gpio_cdev); */ - - unregister_chrdev_region(MKDEV(major, 0), MAX_PINS); - platform_device_unregister(pdev); + unregister_chrdev(major, NAME); } module_init(scx200_gpio_init); module_exit(scx200_gpio_cleanup); + +/* + Local variables: + compile-command: "make -k -C ../.. SUBDIRS=drivers/char modules" + c-basic-offset: 8 + End: +*/