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