summaryrefslogtreecommitdiffstats
path: root/drivers/char/lp_m68k.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1997-04-29 21:13:14 +0000
committer <ralf@linux-mips.org>1997-04-29 21:13:14 +0000
commit19c9bba94152148523ba0f7ef7cffe3d45656b11 (patch)
tree40b1cb534496a7f1ca0f5c314a523c69f1fee464 /drivers/char/lp_m68k.c
parent7206675c40394c78a90e74812bbdbf8cf3cca1be (diff)
Import of Linux/MIPS 2.1.36
Diffstat (limited to 'drivers/char/lp_m68k.c')
-rw-r--r--drivers/char/lp_m68k.c319
1 files changed, 187 insertions, 132 deletions
diff --git a/drivers/char/lp_m68k.c b/drivers/char/lp_m68k.c
index 1c634041b..3cc9458bd 100644
--- a/drivers/char/lp_m68k.c
+++ b/drivers/char/lp_m68k.c
@@ -35,22 +35,22 @@
*/
#include <linux/config.h>
+#include <linux/module.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/sched.h>
+#include <linux/string.h>
#include <asm/irq.h>
+#ifdef CONFIG_KERNELD
+#include <linux/kerneld.h>
+#endif
#ifdef CONFIG_AMIGA
-#include <asm/amigaints.h>
#ifdef CONFIG_MULTIFACE_III_LP
#include <linux/lp_mfc.h>
#endif
#endif
-#ifdef CONFIG_ATARI
-#include <asm/atarihw.h>
-#include <asm/atariints.h>
-#endif
#include <linux/lp_m68k.h>
#include <linux/lp_intern.h>
@@ -68,13 +68,16 @@
*/
#define FORCE_POLLING 0
#define FORCE_INTERRUPT 1
+/*
+ * PREFER_INTERRUPT doesn't make much sense on m68k.
+ * it is preserved here in case of joining with the i386 driver
+ *
#define PREFER_INTERRUPT 2
+ */
#define WHICH_DRIVER FORCE_INTERRUPT
-#define MAX_LP 3 /* the maximum number of devices */
-
-struct lp_struct lp_table[MAX_LP] = {{0,},};
+struct lp_struct *lp_table[MAX_LP] = {NULL,};
static int max_lp; /* the real number of devices */
@@ -100,9 +103,9 @@ static int lp_char_polled(char lpchar, int dev)
count ++;
if(need_resched)
schedule();
- } while (lp_table[dev].lp_is_busy(dev) && count < lp_table[dev].chars);
+ } while (lp_table[dev]->lp_is_busy(dev) && count < lp_table[dev]->chars);
- if (count == lp_table[dev].chars) {
+ if (count == lp_table[dev]->chars) {
return 0;
/* we timed out, and the character was /not/ printed */
}
@@ -112,7 +115,7 @@ static int lp_char_polled(char lpchar, int dev)
lp_max_count = count;
}
#endif
- lp_table[dev].lp_out(lpchar, dev);
+ lp_table[dev]->lp_out(lpchar, dev);
return 1;
}
#endif
@@ -127,8 +130,8 @@ unsigned int lp_last_call = 0;
#if WHICH_DRIVER != FORCE_POLLING
static __inline__ int lp_char_interrupt(char lpchar, int dev)
{
- if (!lp_table[dev].lp_is_busy(dev)) {
- lp_table[dev].lp_out(lpchar,dev);
+ if (!lp_table[dev]->lp_is_busy(dev)) {
+ lp_table[dev]->lp_out(lpchar,dev);
return 1;
}
return 0;
@@ -136,49 +139,44 @@ static __inline__ int lp_char_interrupt(char lpchar, int dev)
static int lp_error;
-static void lp_interrupt(int irq, struct pt_regs *fp, void *dummy)
+void lp_interrupt(int dev)
{
- unsigned long flags;
- int dev;
-
- for (dev = 0; dev < max_lp; dev++) {
- if (lp_table[dev].lp_my_interrupt(dev) != 0)
- if (lp_table[dev].do_print)
- {
- if (lp_table[dev].copy_size)
- {
- save_flags(flags);
- cli();
- if (lp_char_interrupt(lp_table[dev].lp_buffer[lp_table[dev].bytes_written], dev)) {
- --lp_table[dev].copy_size;
- ++lp_table[dev].bytes_written;
- restore_flags(flags);
- }
- else
- {
- lp_table[dev].do_print = 0;
- restore_flags(flags);
- lp_error = 1;
- wake_up_interruptible(&lp_table[dev].lp_wait_q);
- }
- }
- else
- {
- lp_table[dev].do_print = 0;
- lp_error = 0;
- wake_up_interruptible(&lp_table[dev].lp_wait_q);
- }
-
- }
+ if (dev >= 0 && dev < MAX_LP && lp_table[dev]->do_print)
+ {
+ if (lp_table[dev]->copy_size)
+ {
+ unsigned long flags;
+ save_flags(flags);
+ cli();
+ if (lp_char_interrupt(lp_table[dev]->lp_buffer[lp_table[dev]->bytes_written], dev)) {
+ --lp_table[dev]->copy_size;
+ ++lp_table[dev]->bytes_written;
+ restore_flags(flags);
+ }
+ else
+ {
+ lp_table[dev]->do_print = 0;
+ restore_flags(flags);
+ lp_error = 1;
+ wake_up_interruptible(&lp_table[dev]->lp_wait_q);
+ }
+ }
+ else
+ {
+ lp_table[dev]->do_print = 0;
+ lp_error = 0;
+ wake_up_interruptible(&lp_table[dev]->lp_wait_q);
+ }
+
}
}
#if WHICH_DRIVER == FORCE_INTERRUPT
-static int lp_write(struct inode *inode, struct file *file,
- const char *buf, int count)
+static long lp_write(struct inode *inode, struct file *file,
+ const char *buf, unsigned long count)
#else
-static int lp_write_interrupt(struct inode *inode, struct file *file,
- const char *buf, int count)
+static long lp_write_interrupt(struct inode *inode, struct file *file,
+ const char *buf, unsigned long count)
#endif
{
unsigned long total_bytes_written = 0;
@@ -187,21 +185,21 @@ static int lp_write_interrupt(struct inode *inode, struct file *file,
int dev = MINOR(inode->i_rdev);
do {
- lp_table[dev].do_print = 0; /* disable lp_interrupt() */
- lp_table[dev].bytes_written = 0; /* init buffer read-pointer */
+ lp_table[dev]->do_print = 0; /* disable lp_interrupt() */
+ lp_table[dev]->bytes_written = 0; /* init buffer read-pointer */
lp_error = 0;
- lp_table[dev].copy_size = (count <= LP_BUFFER_SIZE ? count : LP_BUFFER_SIZE);
- copy_from_user(lp_table[dev].lp_buffer, buf, lp_table[dev].copy_size);
- while (lp_table[dev].copy_size) {
+ lp_table[dev]->copy_size = (count <= LP_BUFFER_SIZE ? count : LP_BUFFER_SIZE);
+ copy_from_user(lp_table[dev]->lp_buffer, buf, lp_table[dev]->copy_size);
+ while (lp_table[dev]->copy_size) {
save_flags(flags);
cli(); /* no interrupts now */
- lp_table[dev].do_print = 1; /* enable lp_interrupt() */
- if (lp_char_interrupt(lp_table[dev].lp_buffer[lp_table[dev].bytes_written], dev)) {
- ++lp_table[dev].bytes_written;
- --lp_table[dev].copy_size;
+ lp_table[dev]->do_print = 1; /* enable lp_interrupt() */
+ if (lp_char_interrupt(lp_table[dev]->lp_buffer[lp_table[dev]->bytes_written], dev)) {
+ ++lp_table[dev]->bytes_written;
+ --lp_table[dev]->copy_size;
lp_error = 0;
} else { /* something went wrong */
- lp_table[dev].do_print = 0; /* disable lp_interrupt() */
+ lp_table[dev]->do_print = 0; /* disable lp_interrupt() */
lp_error = 1; /* printer caused error */
}
if (lp_error) {
@@ -214,14 +212,14 @@ static int lp_write_interrupt(struct inode *inode, struct file *file,
current->timeout = jiffies + LP_TIMEOUT_INTERRUPT;
}
- interruptible_sleep_on(&lp_table[dev].lp_wait_q);
+ interruptible_sleep_on(&lp_table[dev]->lp_wait_q);
restore_flags(flags);
/* we're up again and running. we first disable lp_interrupt(), then
check what happened meanwhile */
- lp_table[dev].do_print = 0;
- rc = total_bytes_written + lp_table[dev].bytes_written;
+ lp_table[dev]->do_print = 0;
+ rc = total_bytes_written + lp_table[dev]->bytes_written;
if (current->signal & ~current->blocked) {
if (rc)
@@ -235,17 +233,17 @@ static int lp_write_interrupt(struct inode *inode, struct file *file,
figure out the type of error, exit on request or if nothing has
been printed at all. */
- if (lp_table[dev].lp_has_pout(dev)) {
+ if (lp_table[dev]->lp_has_pout(dev)) {
printk(KERN_NOTICE "lp%d: paper-out\n",dev);
if (!rc) rc = -ENOSPC;
- } else if (!lp_table[dev].lp_is_online(dev)) {
+ } else if (!lp_table[dev]->lp_is_online(dev)) {
printk(KERN_NOTICE "lp%d: off-line\n",dev);
if (!rc) rc = -EIO;
- } else if (lp_table[dev].lp_is_busy(dev)) {
+ } else if (lp_table[dev]->lp_is_busy(dev)) {
printk(KERN_NOTICE "lp%d: on fire\n",dev);
if (!rc) rc = -EIO;
}
- if (lp_table[dev].flags & LP_ABORT)
+ if (lp_table[dev]->flags & LP_ABORT)
return rc;
}
/* check if our buffer was completely printed, if not, most likely
@@ -253,31 +251,33 @@ static int lp_write_interrupt(struct inode *inode, struct file *file,
against, we start all over again. Else we set the read-pointer
of the buffer and count the printed characters */
- if (!lp_table[dev].copy_size) {
- total_bytes_written += lp_table[dev].bytes_written;
- buf += lp_table[dev].bytes_written;
- count -= lp_table[dev].bytes_written;
+ if (!lp_table[dev]->copy_size) {
+ total_bytes_written += lp_table[dev]->bytes_written;
+ buf += lp_table[dev]->bytes_written;
+ count -= lp_table[dev]->bytes_written;
}
}
} while (count > 0);
return total_bytes_written;
}
+#else
+void (*lp_interrupt)() = NULL;
#endif
#if WHICH_DRIVER != FORCE_INTERRUPT
#if WHICH_DRIVER == FORCE_POLLING
-static int lp_write(struct inode *inode, struct file *file,
- const char *buf, int count)
+static long lp_write(struct inode *inode, struct file *file,
+ const char *buf, unsigned long count)
#else
-static int lp_write_polled(struct inode *inode, struct file *file,
- const char *buf, int count)
+static long lp_write_polled(struct inode *inode, struct file *file,
+ const char *buf, unsigned long count)
#endif
{
char *temp = buf;
int dev = MINOR(inode->i_rdev);
#ifdef LP_DEBUG
- if (jiffies-lp_last_call > lp_table[dev].time) {
+ if (jiffies-lp_last_call > lp_table[dev]->time) {
lp_total_chars = 0;
lp_max_count = 1;
}
@@ -293,25 +293,25 @@ static int lp_write_polled(struct inode *inode, struct file *file,
lp_total_chars++;
#endif
} else { /* if printer timed out */
- if (lp_table[dev].lp_has_pout(dev)) {
+ if (lp_table[dev]->lp_has_pout(dev)) {
printk(KERN_NOTICE "lp%d: out of paper\n",dev);
- if (lp_table[dev].flags & LP_ABORT)
+ if (lp_table[dev]->flags & LP_ABORT)
return temp - buf ? temp-buf : -ENOSPC;
current->state = TASK_INTERRUPTIBLE;
current->timeout = jiffies + LP_TIMEOUT_POLLED;
schedule();
- } else if (!lp_table[dev].lp_is_online(dev)) {
+ } else if (!lp_table[dev]->lp_is_online(dev)) {
printk(KERN_NOTICE "lp%d: off-line\n",dev);
- if (lp_table[dev].flags & LP_ABORT)
+ if (lp_table[dev]->flags & LP_ABORT)
return temp - buf ? temp-buf : -EIO;
current->state = TASK_INTERRUPTIBLE;
current->timeout = jiffies + LP_TIMEOUT_POLLED;
schedule();
} else
/* not offline or out of paper. on fire? */
- if (lp_table[dev].lp_is_busy(dev)) {
+ if (lp_table[dev]->lp_is_busy(dev)) {
printk(KERN_NOTICE "lp%d: on fire\n",dev);
- if (lp_table[dev].flags & LP_ABORT)
+ if (lp_table[dev]->flags & LP_ABORT)
return temp - buf ? temp-buf : -EFAULT;
current->state = TASK_INTERRUPTIBLE;
current->timeout = jiffies + LP_TIMEOUT_POLLED;
@@ -327,11 +327,11 @@ static int lp_write_polled(struct inode *inode, struct file *file,
}
#ifdef LP_DEBUG
printk("lp sleeping at %d characters for %d jiffies\n",
- lp_total_chars, lp_table[dev].time);
+ lp_total_chars, lp_table[dev]->time);
lp_total_chars = 0;
#endif
current->state = TASK_INTERRUPTIBLE;
- current->timeout = jiffies + lp_table[dev].time;
+ current->timeout = jiffies + lp_table[dev]->time;
schedule();
}
}
@@ -339,11 +339,11 @@ static int lp_write_polled(struct inode *inode, struct file *file,
}
#endif
-static unsigned int lp_irq = 0;
+unsigned int lp_irq = 0;
#if WHICH_DRIVER == PREFER_INTERRUPT
-static int lp_write(struct inode *inode, struct file *file,
- const char *buf, int count)
+static long lp_write(struct inode *inode, struct file *file,
+ const char *buf, unsigned long count)
{
if (lp_irq)
return lp_write_interrupt(inode, file, buf, count);
@@ -352,8 +352,8 @@ static int lp_write(struct inode *inode, struct file *file,
}
#endif
-static int lp_lseek(struct inode *inode, struct file *file,
- off_t offset, int origin)
+static long long lp_lseek(struct inode * inode, struct file * file,
+ long long offset, int origin)
{
return -ESPIPE;
}
@@ -361,22 +361,45 @@ static int lp_lseek(struct inode *inode, struct file *file,
static int lp_open(struct inode *inode, struct file *file)
{
int dev = MINOR(inode->i_rdev);
+ int ret;
- if (dev >= max_lp)
+ if (dev >= MAX_LP)
return -ENODEV;
- if (!(lp_table[dev].flags & LP_EXIST))
+#ifdef CONFIG_KERNELD
+ if (!lp_table[dev]) {
+ char modname[30];
+
+ sprintf(modname, "char-major-%d-%d", LP_MAJOR, dev);
+ request_module(modname);
+ }
+#endif
+ if (!lp_table[dev])
+ return -ENODEV;
+ if (!(lp_table[dev]->flags & LP_EXIST))
return -ENODEV;
- if (lp_table[dev].flags & LP_BUSY)
+ if (lp_table[dev]->flags & LP_BUSY)
return -EBUSY;
- lp_table[dev].flags |= LP_BUSY;
+ lp_table[dev]->flags |= LP_BUSY;
- return 0;
+ ret = lp_table[dev]->lp_open(dev);
+ if (ret != 0) {
+ lp_table[dev]->flags &= ~LP_BUSY;
+ }
+ else {
+ MOD_INC_USE_COUNT;
+ }
+ return ret;
}
-static void lp_release(struct inode *inode, struct file *file)
+static int lp_release(struct inode *inode, struct file *file)
{
- lp_table[MINOR(inode->i_rdev)].flags &= ~LP_BUSY;
+ int dev =MINOR(inode->i_rdev);
+
+ lp_table[dev]->flags &= ~LP_BUSY;
+ lp_table[dev]->lp_release(dev);
+ MOD_DEC_USE_COUNT;
+ return 0;
}
@@ -391,30 +414,33 @@ static int lp_ioctl(struct inode *inode, struct file *file,
#endif
if (minor >= max_lp)
return -ENODEV;
- if (!(lp_table[minor].flags & LP_EXIST))
+ if (!(lp_table[minor]->flags & LP_EXIST))
return -ENODEV;
switch (cmd) {
case LPTIME:
- lp_table[minor].time = arg;
+ lp_table[minor]->time = arg;
break;
case LPCHAR:
- lp_table[minor].chars = arg;
+ lp_table[minor]->chars = arg;
break;
case LPABORT:
if (arg)
- lp_table[minor].flags |= LP_ABORT;
+ lp_table[minor]->flags |= LP_ABORT;
else
- lp_table[minor].flags &= ~LP_ABORT;
+ lp_table[minor]->flags &= ~LP_ABORT;
break;
case LPWAIT:
- lp_table[minor].wait = arg;
+ lp_table[minor]->wait = arg;
break;
case LPSETIRQ:
case LPGETIRQ:
retval = lp_irq;
break;
default:
- retval = -EINVAL;
+ if (lp_table[minor]->lp_ioctl)
+ retval = lp_table[minor]->lp_ioctl(minor, cmd, arg);
+ else
+ retval = -EINVAL;
}
return retval;
}
@@ -425,13 +451,19 @@ static struct file_operations lp_fops = {
NULL, /* lp_read */
lp_write,
NULL, /* lp_readdir */
- NULL, /* lp_select */
+ NULL, /* lp_poll */
lp_ioctl,
NULL, /* lp_mmap */
lp_open,
lp_release
};
+EXPORT_SYMBOL(lp_table);
+EXPORT_SYMBOL(lp_irq);
+EXPORT_SYMBOL(lp_interrupt);
+EXPORT_SYMBOL(lp_init);
+EXPORT_SYMBOL(register_parallel);
+EXPORT_SYMBOL(unregister_parallel);
int lp_init(void)
{
@@ -441,8 +473,8 @@ int lp_init(void)
return -EBUSY;
if (register_chrdev(LP_MAJOR,"lp", &lp_fops)) {
- printk("unable to get major %d for line printer\n", LP_MAJOR);
- return -EBUSY;
+ printk(KERN_ERR "unable to get major %d for line printer\n", LP_MAJOR);
+ return -ENXIO;
}
#if WHICH_DRIVER == FORCE_POLLING
@@ -450,35 +482,14 @@ int lp_init(void)
printk(KERN_INFO "lp_init: lp using polling driver\n");
#else
-#ifdef CONFIG_AMIGA
- if (MACH_IS_AMIGA && AMIGAHW_PRESENT(AMI_PARALLEL))
- lp_irq = add_isr(IRQ_AMIGA_CIAA_FLG, lp_interrupt, 0,
- NULL, "printer");
-#endif
-#ifdef CONFIG_ATARI
- if (MACH_IS_ATARI)
- lp_irq = add_isr(IRQ_MFP_BUSY, lp_interrupt, IRQ_TYPE_SLOW,
- NULL, "printer");
+ lp_irq = 1;
+ printk(KERN_INFO "lp_init: lp using interrupt driver\n");
#endif
- if (lp_irq)
- printk(KERN_INFO "lp_init: lp using interrupt\n");
- else
-
-#if WHICH_DRIVER == PREFER_INTERRUPT
- printk(KERN_INFO "lp_init: lp using polling driver\n");
-#else
- printk(KERN_WARNING "lp_init: can't get interrupt, and polling driver not configured\n");
-#endif
-#endif
-
- max_lp = 0;
- max_lp += lp_internal_init(lp_table, max_lp, MAX_LP, WHICH_DRIVER);
+#ifndef MODULE
+ lp_internal_init();
#ifdef CONFIG_MULTIFACE_III_LP
- max_lp += lp_mfc_init(lp_table, max_lp, MAX_LP, WHICH_DRIVER);
-#if WHICH_DRIVER != FORCE_POLLING
- add_isr(IRQ_AMIGA_PORTS, lp_interrupt, 0, NULL,
- "Multiface III printer");
+ lp_mfc_init();
#endif
#endif
return 0;
@@ -490,3 +501,47 @@ int lp_init(void)
void lp_setup(char *str, int *ints)
{
}
+
+#ifdef MODULE
+int init_module(void)
+{
+return lp_init();
+}
+
+void cleanup_module(void)
+{
+unregister_chrdev(LP_MAJOR, "lp");
+}
+#endif
+
+/*
+ * (un-)register for hardware drivers
+ * tab is an inititalised lp_struct, dev the desired minor
+ * if dev < 0, let the driver choose the first free minor
+ * if sucessful return the minor, else -1
+ */
+int register_parallel(struct lp_struct *tab, int dev)
+{
+if (dev < 0) {
+ dev = 0;
+ while ((dev < MAX_LP) && (lp_table[dev] != NULL))
+ dev++;
+}
+if (dev > MAX_LP)
+ return -1;
+if (lp_table[dev] != NULL)
+ return -1;
+lp_table[dev] = tab;
+printk(KERN_INFO "lp%d: %s at 0x%08lx\n", dev, tab->name, (long)tab->base);
+return dev;
+}
+
+#ifdef CONFIG_MODULES
+void unregister_parallel(int dev)
+{
+if ((dev < 0) || (dev > MAX_LP) || (lp_table[dev] == NULL))
+ printk(KERN_ERR "WARNING: unregister_parallel for non-existant device ignored!\n");
+else
+ lp_table[dev] = NULL;
+}
+#endif