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