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