OpenCores
URL https://opencores.org/ocsvn/or1k_old/or1k_old/trunk

Subversion Repositories or1k_old

[/] [or1k_old/] [trunk/] [uclinux/] [uClinux-2.0.x/] [drivers/] [char/] [lp_m68k.c] - Blame information for rev 199

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 199 simons
/*
2
 * split in two parts for better support of different hardware
3
 * by Joerg Dorchain (dorchain@mpi-sb.mpg.de)
4
 *
5
 * Amiga printer device by Michael Rausch (linux@uni-koblenz.de);
6
 * Atari support added by Andreas Schwab (schwab@ls5.informatik.uni-dortmund.de);
7
 * based upon work from
8
 *
9
 * Copyright (C) 1992 by Jim Weigand and Linus Torvalds
10
 * Copyright (C) 1992,1993 by Michael K. Johnson
11
 * - Thanks much to Gunter Windau for pointing out to me where the error
12
 *   checking ought to be.
13
 * Copyright (C) 1993 by Nigel Gamble (added interrupt code)
14
 */
15
 
16
/* 01/17/95: Matthias Welwarsky (dg8y@rs11.hrz.th-darmstadt.de)
17
 * lp_write(): rewritten from scratch
18
 * lp_interrupt(): fixed cli()/sti()-bug
19
 *
20
 * 95/05/28: Andreas Schwab (schwab@issan.informatik.uni-dortmund.de)
21
 * lp_write() fixed to make it work again.
22
 * 95/08/18: Andreas Schwab
23
 * lp_write_interrupt: fix race condition
24
 *
25
 *  * CAUTION, please do check! *
26
 *
27
 *  on 68000-based machines sti() must NEVER appear in interrupt driven
28
 *  code. The 68k-CPU has a priority-based interrupt scheme. while an interrupt
29
 *  with a certain priority is executed, all requests with lower or same
30
 *  priority get locked out. executing the sti()-macro allows ANY interrupt
31
 *  to be served. this really causes BIG trouble!
32
 *  to protect an interrupt driven routine against being interrupted
33
 *  (if absolutely needed!) one should use save_flags();cli()/restore_flags()!
34
 *
35
 */
36
 
37
#include <linux/config.h>
38
#include <linux/errno.h>
39
#include <linux/kernel.h>
40
#include <linux/major.h>
41
#include <linux/sched.h>
42
#include <asm/irq.h>
43
 
44
#ifdef CONFIG_AMIGA
45
#include <asm/amigaints.h>
46
#ifdef CONFIG_MULTIFACE_III_LP
47
#include <linux/lp_mfc.h>
48
#endif
49
#endif
50
#ifdef CONFIG_ATARI
51
#include <asm/atarihw.h>
52
#include <asm/atariints.h>
53
#endif
54
 
55
#include <linux/lp_m68k.h>
56
#include <linux/lp_intern.h>
57
#include <linux/malloc.h>
58
#include <linux/interrupt.h>
59
 
60
#include <asm/segment.h>
61
#include <asm/system.h>
62
 
63
 
64
/*
65
 *  why bother around with the pio driver when the interrupt works;
66
 *  so, for "security" reasons only, it's configurable here.
67
 *  saves some bytes, at least ...
68
 */
69
#define FORCE_POLLING    0
70
#define FORCE_INTERRUPT  1
71
#define PREFER_INTERRUPT 2
72
 
73
#define WHICH_DRIVER    FORCE_INTERRUPT
74
 
75
#define MAX_LP 3 /* the maximum number of devices */
76
 
77
struct lp_struct lp_table[MAX_LP] = {{0,},};
78
 
79
static int max_lp; /* the real number of devices */
80
 
81
/*
82
 * All my debugging code assumes that you debug with only one printer at
83
 * a time. RWWH
84
 */
85
 
86
#define LP_DEBUG 
87
#undef LP_DEBUG 
88
 
89
 
90
#if WHICH_DRIVER != FORCE_INTERRUPT
91
#ifdef LP_DEBUG
92
static int lp_max_count = 1;
93
#endif
94
 
95
static int lp_char_polled(char lpchar, int dev)
96
{
97
        unsigned long count  = 0;
98
 
99
        do {
100
                count ++;
101
                if(need_resched)
102
                        schedule();
103
        } while (lp_table[dev].lp_is_busy(dev) && count < lp_table[dev].chars);
104
 
105
        if (count == lp_table[dev].chars) {
106
                return 0;
107
                /* we timed out, and the character was /not/ printed */
108
        }
109
#ifdef LP_DEBUG
110
        if (count > lp_max_count) {
111
                printk("lp success after %d counts.\n",count);
112
                lp_max_count = count;
113
        }
114
#endif
115
        lp_table[dev].lp_out(lpchar, dev);
116
        return 1;
117
}
118
#endif
119
 
120
 
121
#ifdef LP_DEBUG
122
unsigned int lp_total_chars = 0;
123
unsigned int lp_last_call = 0;
124
#endif
125
 
126
 
127
#if WHICH_DRIVER != FORCE_POLLING
128
static __inline__ int lp_char_interrupt(char lpchar, int dev)
129
{
130
        if (!lp_table[dev].lp_is_busy(dev)) {
131
                lp_table[dev].lp_out(lpchar,dev);
132
                return 1;
133
        }
134
        return 0;
135
}
136
 
137
static int lp_error;
138
 
139
static void lp_interrupt(int irq, struct pt_regs *fp, void *dummy)
140
{
141
    unsigned long flags;
142
    int dev;
143
 
144
    for (dev = 0; dev < max_lp; dev++) {
145
        if (lp_table[dev].lp_my_interrupt(dev) != 0)
146
          if (lp_table[dev].do_print)
147
          {
148
                  if (lp_table[dev].copy_size)
149
                  {
150
                          save_flags(flags);
151
                          cli();
152
                          if (lp_char_interrupt(lp_table[dev].lp_buffer[lp_table[dev].bytes_written], dev)) {
153
                                  --lp_table[dev].copy_size;
154
                                  ++lp_table[dev].bytes_written;
155
                                  restore_flags(flags);
156
                          }
157
                          else
158
                          {
159
                                  lp_table[dev].do_print = 0;
160
                                  restore_flags(flags);
161
                                  lp_error = 1;
162
                                  wake_up_interruptible(&lp_table[dev].lp_wait_q);
163
                          }
164
                  }
165
                  else
166
                  {
167
                          lp_table[dev].do_print = 0;
168
                          lp_error = 0;
169
                          wake_up_interruptible(&lp_table[dev].lp_wait_q);
170
                  }
171
 
172
          }
173
    }
174
}
175
 
176
#if WHICH_DRIVER == FORCE_INTERRUPT
177
static int lp_write(struct inode *inode, struct file *file,
178
                    const char *buf, int count)
179
#else
180
static int lp_write_interrupt(struct inode *inode, struct file *file,
181
                              const char *buf, int count)
182
#endif
183
{
184
  unsigned long total_bytes_written = 0;
185
  unsigned int flags;
186
  int rc;
187
  int dev = MINOR(inode->i_rdev);
188
 
189
  do {
190
    lp_table[dev].do_print = 0;          /* disable lp_interrupt()   */
191
    lp_table[dev].bytes_written = 0;     /* init buffer read-pointer */
192
    lp_error = 0;
193
    lp_table[dev].copy_size = (count <= LP_BUFFER_SIZE ? count : LP_BUFFER_SIZE);
194
    memcpy_fromfs(lp_table[dev].lp_buffer, buf, lp_table[dev].copy_size);
195
    while (lp_table[dev].copy_size) {
196
      save_flags(flags);
197
      cli();                            /* no interrupts now */
198
      lp_table[dev].do_print = 1;       /* enable lp_interrupt() */
199
      if (lp_char_interrupt(lp_table[dev].lp_buffer[lp_table[dev].bytes_written], dev)) {
200
        ++lp_table[dev].bytes_written;
201
        --lp_table[dev].copy_size;
202
        lp_error = 0;
203
      } else {                          /* something went wrong   */
204
        lp_table[dev].do_print = 0;      /* disable lp_interrupt() */
205
        lp_error = 1;                   /* printer caused error   */
206
      }
207
      if (lp_error) {
208
 
209
          /* something blocked printing, so we don't want to sleep too long,
210
             in case we have to rekick the interrupt */
211
 
212
          current->timeout = jiffies + LP_TIMEOUT_POLLED;
213
      } else {
214
          current->timeout = jiffies + LP_TIMEOUT_INTERRUPT;
215
      }
216
 
217
      interruptible_sleep_on(&lp_table[dev].lp_wait_q);
218
      restore_flags(flags);
219
 
220
      /* we're up again and running. we first disable lp_interrupt(), then
221
         check what happened meanwhile */
222
 
223
      lp_table[dev].do_print = 0;
224
      rc = total_bytes_written + lp_table[dev].bytes_written;
225
 
226
      if (current->signal & ~current->blocked) {
227
        if (rc)
228
          return rc;
229
        else
230
          return -EINTR;
231
      }
232
      if (lp_error) {
233
 
234
        /* an error has occurred, maybe in lp_interrupt().
235
           figure out the type of error, exit on request or if nothing has
236
           been printed at all. */
237
 
238
        if (lp_table[dev].lp_has_pout(dev)) {
239
          printk(KERN_NOTICE "lp%d: paper-out\n",dev);
240
          if (!rc) rc = -ENOSPC;
241
        } else if (!lp_table[dev].lp_is_online(dev)) {
242
          printk(KERN_NOTICE "lp%d: off-line\n",dev);
243
          if (!rc) rc = -EIO;
244
        } else if (lp_table[dev].lp_is_busy(dev)) {
245
          printk(KERN_NOTICE "lp%d: on fire\n",dev);
246
          if (!rc) rc = -EIO;
247
        }
248
        if (lp_table[dev].flags & LP_ABORT)
249
          return rc;
250
      }
251
      /* check if our buffer was completely printed, if not, most likely
252
         an unsolved error blocks the printer. As we can`t do anything
253
         against, we start all over again. Else we set the read-pointer
254
         of the buffer and count the printed characters */
255
 
256
      if (!lp_table[dev].copy_size) {
257
        total_bytes_written += lp_table[dev].bytes_written;
258
        buf += lp_table[dev].bytes_written;
259
        count -= lp_table[dev].bytes_written;
260
      }
261
    }
262
  } while (count > 0);
263
  return total_bytes_written;
264
}
265
#endif
266
 
267
#if WHICH_DRIVER != FORCE_INTERRUPT
268
#if WHICH_DRIVER == FORCE_POLLING
269
static int lp_write(struct inode *inode, struct file *file,
270
                    const char *buf, int count)
271
#else
272
static int lp_write_polled(struct inode *inode, struct file *file,
273
                           const char *buf, int count)
274
#endif
275
{
276
        char *temp = buf;
277
        int dev = MINOR(inode->i_rdev);
278
 
279
#ifdef LP_DEBUG
280
        if (jiffies-lp_last_call > lp_table[dev].time) {
281
                lp_total_chars = 0;
282
                lp_max_count = 1;
283
        }
284
        lp_last_call = jiffies;
285
#endif
286
 
287
        temp = buf;
288
        while (count > 0) {
289
                if (lp_char_polled(get_user(temp), dev)) {
290
                        /* only update counting vars if character was printed */
291
                        count--; temp++;
292
#ifdef LP_DEBUG
293
                        lp_total_chars++;
294
#endif
295
                } else { /* if printer timed out */
296
                        if (lp_table[dev].lp_has_pout(dev)) {
297
                                printk(KERN_NOTICE "lp%d: out of paper\n",dev);
298
                                if (lp_table[dev].flags & LP_ABORT)
299
                                        return temp - buf ? temp-buf : -ENOSPC;
300
                                current->state = TASK_INTERRUPTIBLE;
301
                                current->timeout = jiffies + LP_TIMEOUT_POLLED;
302
                                schedule();
303
                        } else if (!lp_table[dev].lp_is_online(dev)) {
304
                                printk(KERN_NOTICE "lp%d: off-line\n",dev);
305
                                if (lp_table[dev].flags & LP_ABORT)
306
                                        return temp - buf ? temp-buf : -EIO;
307
                                current->state = TASK_INTERRUPTIBLE;
308
                                current->timeout = jiffies + LP_TIMEOUT_POLLED;
309
                                schedule();
310
                        } else
311
                        /* not offline or out of paper. on fire? */
312
                        if (lp_table[dev].lp_is_busy(dev)) {
313
                                printk(KERN_NOTICE "lp%d: on fire\n",dev);
314
                                if (lp_table[dev].flags & LP_ABORT)
315
                                        return temp - buf ? temp-buf : -EFAULT;
316
                                current->state = TASK_INTERRUPTIBLE;
317
                                current->timeout = jiffies + LP_TIMEOUT_POLLED;
318
                                schedule();
319
                        }
320
 
321
                        /* check for signals before going to sleep */
322
                        if (current->signal & ~current->blocked) {
323
                                if (temp != buf)
324
                                        return temp-buf;
325
                                else
326
                                        return -EINTR;
327
                        }
328
#ifdef LP_DEBUG
329
                        printk("lp sleeping at %d characters for %d jiffies\n",
330
                                lp_total_chars, lp_table[dev].time);
331
                        lp_total_chars = 0;
332
#endif
333
                        current->state = TASK_INTERRUPTIBLE;
334
                        current->timeout = jiffies + lp_table[dev].time;
335
                        schedule();
336
                }
337
        }
338
        return temp - buf;
339
}
340
#endif
341
 
342
static unsigned int lp_irq = 0;
343
 
344
#if WHICH_DRIVER == PREFER_INTERRUPT
345
static int lp_write(struct inode *inode, struct file *file,
346
                    const char *buf, int count)
347
{
348
        if (lp_irq)
349
                return lp_write_interrupt(inode, file, buf, count);
350
        else
351
                return lp_write_polled(inode, file, buf, count);
352
}
353
#endif
354
 
355
static int lp_lseek(struct inode *inode, struct file *file,
356
                    off_t offset, int origin)
357
{
358
        return -ESPIPE;
359
}
360
 
361
static int lp_open(struct inode *inode, struct file *file)
362
{
363
        int dev = MINOR(inode->i_rdev);
364
 
365
        if (dev >= max_lp)
366
                return -ENODEV;
367
        if (!(lp_table[dev].flags & LP_EXIST))
368
                return -ENODEV;
369
        if (lp_table[dev].flags & LP_BUSY)
370
                return -EBUSY;
371
 
372
        lp_table[dev].flags |= LP_BUSY;
373
 
374
        return 0;
375
}
376
 
377
static void lp_release(struct inode *inode, struct file *file)
378
{
379
        lp_table[MINOR(inode->i_rdev)].flags &= ~LP_BUSY;
380
}
381
 
382
 
383
static int lp_ioctl(struct inode *inode, struct file *file,
384
                    unsigned int cmd, unsigned long arg)
385
{
386
        unsigned int minor = MINOR(inode->i_rdev);
387
        int retval = 0;
388
 
389
#ifdef LP_DEBUG
390
        printk("lp%d ioctl, cmd: 0x%x, arg: 0x%x\n", minor, cmd, arg);
391
#endif
392
        if (minor >= max_lp)
393
                return -ENODEV;
394
        if (!(lp_table[minor].flags & LP_EXIST))
395
                return -ENODEV;
396
        switch (cmd) {
397
        case LPTIME:
398
                lp_table[minor].time = arg;
399
                break;
400
        case LPCHAR:
401
                lp_table[minor].chars = arg;
402
                break;
403
        case LPABORT:
404
                if (arg)
405
                        lp_table[minor].flags |= LP_ABORT;
406
                else
407
                        lp_table[minor].flags &= ~LP_ABORT;
408
                break;
409
        case LPWAIT:
410
                lp_table[minor].wait = arg;
411
                break;
412
        case LPSETIRQ:
413
        case LPGETIRQ:
414
                retval = lp_irq;
415
                break;
416
        default:
417
                retval = -EINVAL;
418
        }
419
        return retval;
420
}
421
 
422
 
423
static struct file_operations lp_fops = {
424
        lp_lseek,
425
        NULL,           /* lp_read */
426
        lp_write,
427
        NULL,           /* lp_readdir */
428
        NULL,           /* lp_select */
429
        lp_ioctl,
430
        NULL,           /* lp_mmap */
431
        lp_open,
432
        lp_release
433
};
434
 
435
 
436
int lp_init(void)
437
{
438
        extern char m68k_debug_device[];
439
 
440
        if (!strcmp( m68k_debug_device, "par" ))
441
                return -EBUSY;
442
 
443
        if (register_chrdev(LP_MAJOR,"lp", &lp_fops)) {
444
                printk("unable to get major %d for line printer\n", LP_MAJOR);
445
                return -EBUSY;
446
        }
447
 
448
#if WHICH_DRIVER == FORCE_POLLING
449
        lp_irq = 0;
450
        printk(KERN_INFO "lp_init: lp using polling driver\n");
451
#else
452
 
453
#ifdef CONFIG_AMIGA
454
        if (MACH_IS_AMIGA && AMIGAHW_PRESENT(AMI_PARALLEL))
455
                lp_irq = add_isr(IRQ_AMIGA_CIAA_FLG, lp_interrupt, 0,
456
                                 NULL, "printer");
457
#endif
458
#ifdef CONFIG_ATARI
459
        if (MACH_IS_ATARI)
460
                lp_irq = add_isr(IRQ_MFP_BUSY, lp_interrupt, IRQ_TYPE_SLOW,
461
                                 NULL, "printer");
462
#endif
463
 
464
        if (lp_irq)
465
                printk(KERN_INFO "lp_init: lp using interrupt\n");
466
        else
467
 
468
#if WHICH_DRIVER == PREFER_INTERRUPT
469
                printk(KERN_INFO "lp_init: lp using polling driver\n");
470
#else
471
                printk(KERN_WARNING "lp_init: can't get interrupt, and polling driver not configured\n");
472
#endif
473
#endif
474
 
475
        max_lp = 0;
476
        max_lp += lp_internal_init(lp_table, max_lp, MAX_LP, WHICH_DRIVER);
477
#ifdef CONFIG_MULTIFACE_III_LP
478
        max_lp += lp_mfc_init(lp_table, max_lp, MAX_LP, WHICH_DRIVER);
479
#if WHICH_DRIVER != FORCE_POLLING
480
        add_isr(IRQ_AMIGA_PORTS, lp_interrupt, 0, NULL,
481
                "Multiface III printer");
482
#endif
483
#endif
484
        return 0;
485
}
486
 
487
/*
488
 * Currently we do not accept any lp-parameters, but that may change.
489
 */
490
void    lp_setup(char *str, int *ints)
491
{
492
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.