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