]> arthur.barton.de Git - ppin.git/blob - ppin.c
Parallel Port PIN driver for Linux 2.6: ppin
[ppin.git] / ppin.c
1 /*
2  *              Parallel Port PIN driver for Linux 2.6: ppin
3  *
4  *              This kernel module will register the /dev/ppin (10, 151)
5  *              device which controls up to eight PINs through the first
6  *              parallel port.
7  *
8  *              Controlling the PINs is as easy as 'echo Num State >/dev/ppin',
9  *              where Num is 0 to 7 and State is one of 'on', 'off'.
10  *              For example: "echo 3 on >/dev/ppin" switches the 3rd PIN on.
11  *
12  *              You can read the status of the PINs with 'cat /dev/ppin'.
13  *
14  *              This program is free software; you can redistribute it and/or
15  *              modify it under the terms of the GNU General Public License
16  *              as published by the Free Software Foundation; either version
17  *              2 of the License, or (at your option) any later version.
18  *
19  * Authors:     Alexander Barton, <alex@barton.de> (for Linux 2.6, 2009)
20  *
21  *              This work is heavily(!) based on the "devled" driver written by
22  *              Konstantinos Natsakis, <cyfex@mail.com> for Linux 2.2/2.4.
23  */
24
25 #include <linux/module.h>
26 #include <linux/miscdevice.h>
27 #include <linux/parport.h>
28 #include <asm/uaccess.h>
29
30 #define PPIN_NAME       "ppin"
31 #define PPIN_VERSION    "0.1"
32
33 #define PPIN_DEV        "ppin"
34 #define PPIN_MAJOR      MISC_MAJOR
35 #define PPIN_MINOR      151
36
37 #define ON_COMMAND      "on"
38 #define OFF_COMMAND     "off"
39
40 static char pin_state = 0;
41 static int buffer_empty = 0;
42 static int ppin_open_cnt = 0;
43 static int available_ports = 0;
44 static struct pardevice *parport_pins = 0;
45
46 MODULE_AUTHOR("Alexander Barton, alex@barton.de");
47 MODULE_DESCRIPTION("Driver for controlling the state of parallel port PINs");
48 MODULE_LICENSE("GPL");
49
50 static void
51 ppin_attach(struct parport *port)
52 {
53         if (available_ports == 0) {
54                 parport_pins =
55                     parport_register_device(port, PPIN_DEV, NULL, NULL,
56                                             NULL, 0, 0);
57
58                 if (parport_pins == 0)
59                         printk(KERN_ERR
60                                "Could not associate " PPIN_DEV " device with parallel port #%d\n",
61                                available_ports + 1);
62                 else
63                         printk(KERN_INFO
64                                "Associated " PPIN_DEV " device with parallel port #%d\n",
65                                available_ports + 1);
66         }
67
68         available_ports++;
69 }
70
71 static void
72 ppin_detach(struct parport *port)
73 {
74         if (available_ports == 1)
75                 parport_pins = 0;
76
77         available_ports--;
78 }
79
80 static struct parport_driver ppin_driver = {
81         PPIN_NAME,
82         ppin_attach,
83         ppin_detach,
84         NULL
85 };
86
87 static ssize_t
88 ppin_read(struct file *file, char *buf, size_t count, loff_t * ppos)
89 {
90         int i;
91         char *tmp = buf;
92         char status[79];
93
94         if (buffer_empty)
95                 return 0;
96
97         sprintf(&status[0],
98                 "PIN #:   0   1   2   3   4   5   6   7\n"
99                 "State: %s %s %s %s %s %s %s %s\n",
100                 pin_state & (1 << 0) ? " on" : "off",
101                 pin_state & (1 << 1) ? " on" : "off",
102                 pin_state & (1 << 2) ? " on" : "off",
103                 pin_state & (1 << 3) ? " on" : "off",
104                 pin_state & (1 << 4) ? " on" : "off",
105                 pin_state & (1 << 5) ? " on" : "off",
106                 pin_state & (1 << 6) ? " on" : "off",
107                 pin_state & (1 << 7) ? " on" : "off");
108
109         for (i = 0; count-- > 0 && i < 78; ++i, ++tmp)
110                 put_user(status[i], tmp);
111
112         if (tmp - buf > 77)
113                 buffer_empty = 1;
114
115         return (tmp - buf);
116 }
117
118 static ssize_t
119 ppin_write(struct file *file, const char *buf, size_t count, loff_t * ppos)
120 {
121         int i;
122         char *tmp_1, *tmp_2;
123
124         i = simple_strtol(buf, &tmp_2, 0);
125
126         if (i < 0 || i > 7) {
127                 printk(KERN_WARNING "" PPIN_DEV ": No such PIN: %d\n", i);
128                 return count;
129         }
130         tmp_2++;
131
132         tmp_1 = strstr(tmp_2, OFF_COMMAND);
133         if (tmp_1 != NULL)
134                 pin_state &= ~(1 << i);
135         else {
136                 tmp_1 = strstr(tmp_2, ON_COMMAND);
137                 if (tmp_1 != NULL)
138                         pin_state |= (1 << i);
139         }
140
141         if (!tmp_1) {
142                 printk(KERN_WARNING "" PPIN_DEV": No such state\n");
143                 return count;
144         }
145
146         if (parport_claim_or_block(parport_pins) < 0) {
147                 printk(KERN_ERR
148                        "Could not claim the " PPIN_DEV " parallel port device\n");
149                 return 0;
150         }
151
152         parport_write_data(parport_pins->port, pin_state);
153
154         parport_release(parport_pins);
155         return count;
156 }
157
158 static int
159 ppin_open(struct inode *inode, struct file *file)
160 {
161         if (ppin_open_cnt)
162                 return -EBUSY;
163         else
164                 ppin_open_cnt = 1;
165
166         buffer_empty = 0;
167         return 0;
168 }
169
170 static int
171 ppin_release(struct inode *inode, struct file *file)
172 {
173         ppin_open_cnt = 0;
174         return 0;
175 }
176
177 static struct file_operations ppin_fops = {
178         owner:THIS_MODULE,
179         read:ppin_read,
180         write:ppin_write,
181         open:ppin_open,
182         release:ppin_release,
183 };
184
185 static struct miscdevice ppin_dev = {
186         PPIN_MINOR,
187         PPIN_DEV,
188         &ppin_fops
189 };
190
191 int __init
192 ppin_init(void)
193 {
194         if (parport_register_driver(&ppin_driver) != 0) {
195                 printk(KERN_ERR "Could not register the " PPIN_DEV " driver.\n");
196                 return -EIO;
197         }
198
199         if (misc_register(&ppin_dev) != 0) {
200                 printk(KERN_ERR
201                        "Could not register the misc device " PPIN_DEV " (%d, %d)\n",
202                        PPIN_MAJOR, PPIN_MINOR);
203                 return -EIO;
204         }
205
206         printk(KERN_INFO "" PPIN_NAME " driver v%s loaded\n", PPIN_VERSION);
207         return 0;
208 }
209
210 static void __exit
211 ppin_cleanup(void)
212 {
213         if (misc_deregister(&ppin_dev) != 0)
214                 printk(KERN_ERR
215                        "Cound not deregister the misc device " PPIN_DEV " (%d, %d)\n",
216                        PPIN_MAJOR, PPIN_MINOR);
217
218         parport_unregister_device(parport_pins);
219         parport_unregister_driver(&ppin_driver);
220
221         printk(KERN_INFO "" PPIN_NAME " driver v%s unloaded\n", PPIN_VERSION);
222 }
223
224 module_init(ppin_init);
225 module_exit(ppin_cleanup);