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