linux/drivers/char/scx200_gpio.c
<<
>>
Prefs
   1/* linux/drivers/char/scx200_gpio.c
   2
   3   National Semiconductor SCx200 GPIO driver.  Allows a user space
   4   process to play with the GPIO pins.
   5
   6   Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com> */
   7
   8#include <linux/device.h>
   9#include <linux/fs.h>
  10#include <linux/module.h>
  11#include <linux/errno.h>
  12#include <linux/kernel.h>
  13#include <linux/init.h>
  14#include <linux/platform_device.h>
  15#include <linux/uaccess.h>
  16#include <asm/io.h>
  17
  18#include <linux/types.h>
  19#include <linux/cdev.h>
  20
  21#include <linux/scx200_gpio.h>
  22#include <linux/nsc_gpio.h>
  23
  24#define DRVNAME "scx200_gpio"
  25
  26static struct platform_device *pdev;
  27
  28MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
  29MODULE_DESCRIPTION("NatSemi/AMD SCx200 GPIO Pin Driver");
  30MODULE_LICENSE("GPL");
  31
  32static int major = 0;           /* default to dynamic major */
  33module_param(major, int, 0);
  34MODULE_PARM_DESC(major, "Major device number");
  35
  36#define MAX_PINS 32             /* 64 later, when known ok */
  37
  38struct nsc_gpio_ops scx200_gpio_ops = {
  39        .owner          = THIS_MODULE,
  40        .gpio_config    = scx200_gpio_configure,
  41        .gpio_dump      = nsc_gpio_dump,
  42        .gpio_get       = scx200_gpio_get,
  43        .gpio_set       = scx200_gpio_set,
  44        .gpio_change    = scx200_gpio_change,
  45        .gpio_current   = scx200_gpio_current
  46};
  47EXPORT_SYMBOL_GPL(scx200_gpio_ops);
  48
  49static int scx200_gpio_open(struct inode *inode, struct file *file)
  50{
  51        unsigned m = iminor(inode);
  52        file->private_data = &scx200_gpio_ops;
  53
  54        if (m >= MAX_PINS)
  55                return -EINVAL;
  56        return nonseekable_open(inode, file);
  57}
  58
  59static int scx200_gpio_release(struct inode *inode, struct file *file)
  60{
  61        return 0;
  62}
  63
  64static const struct file_operations scx200_gpio_fileops = {
  65        .owner   = THIS_MODULE,
  66        .write   = nsc_gpio_write,
  67        .read    = nsc_gpio_read,
  68        .open    = scx200_gpio_open,
  69        .release = scx200_gpio_release,
  70        .llseek  = no_llseek,
  71};
  72
  73static struct cdev scx200_gpio_cdev;  /* use 1 cdev for all pins */
  74
  75static int __init scx200_gpio_init(void)
  76{
  77        int rc;
  78        dev_t devid;
  79
  80        if (!scx200_gpio_present()) {
  81                printk(KERN_ERR DRVNAME ": no SCx200 gpio present\n");
  82                return -ENODEV;
  83        }
  84
  85        /* support dev_dbg() with pdev->dev */
  86        pdev = platform_device_alloc(DRVNAME, 0);
  87        if (!pdev)
  88                return -ENOMEM;
  89
  90        rc = platform_device_add(pdev);
  91        if (rc)
  92                goto undo_malloc;
  93
  94        /* nsc_gpio uses dev_dbg(), so needs this */
  95        scx200_gpio_ops.dev = &pdev->dev;
  96
  97        if (major) {
  98                devid = MKDEV(major, 0);
  99                rc = register_chrdev_region(devid, MAX_PINS, "scx200_gpio");
 100        } else {
 101                rc = alloc_chrdev_region(&devid, 0, MAX_PINS, "scx200_gpio");
 102                major = MAJOR(devid);
 103        }
 104        if (rc < 0) {
 105                dev_err(&pdev->dev, "SCx200 chrdev_region err: %d\n", rc);
 106                goto undo_platform_device_add;
 107        }
 108
 109        cdev_init(&scx200_gpio_cdev, &scx200_gpio_fileops);
 110        cdev_add(&scx200_gpio_cdev, devid, MAX_PINS);
 111
 112        return 0; /* succeed */
 113
 114undo_platform_device_add:
 115        platform_device_del(pdev);
 116undo_malloc:
 117        platform_device_put(pdev);
 118
 119        return rc;
 120}
 121
 122static void __exit scx200_gpio_cleanup(void)
 123{
 124        cdev_del(&scx200_gpio_cdev);
 125        /* cdev_put(&scx200_gpio_cdev); */
 126
 127        unregister_chrdev_region(MKDEV(major, 0), MAX_PINS);
 128        platform_device_unregister(pdev);
 129}
 130
 131module_init(scx200_gpio_init);
 132module_exit(scx200_gpio_cleanup);
 133