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 outb_p(lpchar, LP_B(minor));
50 do {
51 status = LP_S(minor);
52 count ++;
53 if(need_resched)
54 schedule();
55 } while(!(status & LP_PBUSY) && count < LP_CHAR(minor));
56
57 if (count == LP_CHAR(minor)) {
58 return 0;
59
60 }
61 #ifdef LP_DEBUG
62 if (count > lp_max_count) {
63 printk("lp success after %d counts.\n",count);
64 lp_max_count=count;
65 }
66 #endif
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 outb_p(lpchar, LP_B(minor));
85
86 if (!((status = LP_S(minor)) & LP_PACK) || (status & LP_PBUSY)
87 || !((status = LP_S(minor)) & LP_PACK) || (status & LP_PBUSY)
88 || !((status = LP_S(minor)) & LP_PACK) || (status & LP_PBUSY)) {
89
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 if (!(lp_table[minor].lp_buffer = kmalloc(LP_BUFFER_SIZE,
293 GFP_KERNEL)))
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
334 #ifdef LP_DEBUG
335 printk("lp%d ioctl, cmd: 0x%x, arg: 0x%x\n", minor, cmd, arg);
336 #endif
337 if (minor >= LP_NO)
338 return -ENODEV;
339 if ((LP_F(minor) & LP_EXIST) == 0)
340 return -ENODEV;
341 switch ( cmd ) {
342 case LPTIME:
343 LP_TIME(minor) = arg;
344 break;
345 case LPCHAR:
346 LP_CHAR(minor) = arg;
347 break;
348 case LPABORT:
349 if(arg)
350 LP_F(minor) |= LP_ABORT;
351 else LP_F(minor) &= ~LP_ABORT;
352 break;
353 case LPWAIT:
354 LP_WAIT(minor) = arg;
355 break;
356 case LPSETIRQ: {
357 int ret;
358 int oldirq;
359 int newirq = arg;
360 struct lp_struct *lp = &lp_table[minor];
361 struct sigaction sa;
362
363 if (!suser())
364 return -EPERM;
365
366 oldirq = LP_IRQ(minor);
367
368
369 if (!oldirq && newirq) {
370 if (!(lp->lp_buffer = kmalloc(LP_BUFFER_SIZE, GFP_KERNEL)))
371 return -ENOMEM;
372 }
373
374 if (oldirq) {
375 free_irq(oldirq);
376 }
377 if (newirq) {
378
379 sa.sa_handler = lp_interrupt;
380 sa.sa_flags = SA_INTERRUPT;
381 sa.sa_mask = 0;
382 sa.sa_restorer = NULL;
383 if ((ret = irqaction(newirq, &sa))) {
384 if (oldirq) {
385
386 irqaction(oldirq, &sa);
387 } else {
388
389 kfree_s(lp->lp_buffer, LP_BUFFER_SIZE);
390 lp->lp_buffer = NULL;
391 }
392 return ret;
393 }
394 }
395 if (oldirq && !newirq) {
396
397 kfree_s(lp->lp_buffer, LP_BUFFER_SIZE);
398 lp->lp_buffer = NULL;
399 }
400 LP_IRQ(minor) = newirq;
401 lp_reset(minor);
402 break;
403 }
404 case LPGETIRQ:
405 arg = LP_IRQ(minor);
406 break;
407 default: arg = -EINVAL;
408 }
409 return arg;
410 }
411
412
413 static struct file_operations lp_fops = {
414 lp_lseek,
415 NULL,
416 lp_write,
417 NULL,
418 NULL,
419 lp_ioctl,
420 NULL,
421 lp_open,
422 lp_release
423 };
424
425 long lp_init(long kmem_start)
426 {
427 int offset = 0;
428 unsigned int testvalue = 0;
429 int count = 0;
430
431 if (register_chrdev(6,"lp",&lp_fops)) {
432 printk("unable to get major 6 for line printer\n");
433 return kmem_start;
434 }
435
436 for (offset = 0; offset < LP_NO; offset++) {
437
438 outb_p( LP_DUMMY, LP_B(offset));
439 for (testvalue = 0 ; testvalue < LP_DELAY ; testvalue++)
440 ;
441 testvalue = inb_p(LP_B(offset));
442 if (testvalue != 255) {
443 LP_F(offset) |= LP_EXIST;
444 lp_reset(offset);
445 printk("lp_init: lp%d exists (%d), ", offset, testvalue);
446 if (LP_IRQ(offset))
447 printk("using IRQ%d\n", LP_IRQ(offset));
448 else
449 printk("using polling driver\n");
450 count++;
451 }
452 }
453 if (count == 0)
454 printk("lp_init: no lp devices found\n");
455 return kmem_start;
456 }