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 if (current->signal & ~current->blocked) {
174 if (total_bytes_written + bytes_written)
175 return total_bytes_written + bytes_written;
176 else
177 return -EINTR;
178 }
179 }
180 }
181
182 total_bytes_written += bytes_written;
183 buf += bytes_written;
184 count -= bytes_written;
185
186 } while (count > 0);
187
188 return total_bytes_written;
189 }
190
191 static int lp_write_polled(struct inode * inode, struct file * file,
192 char * buf, int count)
193 {
194 int retval;
195 unsigned int minor = MINOR(inode->i_rdev);
196 char c, *temp = buf;
197
198 #ifdef LP_DEBUG
199 if (jiffies-lp_last_call > LP_TIME(minor)) {
200 lp_total_chars = 0;
201 lp_max_count = 1;
202 }
203 lp_last_call = jiffies;
204 #endif
205
206 temp = buf;
207 while (count > 0) {
208 c = get_fs_byte(temp);
209 retval = lp_char_polled(c, minor);
210
211 if (retval) { count--; temp++;
212 #ifdef LP_DEBUG
213 lp_total_chars++;
214 #endif
215 }
216 if (!retval) {
217 int status = LP_S(minor);
218
219 if (status & LP_POUTPA) {
220 printk("lp%d out of paper\n", minor);
221 if(LP_F(minor) & LP_ABORT)
222 return temp-buf?temp-buf:-ENOSPC;
223 current->state = TASK_INTERRUPTIBLE;
224 current->timeout = jiffies + LP_TIMEOUT_POLLED;
225 schedule();
226 } else
227 if (!(status & LP_PSELECD)) {
228 printk("lp%d off-line\n", minor);
229 if(LP_F(minor) & LP_ABORT)
230 return temp-buf?temp-buf:-EIO;
231 current->state = TASK_INTERRUPTIBLE;
232 current->timeout = jiffies + LP_TIMEOUT_POLLED;
233 schedule();
234 } else
235
236 if (!(status & LP_PERRORP)) {
237 printk("lp%d on fire\n", minor);
238 if(LP_F(minor) & LP_ABORT)
239 return temp-buf?temp-buf:-EFAULT;
240 current->state = TASK_INTERRUPTIBLE;
241 current->timeout = jiffies + LP_TIMEOUT_POLLED;
242 schedule();
243 }
244
245
246 if (current->signal & ~current->blocked) {
247 if (temp != buf)
248 return temp-buf;
249 else
250 return -EINTR;
251 }
252 #ifdef LP_DEBUG
253 printk("lp sleeping at %d characters for %d jiffies\n",
254 lp_total_chars, LP_TIME(minor));
255 lp_total_chars=0;
256 #endif
257 current->state = TASK_INTERRUPTIBLE;
258 current->timeout = jiffies + LP_TIME(minor);
259 schedule();
260 }
261 }
262 return temp-buf;
263 }
264
265 static int lp_write(struct inode * inode, struct file * file, char * buf, int count)
266 {
267 if (LP_IRQ(MINOR(inode->i_rdev)))
268 return lp_write_interrupt(inode, file, buf, count);
269 else
270 return lp_write_polled(inode, file, buf, count);
271 }
272
273 static int lp_lseek(struct inode * inode, struct file * file,
274 off_t offset, int origin)
275 {
276 return -ESPIPE;
277 }
278
279 static int lp_open(struct inode * inode, struct file * file)
280 {
281 unsigned int minor = MINOR(inode->i_rdev);
282 int ret;
283 unsigned int irq;
284 struct sigaction sa;
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 sa.sa_handler = lp_interrupt;
299 sa.sa_flags = SA_INTERRUPT;
300 sa.sa_mask = 0;
301 sa.sa_restorer = NULL;
302 ret = irqaction(irq, &sa);
303 if (ret) {
304 kfree_s(lp_table[minor].lp_buffer, LP_BUFFER_SIZE);
305 lp_table[minor].lp_buffer = NULL;
306 printk("lp%d unable to use interrupt %d, error %d\n", minor, irq, ret);
307 return ret;
308 }
309 }
310
311 LP_F(minor) |= LP_BUSY;
312
313 return 0;
314 }
315
316 static void lp_release(struct inode * inode, struct file * file)
317 {
318 unsigned int minor = MINOR(inode->i_rdev);
319 unsigned int irq;
320
321 if ((irq = LP_IRQ(minor))) {
322 free_irq(irq);
323 kfree_s(lp_table[minor].lp_buffer, LP_BUFFER_SIZE);
324 lp_table[minor].lp_buffer = NULL;
325 }
326
327 LP_F(minor) &= ~LP_BUSY;
328 }
329
330
331 static int lp_ioctl(struct inode *inode, struct file *file,
332 unsigned int cmd, unsigned long arg)
333 {
334 unsigned int minor = MINOR(inode->i_rdev);
335 int retval = 0;
336
337 #ifdef LP_DEBUG
338 printk("lp%d ioctl, cmd: 0x%x, arg: 0x%x\n", minor, cmd, arg);
339 #endif
340 if (minor >= LP_NO)
341 return -ENODEV;
342 if ((LP_F(minor) & LP_EXIST) == 0)
343 return -ENODEV;
344 switch ( cmd ) {
345 case LPTIME:
346 LP_TIME(minor) = arg;
347 break;
348 case LPCHAR:
349 LP_CHAR(minor) = arg;
350 break;
351 case LPABORT:
352 if (arg)
353 LP_F(minor) |= LP_ABORT;
354 else
355 LP_F(minor) &= ~LP_ABORT;
356 break;
357 case LPWAIT:
358 LP_WAIT(minor) = arg;
359 break;
360 case LPSETIRQ: {
361 int oldirq;
362 int newirq = arg;
363 struct lp_struct *lp = &lp_table[minor];
364 struct sigaction sa;
365
366 if (!suser())
367 return -EPERM;
368
369 oldirq = LP_IRQ(minor);
370
371
372 if (!oldirq && newirq) {
373 lp->lp_buffer = (char *) kmalloc(LP_BUFFER_SIZE, GFP_KERNEL);
374 if (!lp->lp_buffer)
375 return -ENOMEM;
376 }
377
378 if (oldirq) {
379 free_irq(oldirq);
380 }
381 if (newirq) {
382
383 sa.sa_handler = lp_interrupt;
384 sa.sa_flags = SA_INTERRUPT;
385 sa.sa_mask = 0;
386 sa.sa_restorer = NULL;
387 if ((retval = irqaction(newirq, &sa))) {
388 if (oldirq) {
389
390 irqaction(oldirq, &sa);
391 } else {
392
393 kfree_s(lp->lp_buffer, LP_BUFFER_SIZE);
394 lp->lp_buffer = NULL;
395 }
396 return retval;
397 }
398 }
399 if (oldirq && !newirq) {
400
401 kfree_s(lp->lp_buffer, LP_BUFFER_SIZE);
402 lp->lp_buffer = NULL;
403 }
404 LP_IRQ(minor) = newirq;
405 lp_reset(minor);
406 break;
407 }
408 case LPGETIRQ:
409 retval = LP_IRQ(minor);
410 break;
411 default:
412 retval = -EINVAL;
413 }
414 return retval;
415 }
416
417
418 static struct file_operations lp_fops = {
419 lp_lseek,
420 NULL,
421 lp_write,
422 NULL,
423 NULL,
424 lp_ioctl,
425 NULL,
426 lp_open,
427 lp_release
428 };
429
430 long lp_init(long kmem_start)
431 {
432 int offset = 0;
433 unsigned int testvalue = 0;
434 int count = 0;
435
436 if (register_chrdev(LP_MAJOR,"lp",&lp_fops)) {
437 printk("unable to get major %d for line printer\n", LP_MAJOR);
438 return kmem_start;
439 }
440
441 for (offset = 0; offset < LP_NO; offset++) {
442
443 outb_p( LP_DUMMY, LP_B(offset));
444 for (testvalue = 0 ; testvalue < LP_DELAY ; testvalue++)
445 ;
446 testvalue = inb_p(LP_B(offset));
447 if (testvalue != 255) {
448 LP_F(offset) |= LP_EXIST;
449 lp_reset(offset);
450 printk("lp_init: lp%d exists (%d), ", offset, testvalue);
451 if (LP_IRQ(offset))
452 printk("using IRQ%d\n", LP_IRQ(offset));
453 else
454 printk("using polling driver\n");
455 count++;
456 }
457 }
458 if (count == 0)
459 printk("lp_init: no lp devices found\n");
460 return kmem_start;
461 }