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 reported invalid error status (on fire, eh?)\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
286 if (minor >= LP_NO)
287 return -ENODEV;
288 if ((LP_F(minor) & LP_EXIST) == 0)
289 return -ENODEV;
290 if (LP_F(minor) & LP_BUSY)
291 return -EBUSY;
292
293 if ((irq = LP_IRQ(minor))) {
294 lp_table[minor].lp_buffer = (char *) kmalloc(LP_BUFFER_SIZE, GFP_KERNEL);
295 if (!lp_table[minor].lp_buffer)
296 return -ENOMEM;
297
298 ret = request_irq(irq, lp_interrupt, SA_INTERRUPT, "printer");
299 if (ret) {
300 kfree_s(lp_table[minor].lp_buffer, LP_BUFFER_SIZE);
301 lp_table[minor].lp_buffer = NULL;
302 printk("lp%d unable to use interrupt %d, error %d\n", minor, irq, ret);
303 return ret;
304 }
305 }
306
307 LP_F(minor) |= LP_BUSY;
308
309 return 0;
310 }
311
312 static void lp_release(struct inode * inode, struct file * file)
313 {
314 unsigned int minor = MINOR(inode->i_rdev);
315 unsigned int irq;
316
317 if ((irq = LP_IRQ(minor))) {
318 free_irq(irq);
319 kfree_s(lp_table[minor].lp_buffer, LP_BUFFER_SIZE);
320 lp_table[minor].lp_buffer = NULL;
321 }
322
323 LP_F(minor) &= ~LP_BUSY;
324 }
325
326
327 static int lp_ioctl(struct inode *inode, struct file *file,
328 unsigned int cmd, unsigned long arg)
329 {
330 unsigned int minor = MINOR(inode->i_rdev);
331 int retval = 0;
332
333 #ifdef LP_DEBUG
334 printk("lp%d ioctl, cmd: 0x%x, arg: 0x%x\n", minor, cmd, arg);
335 #endif
336 if (minor >= LP_NO)
337 return -ENODEV;
338 if ((LP_F(minor) & LP_EXIST) == 0)
339 return -ENODEV;
340 switch ( cmd ) {
341 case LPTIME:
342 LP_TIME(minor) = arg;
343 break;
344 case LPCHAR:
345 LP_CHAR(minor) = arg;
346 break;
347 case LPABORT:
348 if (arg)
349 LP_F(minor) |= LP_ABORT;
350 else
351 LP_F(minor) &= ~LP_ABORT;
352 break;
353 case LPWAIT:
354 LP_WAIT(minor) = arg;
355 break;
356 case LPSETIRQ: {
357 int oldirq;
358 int newirq = arg;
359 struct lp_struct *lp = &lp_table[minor];
360
361 if (!suser())
362 return -EPERM;
363
364 oldirq = LP_IRQ(minor);
365
366
367 if (!oldirq && newirq) {
368 lp->lp_buffer = (char *) kmalloc(LP_BUFFER_SIZE, GFP_KERNEL);
369 if (!lp->lp_buffer)
370 return -ENOMEM;
371 }
372
373 if (oldirq) {
374 free_irq(oldirq);
375 }
376 if (newirq) {
377
378 if ((retval = request_irq(newirq, lp_interrupt, SA_INTERRUPT, "printer"))) {
379 if (oldirq) {
380
381 request_irq(oldirq, lp_interrupt, SA_INTERRUPT, "printer");
382 } else {
383
384 kfree_s(lp->lp_buffer, LP_BUFFER_SIZE);
385 lp->lp_buffer = NULL;
386 }
387 return retval;
388 }
389 }
390 if (oldirq && !newirq) {
391
392 kfree_s(lp->lp_buffer, LP_BUFFER_SIZE);
393 lp->lp_buffer = NULL;
394 }
395 LP_IRQ(minor) = newirq;
396 lp_reset(minor);
397 break;
398 }
399 case LPGETIRQ:
400 retval = LP_IRQ(minor);
401 break;
402 default:
403 retval = -EINVAL;
404 }
405 return retval;
406 }
407
408
409 static struct file_operations lp_fops = {
410 lp_lseek,
411 NULL,
412 lp_write,
413 NULL,
414 NULL,
415 lp_ioctl,
416 NULL,
417 lp_open,
418 lp_release
419 };
420
421 long lp_init(long kmem_start)
422 {
423 int offset = 0;
424 unsigned int testvalue = 0;
425 int count = 0;
426
427 if (register_chrdev(LP_MAJOR,"lp",&lp_fops)) {
428 printk("unable to get major %d for line printer\n", LP_MAJOR);
429 return kmem_start;
430 }
431
432 for (offset = 0; offset < LP_NO; offset++) {
433
434 outb_p( LP_DUMMY, LP_B(offset));
435 for (testvalue = 0 ; testvalue < LP_DELAY ; testvalue++)
436 ;
437 testvalue = inb_p(LP_B(offset));
438 if (testvalue == LP_DUMMY) {
439 LP_F(offset) |= LP_EXIST;
440 lp_reset(offset);
441 printk("lp_init: lp%d exists, ", offset);
442 if (LP_IRQ(offset))
443 printk("using IRQ%d\n", LP_IRQ(offset));
444 else
445 printk("using polling driver\n");
446 count++;
447 }
448 }
449 if (count == 0)
450 printk("lp_init: no lp devices found\n");
451 return kmem_start;
452 }