Root/target/linux/generic-2.6/files/drivers/char/gpio_dev.c

1/*
2 * character device wrapper for generic gpio layer
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA
17 *
18 * Feedback, Bugs... blogic@openwrt.org
19 *
20 */
21
22#include <linux/module.h>
23#include <linux/errno.h>
24#include <linux/init.h>
25#include <asm/uaccess.h>
26#include <asm/io.h>
27#include <asm/gpio.h>
28#include <asm/atomic.h>
29#include <linux/init.h>
30#include <linux/genhd.h>
31#include <linux/device.h>
32#include <linux/platform_device.h>
33#include <linux/gpio_dev.h>
34
35#define DRVNAME "gpiodev"
36#define DEVNAME "gpio"
37
38static int dev_major;
39static unsigned int gpio_access_mask;
40static struct class *gpiodev_class;
41
42/* Counter is 1, if the device is not opened and zero (or less) if opened. */
43static atomic_t gpio_open_cnt = ATOMIC_INIT(1);
44
45static int
46gpio_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg)
47{
48    int retval = 0;
49
50    if (((1 << arg) & gpio_access_mask) != (1 << arg))
51    {
52        retval = -EINVAL;
53        goto out;
54    }
55
56    switch (cmd)
57    {
58    case GPIO_GET:
59        retval = gpio_get_value(arg);
60        break;
61
62    case GPIO_SET:
63        gpio_set_value(arg, 1);
64        break;
65
66    case GPIO_CLEAR:
67        gpio_set_value(arg, 0);
68        break;
69
70    case GPIO_DIR_IN:
71        gpio_direction_input(arg);
72        break;
73
74    case GPIO_DIR_OUT:
75        gpio_direction_output(arg, 0);
76        break;
77
78    default:
79        retval = -EINVAL;
80        break;
81    }
82
83out:
84    return retval;
85}
86
87static int
88gpio_open(struct inode *inode, struct file *file)
89{
90    int result = 0;
91    unsigned int dev_minor = MINOR(inode->i_rdev);
92
93    if (dev_minor != 0)
94    {
95        printk(KERN_ERR DRVNAME ": trying to access unknown minor device -> %d\n", dev_minor);
96        result = -ENODEV;
97        goto out;
98    }
99
100    /* FIXME: We should really allow multiple applications to open the device
101     * at the same time, as long as the apps access different IO pins.
102     * The generic gpio-registration functions can be used for that.
103     * Two new IOCTLs have to be introduced for that. Need to check userspace
104     * compatibility first. --mb */
105    if (!atomic_dec_and_test(&gpio_open_cnt)) {
106        atomic_inc(&gpio_open_cnt);
107        printk(KERN_ERR DRVNAME ": Device with minor ID %d already in use\n", dev_minor);
108        result = -EBUSY;
109        goto out;
110    }
111
112out:
113    return result;
114}
115
116static int
117gpio_close(struct inode * inode, struct file * file)
118{
119    smp_mb__before_atomic_inc();
120    atomic_inc(&gpio_open_cnt);
121
122    return 0;
123}
124
125struct file_operations gpio_fops = {
126    ioctl: gpio_ioctl,
127    open: gpio_open,
128    release: gpio_close
129};
130
131static int
132gpio_probe(struct platform_device *dev)
133{
134    int result = 0;
135
136    dev_major = register_chrdev(0, DEVNAME, &gpio_fops);
137    if (!dev_major)
138    {
139        printk(KERN_ERR DRVNAME ": Error whilst opening %s \n", DEVNAME);
140        result = -ENODEV;
141        goto out;
142    }
143
144    gpiodev_class = class_create(THIS_MODULE, DRVNAME);
145    device_create(gpiodev_class, NULL, MKDEV(dev_major, 0), dev, DEVNAME);
146
147    printk(KERN_INFO DRVNAME ": gpio device registered with major %d\n", dev_major);
148
149    if (dev->num_resources != 1)
150    {
151        printk(KERN_ERR DRVNAME ": device may only have 1 resource\n");
152        result = -ENODEV;
153        goto out;
154    }
155
156    gpio_access_mask = dev->resource[0].start;
157
158    printk(KERN_INFO DRVNAME ": gpio platform device registered with access mask %08X\n", gpio_access_mask);
159out:
160    return result;
161}
162
163static int
164gpio_remove(struct platform_device *dev)
165{
166    unregister_chrdev(dev_major, DEVNAME);
167    return 0;
168}
169
170static struct
171platform_driver gpio_driver = {
172    .probe = gpio_probe,
173    .remove = gpio_remove,
174    .driver = {
175        .name = "GPIODEV",
176        .owner = THIS_MODULE,
177    },
178};
179
180static int __init
181gpio_mod_init(void)
182{
183    int ret = platform_driver_register(&gpio_driver);
184    if (ret)
185        printk(KERN_INFO DRVNAME ": Error registering platfom driver!");
186
187    return ret;
188}
189
190static void __exit
191gpio_mod_exit(void)
192{
193    platform_driver_unregister(&gpio_driver);
194}
195
196module_init (gpio_mod_init);
197module_exit (gpio_mod_exit);
198
199MODULE_LICENSE("GPL");
200MODULE_AUTHOR("John Crispin / OpenWrt");
201MODULE_DESCRIPTION("Character device for for generic gpio api");
202

Archive Download this file



interactive