+= driver
[raggedstone] / dhwk / driver / dhwk.c
1 #include <linux/init.h>
2 #include <linux/module.h>
3 #include <linux/pci.h>
4 #include <linux/types.h>
5 #include <linux/fs.h>
6 #include <asm/uaccess.h>
7 #include <linux/poll.h>
8 #include <linux/sched.h>
9 #include <linux/interrupt.h>
10 #include <asm/delay.h>
11
12 static const char *version = "$Id: dhwk.c,v 1.1 2007-03-10 22:35:54 sithglan Exp $";
13 static unsigned long ioaddr;
14 static unsigned long locks;
15
16 #define BUFFER_SIZE 32768
17
18 static unsigned char send_buffer[BUFFER_SIZE];
19 static unsigned char recv_buffer[BUFFER_SIZE];
20
21 static wait_queue_head_t send_wq;
22 static wait_queue_head_t receive_wq;
23 static u8 irq; /* FIXME: Get it from the pci struct */
24 static int my_dhwk_dev_id;
25
26 MODULE_LICENSE("Dual BSD/GPL");
27
28 #define MODULE_NAME "dhwk"
29 #define DHWK_MAJOR 42
30
31 #define INTERRUPTS_PLEASE 1
32
33 #define SDR (ioaddr + 0)
34 #define RDR (ioaddr + 2)
35 #define ISR (ioaddr + 4)
36 #define CTR (ioaddr + 6)
37
38 static int
39 dhwk_open(struct inode *inode, struct file *f)
40 {
41 if (iminor(inode) != 0) {
42 return -ENXIO;
43 }
44
45 dhwk_open_again:
46
47 if (( (f->f_flags & O_ACCMODE) == O_RDONLY
48 || (f->f_flags & O_ACCMODE) == O_RDWR)
49 && (locks & 0x01)) {
50 if (f->f_flags & O_NONBLOCK) {
51 return -EBUSY;
52
53 } else {
54 schedule();
55 goto dhwk_open_again;
56 }
57 }
58
59 if (( (f->f_flags & O_ACCMODE) == O_WRONLY
60 || (f->f_flags & O_ACCMODE) == O_RDWR)
61 && (locks & 0x02)) {
62 if (f->f_flags & O_NONBLOCK) {
63 return -EBUSY;
64
65 } else {
66 schedule();
67 goto dhwk_open_again;
68 }
69 }
70
71 if (( (f->f_flags & O_ACCMODE) == O_RDONLY
72 || (f->f_flags & O_ACCMODE) == O_RDWR)) {
73 test_and_set_bit(0, &locks);
74 }
75
76 if (( (f->f_flags & O_ACCMODE) == O_WRONLY
77 || (f->f_flags & O_ACCMODE) == O_RDWR)) {
78 test_and_set_bit(1, &locks);
79 }
80
81 return 0;
82 }
83
84 static int
85 dhwk_release(struct inode *i, struct file *f)
86 {
87
88 if (( (f->f_flags & O_ACCMODE) == O_RDONLY
89 || (f->f_flags & O_ACCMODE) == O_RDWR)) {
90 locks &= ~ 0x01;
91 }
92
93 if (( (f->f_flags & O_ACCMODE) == O_WRONLY
94 || (f->f_flags & O_ACCMODE) == O_RDWR)) {
95 locks &= ~ 0x02;
96 }
97
98 return 0;
99 }
100
101 static ssize_t
102 dhwk_read(struct file *f, char __user *u, size_t size, loff_t *offset)
103 {
104 size_t count = 0;
105 short word = 0;
106 short status = 0;
107 int next_status = 0;
108
109 if (! access_ok(VERIFY_WRITE, u, size)) {
110 return -EFAULT;
111 }
112
113 while (count < size) {
114
115 dhwk_read_again:
116
117 if (next_status == 0) {
118 status = inw(ISR);
119 if (! (status & 0x0200)) {
120 /* Receive FIFO Empty */
121 if (f->f_flags & O_NONBLOCK) {
122 __copy_to_user(u + count - (count % BUFFER_SIZE),
123 recv_buffer, count % BUFFER_SIZE + 1);
124 return count;
125
126 } else {
127 #if INTERRUPTS_PLEASE
128 wait_event_interruptible(receive_wq, inw(ISR) & 0x0200);
129 if (signal_pending(current)) {
130 return -ERESTARTSYS;
131 }
132 #else
133 schedule();
134 #endif
135 goto dhwk_read_again;
136 }
137
138 } else if (! (status & 0x0400)) {
139 /* Receive FIFO Half Full */
140 next_status = 2048;
141 }
142
143 } else {
144 next_status--;
145 }
146
147 word = inw(RDR);
148 #if 0
149
150 if ((word & 0xFF) != 0xc3) {
151 short debug_enable = inw(ioaddr + 8);
152 printk(KERN_ALERT "dhwk: Fehler: 0x%08x\n", 0x00 | word);
153 }
154 #endif
155
156 recv_buffer[count % BUFFER_SIZE] = (unsigned char) word;
157
158 if (count % BUFFER_SIZE == (BUFFER_SIZE - 1)
159 || count == (size - 1)) {
160 __copy_to_user(u + count - (count % BUFFER_SIZE),
161 recv_buffer, count % BUFFER_SIZE + 1);
162 };
163
164 count++;
165 }
166
167 return count;
168 }
169
170 static ssize_t
171 dhwk_write(struct file *f, const char __user *u, size_t size, loff_t *offset)
172 {
173 size_t count = 0;
174 size_t grabbed = 0;
175 short status = 0;
176 int next_status = 0;
177
178 if (! access_ok(VERIFY_READ, u, size)) {
179 return -EFAULT;
180 }
181
182 while (count < size) {
183 if (grabbed <= count) {
184 __copy_from_user(send_buffer, u + count,
185 (size - count) < BUFFER_SIZE ? (size - count) : BUFFER_SIZE);
186 grabbed += (size - count) < BUFFER_SIZE ? (size - count) : BUFFER_SIZE;
187 }
188
189 dhwk_write_again:
190
191 if (next_status == 0) {
192 status = inw(ISR);
193 if (! (status & 0x8000)) {
194 /* Send FIFO FULL */
195 if (f->f_flags & O_NONBLOCK) {
196 return count;
197
198 } else {
199 #if INTERRUPTS_PLEASE
200 wait_event_interruptible(send_wq, inw(ISR) & 0x0800);
201 if (signal_pending(current)) {
202 return -ERESTARTSYS;
203 }
204 #else
205 schedule();
206 #endif
207 goto dhwk_write_again;
208 }
209
210 } else if (status & 0x4000) {
211 /* Send FIFO not HALF Full */
212 next_status = 2048;
213 }
214 } else {
215 next_status--;
216 }
217
218 outw(0x0000 | send_buffer[count % BUFFER_SIZE], SDR);
219 count++;
220 }
221
222 return count;
223 }
224
225 static unsigned int
226 dhwk_poll(struct file *f, struct poll_table_struct *pts)
227 {
228 unsigned int mask;
229 unsigned short reg;
230
231 dhwk_poll_again:
232 mask = 0;
233 reg = inw(ISR);
234
235 if (( (f->f_flags & O_ACCMODE) == O_RDONLY
236 || (f->f_flags & O_ACCMODE) == O_RDWR)) {
237 if (f->f_flags & O_NONBLOCK) {
238 if (reg & 0x0200) {
239 mask |= POLLIN | POLLRDNORM;
240
241 } else {
242 return -EAGAIN;
243 }
244
245 } else {
246 schedule();
247 goto dhwk_poll_again;
248 }
249 }
250
251 if (( (f->f_flags & O_ACCMODE) == O_WRONLY
252 || (f->f_flags & O_ACCMODE) == O_RDWR)) {
253 if ((f->f_flags & O_NONBLOCK)) {
254 /* If write is possible */
255 if (! (reg & 0x8000)) {
256 mask |= POLLOUT | POLLWRNORM;
257
258 } else {
259 return -EAGAIN;
260 }
261
262 } else {
263 schedule();
264 goto dhwk_poll_again;
265 }
266
267 }
268
269 return mask;
270 }
271
272 static int __devinit
273 dhwk_pci_init(struct pci_dev *pdev, const struct pci_device_id *ent)
274 {
275 int ret;
276
277 printk(KERN_ALERT "dhwk: Gruppe 2: %s\n", version);
278
279 ret = pci_enable_device(pdev);
280 if (ret) {
281 printk(KERN_ERR "dhwk: Could not enable pci device.\n");
282 pci_disable_device(pdev);
283 return 1;
284 }
285
286 ret = pci_request_regions(pdev, MODULE_NAME);
287 if (ret) {
288 printk(KERN_ERR "dhwk: Could not request regions.\n");
289 pci_disable_device(pdev);
290 return 1;
291 }
292
293 irq = pdev->irq;
294
295 ioaddr = pci_resource_start(pdev, 0);
296 printk(KERN_ALERT "dhwk: ioaddr at 0x%08x irq 0x%02x\n", (unsigned int) ioaddr, irq);
297
298 /* Pull Reset (twice) */
299 outw(0x0100, CTR);
300 outw(0x0100, CTR);
301
302 udelay(10);
303
304 /* CLEAR WRONG STATUS */
305 ret = inw(ISR);
306 ret = inw(ISR);
307
308 /* Enable Sender and Receiver and all available Interrupts */
309 while ((inw(CTR) & 0x06FF) != 0x06FF) {
310 outw(0x06FF, CTR);
311 }
312 return 0;
313 }
314
315 static void __devexit
316 dhwk_pci_exit(struct pci_dev *pdev)
317 {
318 int ret;
319 outw(0x0000, CTR);
320 ret = inw(ISR); /* Get pending interrupts down */
321 ret = inw(ISR);
322 pci_release_regions(pdev);
323 pci_disable_device(pdev);
324 pci_set_drvdata(pdev, NULL);
325 printk(KERN_ALERT "dhwk: Gruppe 2: Module unloaded.\n");
326 }
327
328 static struct pci_device_id dhwk_pci_tbl[] = {
329 {0x2222, 0xaffe, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* FIXME */
330 #if 0
331 {0xbaff, 0xaffe, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* FIXME */
332 #endif
333 {0,},
334 };
335
336 static struct pci_driver dhwk_pci_driver = {
337 .name = MODULE_NAME,
338 .id_table = dhwk_pci_tbl,
339 .probe = dhwk_pci_init,
340 .remove = dhwk_pci_exit,
341 };
342
343 struct file_operations dhwk_fops = {
344 .owner = THIS_MODULE,
345 .read = dhwk_read,
346 .poll = dhwk_poll,
347 .write = dhwk_write,
348 .open = dhwk_open,
349 .release = dhwk_release,
350 };
351
352 static irqreturn_t
353 interrupt_handler(int irq_to_check, void *dev_id, struct pt_regs *regs)
354 {
355 register unsigned short status;
356 status = inw(ISR);
357
358 if (status & 0x0200) {
359 wake_up_interruptible(& receive_wq);
360 }
361
362 if (status & 0x8000) {
363 wake_up_interruptible(& send_wq);
364 }
365
366 if (irq_to_check == irq) {
367 return IRQ_HANDLED;
368
369 } else {
370 return IRQ_NONE;
371 }
372 }
373
374 static int
375 dhwk_init(void)
376 {
377 int ret;
378
379 ret = pci_module_init(& dhwk_pci_driver);
380 if (ret) {
381 return -EIO;
382 }
383
384 ret = register_chrdev(DHWK_MAJOR, MODULE_NAME, & dhwk_fops);
385 if (ret) {
386 printk (KERN_ALERT "dhwk: unable to get major %d\n", DHWK_MAJOR);
387 pci_unregister_driver(& dhwk_pci_driver);
388 return -EIO;
389 }
390
391 init_waitqueue_head(& send_wq);
392 init_waitqueue_head(& receive_wq);
393
394 #if INTERRUPTS_PLEASE
395 #if 0
396 ret = request_irq(irq, interrupt_handler, SA_INTERRUPT, "dhwk", &my_dhwk_dev_id);
397 #endif
398 ret = request_irq(irq, interrupt_handler, SA_SHIRQ, "dhwk", &my_dhwk_dev_id);
399 if (ret) {
400 printk (KERN_ALERT "dhwk: unable to register interrupt %d\n", irq);
401 pci_unregister_driver(& dhwk_pci_driver);
402 unregister_chrdev(DHWK_MAJOR, MODULE_NAME);
403 return -EIO;
404 }
405 #endif
406
407 return ret;
408 }
409
410 static void
411 dhwk_exit(void)
412 {
413 free_irq(irq, &my_dhwk_dev_id);
414 pci_unregister_driver(& dhwk_pci_driver);
415 unregister_chrdev(DHWK_MAJOR, MODULE_NAME);
416 }
417
418 module_init(dhwk_init);
419 module_exit(dhwk_exit);
Impressum, Datenschutz