]> arthur.barton.de Git - ppin.git/blob - ppin.c
Initialize PIN states on module loading
[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 void
51 set_pins(void)
52 {
53         if (parport_claim_or_block(parport_pins) < 0) {
54                 printk(KERN_ERR
55                        "Could not claim the " PPIN_DEV " parallel port device\n");
56                 return;
57         }
58         parport_write_data(parport_pins->port, pin_state);
59         parport_release(parport_pins);
60 }
61
62 static void
63 ppin_attach(struct parport *port)
64 {
65         if (available_ports == 0) {
66                 parport_pins =
67                     parport_register_device(port, PPIN_DEV, NULL, NULL,
68                                             NULL, 0, 0);
69
70                 if (parport_pins == 0)
71                         printk(KERN_ERR
72                                "Could not associate " PPIN_DEV " device with parallel port #%d\n",
73                                available_ports + 1);
74                 else
75                         printk(KERN_INFO
76                                "Associated " PPIN_DEV " device with parallel port #%d\n",
77                                available_ports + 1);
78         }
79
80         available_ports++;
81 }
82
83 static void
84 ppin_detach(struct parport *port)
85 {
86         if (available_ports == 1)
87                 parport_pins = 0;
88
89         available_ports--;
90 }
91
92 static struct parport_driver ppin_driver = {
93         PPIN_NAME,
94         ppin_attach,
95         ppin_detach,
96         {NULL}
97 };
98
99 static ssize_t
100 ppin_read(struct file *file, char *buf, size_t count, loff_t * ppos)
101 {
102         int i;
103         char *tmp = buf;
104         char status[79];
105
106         if (buffer_empty)
107                 return 0;
108
109         sprintf(&status[0],
110                 "PIN #:   0   1   2   3   4   5   6   7\n"
111                 "State: %s %s %s %s %s %s %s %s\n",
112                 pin_state & (1 << 0) ? " on" : "off",
113                 pin_state & (1 << 1) ? " on" : "off",
114                 pin_state & (1 << 2) ? " on" : "off",
115                 pin_state & (1 << 3) ? " on" : "off",
116                 pin_state & (1 << 4) ? " on" : "off",
117                 pin_state & (1 << 5) ? " on" : "off",
118                 pin_state & (1 << 6) ? " on" : "off",
119                 pin_state & (1 << 7) ? " on" : "off");
120
121         for (i = 0; count-- > 0 && i < 78; ++i, ++tmp)
122                 put_user(status[i], tmp);
123
124         if (tmp - buf > 77)
125                 buffer_empty = 1;
126
127         return (tmp - buf);
128 }
129
130 static ssize_t
131 ppin_write(struct file *file, const char *buf, size_t count, loff_t * ppos)
132 {
133         int i;
134         char *tmp_1, *tmp_2;
135
136         i = simple_strtol(buf, &tmp_2, 0);
137
138         if (i < 0 || i > 7) {
139                 printk(KERN_WARNING "" PPIN_DEV ": No such PIN: %d\n", i);
140                 return count;
141         }
142         tmp_2++;
143
144         tmp_1 = strstr(tmp_2, OFF_COMMAND);
145         if (tmp_1 != NULL)
146                 pin_state &= ~(1 << i);
147         else {
148                 tmp_1 = strstr(tmp_2, ON_COMMAND);
149                 if (tmp_1 != NULL)
150                         pin_state |= (1 << i);
151         }
152
153         if (!tmp_1) {
154                 printk(KERN_WARNING "" PPIN_DEV": No such state\n");
155                 return count;
156         }
157
158         set_pins();
159         return count;
160 }
161
162 static int
163 ppin_open(struct inode *inode, struct file *file)
164 {
165         if (ppin_open_cnt)
166                 return -EBUSY;
167         else
168                 ppin_open_cnt = 1;
169
170         buffer_empty = 0;
171         return 0;
172 }
173
174 static int
175 ppin_release(struct inode *inode, struct file *file)
176 {
177         ppin_open_cnt = 0;
178         return 0;
179 }
180
181 static struct file_operations ppin_fops = {
182         owner:THIS_MODULE,
183         read:ppin_read,
184         write:ppin_write,
185         open:ppin_open,
186         release:ppin_release,
187 };
188
189 static struct miscdevice ppin_dev = {
190         PPIN_MINOR,
191         PPIN_DEV,
192         &ppin_fops
193 };
194
195 int __init
196 ppin_init(void)
197 {
198         if (parport_register_driver(&ppin_driver) != 0) {
199                 printk(KERN_ERR "Could not register the " PPIN_DEV " driver.\n");
200                 return -EIO;
201         }
202
203         if (misc_register(&ppin_dev) != 0) {
204                 printk(KERN_ERR
205                        "Could not register the misc device " PPIN_DEV " (%d, %d)\n",
206                        PPIN_MAJOR, PPIN_MINOR);
207                 return -EIO;
208         }
209
210         printk(KERN_INFO "" PPIN_NAME " driver v%s loaded\n", PPIN_VERSION);
211
212         set_pins();
213         return 0;
214 }
215
216 static void __exit
217 ppin_cleanup(void)
218 {
219         if (misc_deregister(&ppin_dev) != 0)
220                 printk(KERN_ERR
221                        "Cound not deregister the misc device " PPIN_DEV " (%d, %d)\n",
222                        PPIN_MAJOR, PPIN_MINOR);
223
224         parport_unregister_device(parport_pins);
225         parport_unregister_driver(&ppin_driver);
226
227         printk(KERN_INFO "" PPIN_NAME " driver v%s unloaded\n", PPIN_VERSION);
228 }
229
230 module_init(ppin_init);
231 module_exit(ppin_cleanup);