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