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