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