This source file includes following definitions.
- lp_reset
- lp_char_polled
- lp_char_interrupt
- lp_interrupt
- lp_write_interrupt
- lp_write_polled
- lp_write
- lp_lseek
- lp_open
- lp_release
- lp_ioctl
- lp_probe
- lp_setup
- lp_init
- cleanup_module
1
2
3
4
5
6
7
8
9
10
11
12
13 #include <linux/module.h>
14
15 #include <linux/errno.h>
16 #include <linux/kernel.h>
17 #include <linux/major.h>
18 #include <linux/sched.h>
19 #include <linux/lp.h>
20 #include <linux/malloc.h>
21 #include <linux/ioport.h>
22 #include <linux/fcntl.h>
23 #include <linux/delay.h>
24
25 #include <asm/io.h>
26 #include <asm/segment.h>
27 #include <asm/system.h>
28
29
30
31
32
33
34
35 struct lp_struct lp_table[] = {
36 { 0x3bc, 0, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, 0, 0, 0, {0} },
37 { 0x378, 0, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, 0, 0, 0, {0} },
38 { 0x278, 0, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, 0, 0, 0, {0} },
39 };
40 #define LP_NO 3
41
42
43 #define LP_READY(minor, status) \
44 ((LP_F(minor) & LP_CAREFUL) ? _LP_CAREFUL_READY(status) : (status & LP_PBUSY))
45 #define LP_CAREFUL_READY(minor, status) \
46 ((LP_F(minor) & LP_CAREFUL) ? _LP_CAREFUL_READY(status) : 1)
47 #define _LP_CAREFUL_READY(status) \
48 (status & (LP_PBUSY|LP_POUTPA|LP_PSELECD|LP_PERRORP)) == \
49 (LP_PBUSY|LP_PSELECD|LP_PERRORP)
50
51
52
53
54
55
56
57 #undef LP_DEBUG
58
59 static int lp_reset(int minor)
60 {
61 outb_p(LP_PSELECP, LP_C(minor));
62 udelay(LP_DELAY);
63 outb_p(LP_PSELECP | LP_PINITP, LP_C(minor));
64 return LP_S(minor);
65 }
66
67 static inline int lp_char_polled(char lpchar, int minor)
68 {
69 int status, wait = 0;
70 unsigned long count = 0;
71 struct lp_stats *stats;
72
73 do {
74 status = LP_S(minor);
75 count ++;
76 if(need_resched)
77 schedule();
78 } while(!LP_READY(minor,status) && count < LP_CHAR(minor));
79
80 if (count == LP_CHAR(minor)) {
81 return 0;
82
83 }
84 outb_p(lpchar, LP_B(minor));
85 stats = &LP_STAT(minor);
86 stats->chars++;
87
88
89 while(wait != LP_WAIT(minor)) wait++;
90
91 outb_p(( LP_PSELECP | LP_PINITP | LP_PSTROBE ), ( LP_C( minor )));
92 while(wait) wait--;
93
94 outb_p(( LP_PSELECP | LP_PINITP ), ( LP_C( minor )));
95
96 if (count > stats->maxwait) {
97 #ifdef LP_DEBUG
98 printk(KERN_DEBUG "lp%d success after %d counts.\n",minor,count);
99 #endif
100 stats->maxwait = count;
101 }
102 count *= 256;
103 wait = (count > stats->meanwait)? count - stats->meanwait :
104 stats->meanwait - count;
105 stats->meanwait = (255*stats->meanwait + count + 128) / 256;
106 stats->mdev = ((127 * stats->mdev) + wait + 64) / 128;
107
108 return 1;
109 }
110
111 static inline int lp_char_interrupt(char lpchar, int minor)
112 {
113 int wait;
114 unsigned long count = 0;
115 unsigned char status;
116 struct lp_stats *stats;
117
118 do {
119 if ((status = LP_S(minor)) & LP_PBUSY) {
120 if (!LP_CAREFUL_READY(minor, status))
121 return 0;
122 outb_p(lpchar, LP_B(minor));
123 stats = &LP_STAT(minor);
124 stats->chars++;
125
126
127 wait = 0;
128 while(wait != LP_WAIT(minor)) wait++;
129
130 outb_p(( LP_PSELECP | LP_PINITP | LP_PSTROBE ), ( LP_C( minor )));
131 while(wait) wait--;
132
133 outb_p(( LP_PSELECP | LP_PINITP ), ( LP_C( minor )));
134
135 if (count) {
136 if (count > stats->maxwait)
137 stats->maxwait = count;
138 count *= 256;
139 wait = (count > stats->meanwait)? count - stats->meanwait :
140 stats->meanwait - count;
141 stats->meanwait = (255*stats->meanwait + count + 128) / 256;
142 stats->mdev = ((127 * stats->mdev) + wait + 64) / 128;
143 }
144 return 1;
145 }
146 } while (count++ < LP_CHAR(minor));
147
148 return 0;
149 }
150
151 static void lp_interrupt(int irq, void *dev_id, struct pt_regs *regs)
152 {
153 struct lp_struct *lp = &lp_table[0];
154
155 while (irq != lp->irq) {
156 if (++lp >= &lp_table[LP_NO])
157 return;
158 }
159
160 wake_up(&lp->lp_wait_q);
161 }
162
163 static inline int lp_write_interrupt(unsigned int minor, const char * buf, int count)
164 {
165 unsigned long copy_size;
166 unsigned long total_bytes_written = 0;
167 unsigned long bytes_written;
168 struct lp_struct *lp = &lp_table[minor];
169 unsigned char status;
170
171 do {
172 bytes_written = 0;
173 copy_size = (count <= LP_BUFFER_SIZE ? count : LP_BUFFER_SIZE);
174 memcpy_fromfs(lp->lp_buffer, buf, copy_size);
175
176 while (copy_size) {
177 if (lp_char_interrupt(lp->lp_buffer[bytes_written], minor)) {
178 --copy_size;
179 ++bytes_written;
180 lp_table[minor].runchars++;
181 } else {
182 int rc = total_bytes_written + bytes_written;
183 if (lp_table[minor].runchars > LP_STAT(minor).maxrun)
184 LP_STAT(minor).maxrun = lp_table[minor].runchars;
185 status = LP_S(minor);
186 if ((status & LP_POUTPA)) {
187 printk(KERN_INFO "lp%d out of paper\n", minor);
188 if (LP_F(minor) & LP_ABORT)
189 return rc?rc:-ENOSPC;
190 } else if (!(status & LP_PSELECD)) {
191 printk(KERN_INFO "lp%d off-line\n", minor);
192 if (LP_F(minor) & LP_ABORT)
193 return rc?rc:-EIO;
194 } else if (!(status & LP_PERRORP)) {
195 printk(KERN_ERR "lp%d printer error\n", minor);
196 if (LP_F(minor) & LP_ABORT)
197 return rc?rc:-EIO;
198 }
199 LP_STAT(minor).sleeps++;
200 cli();
201 outb_p((LP_PSELECP|LP_PINITP|LP_PINTEN), (LP_C(minor)));
202 status = LP_S(minor);
203 if ((!(status & LP_PACK) || (status & LP_PBUSY))
204 && LP_CAREFUL_READY(minor, status)) {
205 outb_p((LP_PSELECP|LP_PINITP), (LP_C(minor)));
206 sti();
207 continue;
208 }
209 lp_table[minor].runchars=0;
210 current->timeout = jiffies + LP_TIMEOUT_INTERRUPT;
211 interruptible_sleep_on(&lp->lp_wait_q);
212 outb_p((LP_PSELECP|LP_PINITP), (LP_C(minor)));
213 sti();
214 if (current->signal & ~current->blocked) {
215 if (total_bytes_written + bytes_written)
216 return total_bytes_written + bytes_written;
217 else
218 return -EINTR;
219 }
220 }
221 }
222
223 total_bytes_written += bytes_written;
224 buf += bytes_written;
225 count -= bytes_written;
226
227 } while (count > 0);
228
229 return total_bytes_written;
230 }
231
232 static inline int lp_write_polled(unsigned int minor, const char * buf, int count)
233 {
234 int retval,status;
235 char c;
236 const char *temp;
237
238 temp = buf;
239 while (count > 0) {
240 c = get_user(temp);
241 retval = lp_char_polled(c, minor);
242
243 if (retval) {
244 count--; temp++;
245 lp_table[minor].runchars++;
246 } else {
247 if (lp_table[minor].runchars > LP_STAT(minor).maxrun)
248 LP_STAT(minor).maxrun = lp_table[minor].runchars;
249 status = LP_S(minor);
250
251 if (status & LP_POUTPA) {
252 printk(KERN_INFO "lp%d out of paper\n", minor);
253 if(LP_F(minor) & LP_ABORT)
254 return temp-buf?temp-buf:-ENOSPC;
255 current->state = TASK_INTERRUPTIBLE;
256 current->timeout = jiffies + LP_TIMEOUT_POLLED;
257 schedule();
258 } else
259 if (!(status & LP_PSELECD)) {
260 printk(KERN_INFO "lp%d off-line\n", minor);
261 if(LP_F(minor) & LP_ABORT)
262 return temp-buf?temp-buf:-EIO;
263 current->state = TASK_INTERRUPTIBLE;
264 current->timeout = jiffies + LP_TIMEOUT_POLLED;
265 schedule();
266 } else
267
268 if (!(status & LP_PERRORP)) {
269 printk(KERN_ERR "lp%d reported invalid error status (on fire, eh?)\n", minor);
270 if(LP_F(minor) & LP_ABORT)
271 return temp-buf?temp-buf:-EIO;
272 current->state = TASK_INTERRUPTIBLE;
273 current->timeout = jiffies + LP_TIMEOUT_POLLED;
274 schedule();
275 }
276
277
278 if (current->signal & ~current->blocked) {
279 if (temp != buf)
280 return temp-buf;
281 else
282 return -EINTR;
283 }
284 LP_STAT(minor).sleeps++;
285 #ifdef LP_DEBUG
286 printk(KERN_DEBUG "lp%d sleeping at %d characters for %d jiffies\n",
287 minor,lp_table[minor].runchars, LP_TIME(minor));
288 #endif
289 lp_table[minor].runchars=0;
290 current->state = TASK_INTERRUPTIBLE;
291 current->timeout = jiffies + LP_TIME(minor);
292 schedule();
293 }
294 }
295 return temp-buf;
296 }
297
298 static int lp_write(struct inode * inode, struct file * file, const char * buf, int count)
299 {
300 unsigned int minor = MINOR(inode->i_rdev);
301
302 if (jiffies-lp_table[minor].lastcall > LP_TIME(minor))
303 lp_table[minor].runchars = 0;
304 lp_table[minor].lastcall = jiffies;
305
306 if (LP_IRQ(minor))
307 return lp_write_interrupt(minor, buf, count);
308 else
309 return lp_write_polled(minor, buf, count);
310 }
311
312 static int lp_lseek(struct inode * inode, struct file * file,
313 off_t offset, int origin)
314 {
315 return -ESPIPE;
316 }
317
318 static int lp_open(struct inode * inode, struct file * file)
319 {
320 unsigned int minor = MINOR(inode->i_rdev);
321 int ret;
322 unsigned int irq;
323
324 if (minor >= LP_NO)
325 return -ENODEV;
326 if ((LP_F(minor) & LP_EXIST) == 0)
327 return -ENODEV;
328 if (LP_F(minor) & LP_BUSY)
329 return -EBUSY;
330
331 MOD_INC_USE_COUNT;
332
333
334
335
336
337
338 if ((LP_F(minor) & LP_ABORTOPEN) && !(file->f_flags & O_NONBLOCK)) {
339 int status = LP_S(minor);
340 if (status & LP_POUTPA) {
341 printk(KERN_INFO "lp%d out of paper\n", minor);
342 MOD_DEC_USE_COUNT;
343 return -ENOSPC;
344 } else if (!(status & LP_PSELECD)) {
345 printk(KERN_INFO "lp%d off-line\n", minor);
346 MOD_DEC_USE_COUNT;
347 return -EIO;
348 } else if (!(status & LP_PERRORP)) {
349 printk(KERN_ERR "lp%d printer error\n", minor);
350 MOD_DEC_USE_COUNT;
351 return -EIO;
352 }
353 }
354
355 if ((irq = LP_IRQ(minor))) {
356 lp_table[minor].lp_buffer = (char *) kmalloc(LP_BUFFER_SIZE, GFP_KERNEL);
357 if (!lp_table[minor].lp_buffer) {
358 MOD_DEC_USE_COUNT;
359 return -ENOMEM;
360 }
361
362 ret = request_irq(irq, lp_interrupt, SA_INTERRUPT, "printer", NULL);
363 if (ret) {
364 kfree_s(lp_table[minor].lp_buffer, LP_BUFFER_SIZE);
365 lp_table[minor].lp_buffer = NULL;
366 printk("lp%d unable to use interrupt %d, error %d\n", minor, irq, ret);
367 MOD_DEC_USE_COUNT;
368 return ret;
369 }
370 }
371
372 LP_F(minor) |= LP_BUSY;
373 return 0;
374 }
375
376 static void lp_release(struct inode * inode, struct file * file)
377 {
378 unsigned int minor = MINOR(inode->i_rdev);
379 unsigned int irq;
380
381 if ((irq = LP_IRQ(minor))) {
382 free_irq(irq, NULL);
383 kfree_s(lp_table[minor].lp_buffer, LP_BUFFER_SIZE);
384 lp_table[minor].lp_buffer = NULL;
385 }
386
387 LP_F(minor) &= ~LP_BUSY;
388 MOD_DEC_USE_COUNT;
389 }
390
391
392 static int lp_ioctl(struct inode *inode, struct file *file,
393 unsigned int cmd, unsigned long arg)
394 {
395 unsigned int minor = MINOR(inode->i_rdev);
396 int retval = 0;
397
398 #ifdef LP_DEBUG
399 printk(KERN_DEBUG "lp%d ioctl, cmd: 0x%x, arg: 0x%x\n", minor, cmd, arg);
400 #endif
401 if (minor >= LP_NO)
402 return -ENODEV;
403 if ((LP_F(minor) & LP_EXIST) == 0)
404 return -ENODEV;
405 switch ( cmd ) {
406 case LPTIME:
407 LP_TIME(minor) = arg * HZ/100;
408 break;
409 case LPCHAR:
410 LP_CHAR(minor) = arg;
411 break;
412 case LPABORT:
413 if (arg)
414 LP_F(minor) |= LP_ABORT;
415 else
416 LP_F(minor) &= ~LP_ABORT;
417 break;
418 case LPABORTOPEN:
419 if (arg)
420 LP_F(minor) |= LP_ABORTOPEN;
421 else
422 LP_F(minor) &= ~LP_ABORTOPEN;
423 break;
424 case LPCAREFUL:
425 if (arg)
426 LP_F(minor) |= LP_CAREFUL;
427 else
428 LP_F(minor) &= ~LP_CAREFUL;
429 break;
430 case LPWAIT:
431 LP_WAIT(minor) = arg;
432 break;
433 case LPSETIRQ: {
434 int oldirq;
435 int newirq = arg;
436 struct lp_struct *lp = &lp_table[minor];
437
438 if (!suser())
439 return -EPERM;
440
441 oldirq = LP_IRQ(minor);
442
443
444 if (!oldirq && newirq) {
445 lp->lp_buffer = (char *) kmalloc(LP_BUFFER_SIZE, GFP_KERNEL);
446 if (!lp->lp_buffer)
447 return -ENOMEM;
448 }
449
450 if (oldirq) {
451 free_irq(oldirq, NULL);
452 }
453 if (newirq) {
454
455 if ((retval = request_irq(newirq, lp_interrupt, SA_INTERRUPT, "printer", NULL))) {
456 if (oldirq) {
457
458 request_irq(oldirq, lp_interrupt, SA_INTERRUPT, "printer", NULL);
459 } else {
460
461 kfree_s(lp->lp_buffer, LP_BUFFER_SIZE);
462 lp->lp_buffer = NULL;
463 }
464 return retval;
465 }
466 }
467 if (oldirq && !newirq) {
468
469 kfree_s(lp->lp_buffer, LP_BUFFER_SIZE);
470 lp->lp_buffer = NULL;
471 }
472 LP_IRQ(minor) = newirq;
473 lp_reset(minor);
474 break;
475 }
476 case LPGETIRQ:
477 retval = verify_area(VERIFY_WRITE, (void *) arg,
478 sizeof(int));
479 if (retval)
480 return retval;
481 memcpy_tofs((int *) arg, &LP_IRQ(minor), sizeof(int));
482 break;
483 case LPGETSTATUS:
484 retval = verify_area(VERIFY_WRITE, (void *) arg,
485 sizeof(int));
486 if (retval)
487 return retval;
488 else {
489 int status = LP_S(minor);
490 memcpy_tofs((int *) arg, &status, sizeof(int));
491 }
492 break;
493 case LPRESET:
494 lp_reset(minor);
495 break;
496 case LPGETSTATS:
497 retval = verify_area(VERIFY_WRITE, (void *) arg,
498 sizeof(struct lp_stats));
499 if (retval)
500 return retval;
501 else {
502 memcpy_tofs((int *) arg, &LP_STAT(minor), sizeof(struct lp_stats));
503 if (suser())
504 memset(&LP_STAT(minor), 0, sizeof(struct lp_stats));
505 }
506 break;
507 case LPGETFLAGS:
508 retval = verify_area(VERIFY_WRITE, (void *) arg,
509 sizeof(int));
510 if (retval)
511 return retval;
512 else {
513 int status = LP_F(minor);
514 memcpy_tofs((int *) arg, &status, sizeof(int));
515 }
516 break;
517 default:
518 retval = -EINVAL;
519 }
520 return retval;
521 }
522
523
524 static struct file_operations lp_fops = {
525 lp_lseek,
526 NULL,
527 lp_write,
528 NULL,
529 NULL,
530 lp_ioctl,
531 NULL,
532 lp_open,
533 lp_release
534 };
535
536 static int lp_probe(int offset)
537 {
538 int base, size;
539 unsigned int testvalue;
540
541 base = LP_B(offset);
542 if (base == 0)
543 return -1;
544 if (LP_IRQ(offset) > 15)
545 return -1;
546 size = (base == 0x3bc)? 3 : 8;
547 if (check_region(base, size) < 0)
548 return -1;
549
550 outb_p(LP_DUMMY, base);
551 udelay(LP_DELAY);
552 testvalue = inb_p(base);
553 if (testvalue == LP_DUMMY) {
554 LP_F(offset) |= LP_EXIST;
555 lp_reset(offset);
556 printk(KERN_INFO "lp%d at 0x%04x, ", offset, base);
557 request_region(base, size, "lp");
558 if (LP_IRQ(offset))
559 printk("(irq = %d)\n", LP_IRQ(offset));
560 else
561 printk("(polling)\n");
562 return 1;
563 } else
564 return 0;
565 }
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583 void lp_setup(char *str, int *ints)
584
585 {
586 LP_B(0) = ((ints[0] > 0) ? ints[1] : 0 );
587 LP_IRQ(0) = ((ints[0] > 1) ? ints[2] : 0 );
588 LP_B(1) = ((ints[0] > 2) ? ints[3] : 0 );
589 LP_IRQ(1) = ((ints[0] > 3) ? ints[4] : 0 );
590 LP_B(2) = ((ints[0] > 4) ? ints[5] : 0 );
591 LP_IRQ(2) = ((ints[0] > 5) ? ints[6] : 0 );
592 }
593
594 #ifdef MODULE
595 static int io[] = {0, 0, 0};
596 static int irq[] = {0, 0, 0};
597
598 #define lp_init init_module
599 #endif
600
601 int lp_init(void)
602 {
603 int offset = 0;
604 int count = 0;
605 #ifdef MODULE
606 int failed = 0;
607 #endif
608
609 if (register_chrdev(LP_MAJOR,"lp",&lp_fops)) {
610 printk("lp: unable to get major %d\n", LP_MAJOR);
611 return -EIO;
612 }
613 #ifdef MODULE
614
615 for (offset=0; offset < LP_NO; offset++) {
616 int specified=0;
617
618 if (io[offset] != 0) {
619 LP_B(offset) = io[offset];
620 specified++;
621 }
622 if (irq[offset] != 0) {
623 LP_IRQ(offset) = irq[offset];
624 specified++;
625 }
626 if (specified) {
627 if (lp_probe(offset) <= 0) {
628 printk(KERN_INFO "lp%d: Not found\n", offset);
629 failed++;
630 } else
631 count++;
632 }
633 }
634
635
636
637 if (count)
638 return 0;
639 if (failed) {
640 printk(KERN_INFO "lp: No override devices found.\n");
641 unregister_chrdev(LP_MAJOR,"lp");
642 return -EIO;
643 }
644
645
646
647
648 #endif
649
650 for (offset = 0; offset < LP_NO; offset++) {
651 int ret = lp_probe(offset);
652 if (ret < 0)
653 continue;
654 count += ret;
655 }
656 if (count == 0)
657 printk("lp: Driver configured but no interfaces found.\n");
658
659 return 0;
660 }
661
662 #ifdef MODULE
663 void cleanup_module(void)
664 {
665 int offset;
666
667 unregister_chrdev(LP_MAJOR,"lp");
668 for (offset = 0; offset < LP_NO; offset++) {
669 int base, size;
670 base = LP_B(offset);
671 size = (base == 0x3bc)? 3 : 8;
672 if (LP_F(offset) & LP_EXIST)
673 release_region(LP_B(offset),size);
674 }
675 }
676 #endif