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 printk("lp%d unable to use interrupt %d, error %d\n", 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 }
321
322 LP_F(minor) &= ~LP_BUSY;
323 }
324
325
326 static int lp_ioctl(struct inode *inode, struct file *file,
327 unsigned int cmd, unsigned int arg)
328 {
329 unsigned int minor = MINOR(inode->i_rdev);
330
331 #ifdef LP_DEBUG
332 printk("lp%d ioctl, cmd: 0x%x, arg: 0x%x\n", minor, cmd, arg);
333 #endif
334 if (minor >= LP_NO)
335 return -ENODEV;
336 if ((LP_F(minor) & LP_EXIST) == 0)
337 return -ENODEV;
338 switch ( cmd ) {
339 case LPTIME:
340 LP_TIME(minor) = arg;
341 break;
342 case LPCHAR:
343 LP_CHAR(minor) = arg;
344 break;
345 case LPABORT:
346 if(arg)
347 LP_F(minor) |= LP_ABORT;
348 else LP_F(minor) &= ~LP_ABORT;
349 break;
350 case LPWAIT:
351 LP_WAIT(minor) = arg;
352 break;
353 case LPSETIRQ: {
354 int ret;
355 int oldirq;
356 struct sigaction sa;
357
358 if (!suser())
359 return -EPERM;
360
361 if ((oldirq = LP_IRQ(minor))) {
362 free_irq(oldirq);
363 }
364 if (arg) {
365
366 sa.sa_handler = lp_interrupt;
367 sa.sa_flags = SA_INTERRUPT;
368 sa.sa_mask = 0;
369 sa.sa_restorer = NULL;
370 if ((ret = irqaction(arg, &sa))) {
371 if (oldirq)
372
373 irqaction(oldirq, &sa);
374 return ret;
375 }
376 }
377 LP_IRQ(minor) = arg;
378 lp_reset(minor);
379 break;
380 }
381 case LPGETIRQ:
382 arg = LP_IRQ(minor);
383 break;
384 default: arg = -EINVAL;
385 }
386 return arg;
387 }
388
389
390 static struct file_operations lp_fops = {
391 lp_lseek,
392 NULL,
393 lp_write,
394 NULL,
395 NULL,
396 lp_ioctl,
397 NULL,
398 lp_open,
399 lp_release
400 };
401
402 long lp_init(long kmem_start)
403 {
404 int offset = 0;
405 unsigned int testvalue = 0;
406 int count = 0;
407
408 if (register_chrdev(6,"lp",&lp_fops))
409 printk("unable to get major 6 for line printer\n");
410
411 for (offset = 0; offset < LP_NO; offset++) {
412
413 outb_p( LP_DUMMY, LP_B(offset));
414 for (testvalue = 0 ; testvalue < LP_DELAY ; testvalue++)
415 ;
416 testvalue = inb_p(LP_B(offset));
417 if (testvalue != 255) {
418 LP_F(offset) |= LP_EXIST;
419 lp_reset(offset);
420 printk("lp_init: lp%d exists (%d), ", offset, testvalue);
421 if (LP_IRQ(offset))
422 printk("using IRQ%d\n", LP_IRQ(offset));
423 else
424 printk("using polling driver\n");
425 count++;
426 }
427 }
428 if (count == 0)
429 printk("lp_init: no lp devices found\n");
430 return kmem_start;
431 }