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