Path: blob/master/arch/sh/boards/mach-landisk/gio.c
15126 views
/*1* arch/sh/boards/landisk/gio.c - driver for landisk2*3* This driver will also support the I-O DATA Device, Inc. LANDISK Board.4* LANDISK and USL-5P Button, LED and GIO driver drive function.5*6* Copylight (C) 2006 kogiidena7* Copylight (C) 2002 Atom Create Engineering Co., Ltd. *8*9* This file is subject to the terms and conditions of the GNU General Public10* License. See the file "COPYING" in the main directory of this archive11* for more details.12*13*/14#include <linux/module.h>15#include <linux/init.h>16#include <linux/kdev_t.h>17#include <linux/cdev.h>18#include <linux/fs.h>19#include <asm/io.h>20#include <asm/uaccess.h>21#include <mach-landisk/mach/gio.h>22#include <mach-landisk/mach/iodata_landisk.h>2324#define DEVCOUNT 425#define GIO_MINOR 2 /* GIO minor no. */2627static dev_t dev;28static struct cdev *cdev_p;29static int openCnt;3031static int gio_open(struct inode *inode, struct file *filp)32{33int minor;34int ret = -ENOENT;3536preempt_disable();37minor = MINOR(inode->i_rdev);38if (minor < DEVCOUNT) {39if (openCnt > 0) {40ret = -EALREADY;41} else {42openCnt++;43ret = 0;44}45}46preempt_enable();47return ret;48}4950static int gio_close(struct inode *inode, struct file *filp)51{52int minor;5354minor = MINOR(inode->i_rdev);55if (minor < DEVCOUNT) {56openCnt--;57}58return 0;59}6061static long gio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)62{63unsigned int data;64static unsigned int addr = 0;6566if (cmd & 0x01) { /* write */67if (copy_from_user(&data, (int *)arg, sizeof(int))) {68return -EFAULT;69}70}7172switch (cmd) {73case GIODRV_IOCSGIOSETADDR: /* address set */74addr = data;75break;7677case GIODRV_IOCSGIODATA1: /* write byte */78__raw_writeb((unsigned char)(0x0ff & data), addr);79break;8081case GIODRV_IOCSGIODATA2: /* write word */82if (addr & 0x01) {83return -EFAULT;84}85__raw_writew((unsigned short int)(0x0ffff & data), addr);86break;8788case GIODRV_IOCSGIODATA4: /* write long */89if (addr & 0x03) {90return -EFAULT;91}92__raw_writel(data, addr);93break;9495case GIODRV_IOCGGIODATA1: /* read byte */96data = __raw_readb(addr);97break;9899case GIODRV_IOCGGIODATA2: /* read word */100if (addr & 0x01) {101return -EFAULT;102}103data = __raw_readw(addr);104break;105106case GIODRV_IOCGGIODATA4: /* read long */107if (addr & 0x03) {108return -EFAULT;109}110data = __raw_readl(addr);111break;112default:113return -EFAULT;114break;115}116117if ((cmd & 0x01) == 0) { /* read */118if (copy_to_user((int *)arg, &data, sizeof(int))) {119return -EFAULT;120}121}122return 0;123}124125static const struct file_operations gio_fops = {126.owner = THIS_MODULE,127.open = gio_open, /* open */128.release = gio_close, /* release */129.unlocked_ioctl = gio_ioctl,130.llseek = noop_llseek,131};132133static int __init gio_init(void)134{135int error;136137printk(KERN_INFO "gio: driver initialized\n");138139openCnt = 0;140141if ((error = alloc_chrdev_region(&dev, 0, DEVCOUNT, "gio")) < 0) {142printk(KERN_ERR143"gio: Couldn't alloc_chrdev_region, error=%d\n",144error);145return 1;146}147148cdev_p = cdev_alloc();149cdev_p->ops = &gio_fops;150error = cdev_add(cdev_p, dev, DEVCOUNT);151if (error) {152printk(KERN_ERR153"gio: Couldn't cdev_add, error=%d\n", error);154return 1;155}156157return 0;158}159160static void __exit gio_exit(void)161{162cdev_del(cdev_p);163unregister_chrdev_region(dev, DEVCOUNT);164}165166module_init(gio_init);167module_exit(gio_exit);168169MODULE_LICENSE("GPL");170171172