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