linux/arch/sh/boards/mach-landisk/gio.c
<<
>>
Prefs
   1/*
   2 * arch/sh/boards/landisk/gio.c - driver for landisk
   3 *
   4 * This driver will also support the I-O DATA Device, Inc. LANDISK Board.
   5 * LANDISK and USL-5P Button, LED and GIO driver drive function.
   6 *
   7 *   Copylight (C) 2006 kogiidena
   8 *   Copylight (C) 2002 Atom Create Engineering Co., Ltd. *
   9 *
  10 * This file is subject to the terms and conditions of the GNU General Public
  11 * License.  See the file "COPYING" in the main directory of this archive
  12 * for more details.
  13 *
  14 */
  15#include <linux/module.h>
  16#include <linux/init.h>
  17#include <linux/kdev_t.h>
  18#include <linux/cdev.h>
  19#include <linux/fs.h>
  20#include <asm/io.h>
  21#include <linux/uaccess.h>
  22#include <mach-landisk/mach/gio.h>
  23#include <mach-landisk/mach/iodata_landisk.h>
  24
  25#define DEVCOUNT                4
  26#define GIO_MINOR               2       /* GIO minor no. */
  27
  28static dev_t dev;
  29static struct cdev *cdev_p;
  30static int openCnt;
  31
  32static int gio_open(struct inode *inode, struct file *filp)
  33{
  34        int minor;
  35        int ret = -ENOENT;
  36
  37        preempt_disable();
  38        minor = MINOR(inode->i_rdev);
  39        if (minor < DEVCOUNT) {
  40                if (openCnt > 0) {
  41                        ret = -EALREADY;
  42                } else {
  43                        openCnt++;
  44                        ret = 0;
  45                }
  46        }
  47        preempt_enable();
  48        return ret;
  49}
  50
  51static int gio_close(struct inode *inode, struct file *filp)
  52{
  53        int minor;
  54
  55        minor = MINOR(inode->i_rdev);
  56        if (minor < DEVCOUNT) {
  57                openCnt--;
  58        }
  59        return 0;
  60}
  61
  62static long gio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
  63{
  64        unsigned int data;
  65        static unsigned int addr = 0;
  66
  67        if (cmd & 0x01) {       /* write */
  68                if (copy_from_user(&data, (int *)arg, sizeof(int))) {
  69                        return -EFAULT;
  70                }
  71        }
  72
  73        switch (cmd) {
  74        case GIODRV_IOCSGIOSETADDR:     /* address set */
  75                addr = data;
  76                break;
  77
  78        case GIODRV_IOCSGIODATA1:       /* write byte */
  79                __raw_writeb((unsigned char)(0x0ff & data), addr);
  80                break;
  81
  82        case GIODRV_IOCSGIODATA2:       /* write word */
  83                if (addr & 0x01) {
  84                        return -EFAULT;
  85                }
  86                __raw_writew((unsigned short int)(0x0ffff & data), addr);
  87                break;
  88
  89        case GIODRV_IOCSGIODATA4:       /* write long */
  90                if (addr & 0x03) {
  91                        return -EFAULT;
  92                }
  93                __raw_writel(data, addr);
  94                break;
  95
  96        case GIODRV_IOCGGIODATA1:       /* read byte */
  97                data = __raw_readb(addr);
  98                break;
  99
 100        case GIODRV_IOCGGIODATA2:       /* read word */
 101                if (addr & 0x01) {
 102                        return -EFAULT;
 103                }
 104                data = __raw_readw(addr);
 105                break;
 106
 107        case GIODRV_IOCGGIODATA4:       /* read long */
 108                if (addr & 0x03) {
 109                        return -EFAULT;
 110                }
 111                data = __raw_readl(addr);
 112                break;
 113        default:
 114                return -EFAULT;
 115                break;
 116        }
 117
 118        if ((cmd & 0x01) == 0) {        /* read */
 119                if (copy_to_user((int *)arg, &data, sizeof(int))) {
 120                        return -EFAULT;
 121                }
 122        }
 123        return 0;
 124}
 125
 126static const struct file_operations gio_fops = {
 127        .owner = THIS_MODULE,
 128        .open = gio_open,       /* open */
 129        .release = gio_close,   /* release */
 130        .unlocked_ioctl = gio_ioctl,
 131        .llseek = noop_llseek,
 132};
 133
 134static int __init gio_init(void)
 135{
 136        int error;
 137
 138        printk(KERN_INFO "gio: driver initialized\n");
 139
 140        openCnt = 0;
 141
 142        if ((error = alloc_chrdev_region(&dev, 0, DEVCOUNT, "gio")) < 0) {
 143                printk(KERN_ERR
 144                       "gio: Couldn't alloc_chrdev_region, error=%d\n",
 145                       error);
 146                return 1;
 147        }
 148
 149        cdev_p = cdev_alloc();
 150        cdev_p->ops = &gio_fops;
 151        error = cdev_add(cdev_p, dev, DEVCOUNT);
 152        if (error) {
 153                printk(KERN_ERR
 154                       "gio: Couldn't cdev_add, error=%d\n", error);
 155                return 1;
 156        }
 157
 158        return 0;
 159}
 160
 161static void __exit gio_exit(void)
 162{
 163        cdev_del(cdev_p);
 164        unregister_chrdev_region(dev, DEVCOUNT);
 165}
 166
 167module_init(gio_init);
 168module_exit(gio_exit);
 169
 170MODULE_LICENSE("GPL");
 171