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