Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

L68K: Parport for MFC3

0 views
Skip to first unread message

Joerg Dorchain

unread,
Oct 3, 1998, 3:00:00 AM10/3/98
to
(Forwarded from the linux-m68k mailing list)

Hi all,

this is a patch against 2.1.20 for including parport support for the
amiga built-in port and the parallel port of a Multiface 3 card.
Please test it and tell the results. As high-level-driver only the
printer driver (lp) is currently tested (due to the lack of zip-drives,
scanners, ....). At least the MFC3 port should be able to work with
those things.

Have fun,

Joerg


--- ./arch/m68k/config.in.old Tue Sep 8 18:27:47 1998
+++ ./arch/m68k/config.in Sun Sep 20 07:57:51 1998
@@ -103,6 +103,18 @@
fi
fi
bool '/proc/hardware support' CONFIG_PROC_HARDWARE
+
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ tristate 'Parallel port support (disables old lp driver!)' CONFIG_PARPORT
+ if [ "$CONFIG_PARPORT" != "n" ]; then
+ if [ "$CONFIG_AMIGA" != "n" ]; then
+ dep_tristate ' Amiga builtin port' CONFIG_PARPORT_AMIGA $CONFIG_PARPORT
+ if [ "$CONFIG_ZORRO" != "n" ]; then
+ dep_tristate ' Multiface III parallel port' CONFIG_PARPORT_MFC3 $CONFIG_PARPORT
+ fi
+ fi
+ fi
+fi
endmenu

source drivers/block/Config.in
@@ -259,9 +271,16 @@
define_bool CONFIG_NVRAM y
fi

-tristate 'Parallel printer support' CONFIG_M68K_PRINTER
-if [ "$CONFIG_ZORRO" = "y" ]; then
- dep_tristate 'Multiface Card III parallel support' CONFIG_MULTIFACE_III_LP $CONFIG_PRINTER
+if [ "$CONFIG_PARPORT" = "n" ]; then
+ tristate 'Parallel printer support' CONFIG_M68K_PRINTER
+ if [ "$CONFIG_ZORRO" = "y" ]; then
+ dep_tristate 'Multiface Card III parallel support' CONFIG_MULTIFACE_III_LP $CONFIG_PRINTER
+ fi
+else
+ dep_tristate 'Parallel printer support' CONFIG_PRINTER $CONFIG_PARPORT
+ if [ "$CONFIG_PRINTER" != "n" ]; then
+ bool ' Support IEEE1284 status readback' CONFIG_PRINTER_READBACK
+ fi
fi
if [ "$CONFIG_AMIGA" = "y" ]; then
tristate 'Amiga mouse support' CONFIG_AMIGAMOUSE
--- ./drivers/char/lp.c.old Sun Aug 30 13:33:56 1998
+++ ./drivers/char/lp.c Sun Sep 27 14:26:39 1998
@@ -94,13 +94,17 @@
#include <linux/delay.h>

#include <linux/parport.h>
-#undef LP_STATS
+#define LP_STATS
#undef LP_NEED_CAREFUL
#include <linux/lp.h>

#include <asm/irq.h>
#include <asm/uaccess.h>
#include <asm/system.h>
+#include <asm/spinlock.h>
+
+spinlock_t lp_lock;
+

/* if you have more than 3 printers, remember to increase LP_NO */
#define LP_NO 3
@@ -126,7 +130,7 @@
#define LP_READY(minor, status) ((status) & LP_PBUSY)
#endif

-#undef LP_DEBUG
+#define LP_DEBUG
#undef LP_READ_DEBUG

/* --- parport support ----------------------------------------- */
@@ -211,20 +215,12 @@
#endif
/* must wait before taking strobe high, and after taking strobe
low, according spec. Some printers need it, others don't. */
-#ifndef __sparc__
- while (wait != LP_WAIT(minor)) /* FIXME: should be a udelay() */
- wait++;
-#else
- udelay(1);
-#endif
+ udelay(LP_WAIT(minor));
+
/* control port takes strobe high */
w_ctr(minor, LP_PSELECP | LP_PINITP | LP_PSTROBE);
-#ifndef __sparc__
- while (wait) /* FIXME: should be a udelay() */
- wait--;
-#else
- udelay(1);
-#endif
+ udelay(LP_WAIT(minor));
+
/* take strobe low */
if (LP_POLLED(minor))
/* take strobe low */
@@ -240,7 +236,7 @@
/* update waittime statistics */
if (count > stats->maxwait) {
#ifdef LP_DEBUG
- printk(KERN_DEBUG "lp%d success after %d counts.\n", minor, count);
+ printk(KERN_DEBUG "lp%d success after %ld counts.\n", minor, count);
#endif
stats->maxwait = count;
}
@@ -384,7 +380,12 @@
current->timeout = jiffies + LP_TIME(minor);
lp_schedule (minor);
} else {
- cli();
+ /* Replace cli()/sti() by
+ cli()/restore_flags.
+ It's a must for other architectures
+ and doesn't break i386 */
+ unsigned long flags;
+ spin_lock_irqsave(&lp_lock, flags);
if (LP_PREEMPTED(minor))
{
/*
@@ -394,7 +395,7 @@
* envinroment to avoid parport sharing
* starvation.
*/
- sti();
+ spin_unlock_irqrestore(&lp_lock, flags);
goto lp_polling;
}
if (!lp_table[minor].irq_detected)
@@ -402,7 +403,7 @@
current->timeout = jiffies + LP_TIMEOUT_INTERRUPT;
interruptible_sleep_on(&lp->wait_q);
}
- sti();
+ spin_unlock_irqrestore(&lp_lock, flags);
}
}
}
@@ -624,7 +625,7 @@
int retval = 0;

#ifdef LP_DEBUG
- printk(KERN_DEBUG "lp%d ioctl, cmd: 0x%x, arg: 0x%x\n", minor, cmd, arg);
+ printk(KERN_DEBUG "lp%d ioctl, cmd: 0x%0x, arg: 0x%08lx\n", minor, cmd, arg);
#endif
if (minor >= LP_NO)
return -ENODEV;
@@ -788,6 +789,8 @@
unsigned int count = 0;
unsigned int i;
struct parport *port;
+
+ spin_lock_init(&lp_lock);

switch (parport_nr[0])
{
--- ./drivers/misc/parport_ax.c.old Mon Aug 10 17:37:16 1998
+++ ./drivers/misc/parport_ax.c Sun Sep 27 14:05:53 1998
@@ -50,12 +50,6 @@
#define CONFIGB 0x401
#define ECONTROL 0x402

-static void
-parport_ax_null_intr_func(int irq, void *dev_id, struct pt_regs *regs)
-{
- /* NULL function - Does nothing */
-}
-
void
parport_ax_write_epp(struct parport *p, unsigned char d)
{
@@ -206,7 +200,7 @@
{
if (p->irq != PARPORT_IRQ_NONE) {
parport_ax_disable_irq(p);
- free_irq(p->irq, NULL);
+ free_irq(p->irq, p);
}
release_region(p->base, p->size);
if (p->modes & PARPORT_MODE_PCECR)
@@ -220,8 +214,8 @@
{
/* FIXME check that resources are free */
if (p->irq != PARPORT_IRQ_NONE) {
- request_irq(p->irq, parport_ax_null_intr_func,
- 0, p->name, NULL);
+ request_irq(p->irq, parport_intr_func,
+ 0, p->name, p);
parport_ax_enable_irq(p);
}
request_region(p->base, p->size, p->name);
@@ -282,7 +276,7 @@
}

int
-parport_ax_examine_irq(struct parport *p)
+parport_ax_change_irq(struct parport *p,int newirq)
{
return 0; /* FIXME */
}
@@ -355,7 +349,7 @@

parport_ax_enable_irq,
parport_ax_disable_irq,
- parport_ax_examine_irq,
+ parport_ax_change_irq,

parport_ax_inc_use_count,
parport_ax_dec_use_count,
--- ./drivers/misc/parport_init.c.old Thu Dec 11 06:23:33 1902
+++ ./drivers/misc/parport_init.c Sun Sep 20 07:54:35 1998
@@ -122,6 +122,12 @@
#ifdef CONFIG_PARPORT_AX
parport_ax_init();
#endif
+#ifdef CONFIG_PARPORT_AMIGA
+ parport_amiga_init();
+#endif
+#ifdef CONFIG_PARPORT_MFC3
+ parport_mfc3_init();
+#endif
return 0;
}
#endif
@@ -143,6 +149,7 @@
EXPORT_SYMBOL(parport_proc_unregister);
EXPORT_SYMBOL(parport_probe_hook);
EXPORT_SYMBOL(parport_parse_irqs);
+EXPORT_SYMBOL(parport_intr_func);

void inc_parport_count(void)
{
--- ./drivers/misc/parport_pc.c.old Mon Aug 10 17:37:16 1998
+++ ./drivers/misc/parport_pc.c Sun Sep 27 14:07:56 1998
@@ -53,11 +53,6 @@
than PARPORT_MAX (in <linux/parport.h>). */
#define PARPORT_PC_MAX_PORTS 8

-static void parport_pc_null_intr_func(int irq, void *dev_id, struct pt_regs *regs)
-{
- /* Null function - does nothing */
-}
-
void parport_pc_write_epp(struct parport *p, unsigned char d)
{
outb(d, p->base+EPPDATA);
@@ -173,7 +168,7 @@
void parport_pc_release_resources(struct parport *p)
{
if (p->irq != PARPORT_IRQ_NONE)
- free_irq(p->irq, NULL);
+ free_irq(p->irq, p);
release_region(p->base, p->size);
if (p->modes & PARPORT_MODE_PCECR)
release_region(p->base+0x400, 3);
@@ -183,7 +178,7 @@
{
int err;
if (p->irq != PARPORT_IRQ_NONE)
- if ((err = request_irq(p->irq, parport_pc_null_intr_func, 0, p->name, NULL)) != 0) return err;
+ if ((err = request_irq(p->irq, parport_intr_func, 0, p->name, p)) != 0) return err;
request_region(p->base, p->size, p->name);
if (p->modes & PARPORT_MODE_PCECR)
request_region(p->base+0x400, 3, p->name);
@@ -242,7 +237,7 @@
return -ENOSYS; /* FIXME */
}

-int parport_pc_examine_irq(struct parport *p)
+int parport_pc_change_irq(struct parport *p, int newirq)
{
return 0; /* FIXME */
}
@@ -313,7 +308,7 @@

parport_pc_enable_irq,
parport_pc_disable_irq,
- parport_pc_examine_irq,
+ parport_pc_change_irq,

parport_pc_inc_use_count,
parport_pc_dec_use_count,
--- ./drivers/misc/parport_procfs.c.old Mon Aug 10 17:37:16 1998
+++ ./drivers/misc/parport_procfs.c Sun Sep 27 13:32:00 1998
@@ -65,36 +65,29 @@
goto out;
}

- retval = count;
-
if (oldirq == newirq)
- goto out;
+ return count;

- spin_lock_irqsave(&pp->lock, flags);
- if (pp->flags & PARPORT_FLAG_COMA)
- goto out_ok;
+ read_lock_irqsave(&pp->cad_lock, flags);

- retval = -EBUSY;
if (pp->cad)
- goto out_unlock;
-
- if (newirq != PARPORT_IRQ_NONE) {
- retval = request_irq(newirq, parport_null_intr_func,
- SA_INTERRUPT, pp->name, NULL);
- if (retval)
- goto out_unlock;
- else retval = count;
+ {
+ retval = -EBUSY;
+ goto unlock_and_return;
}

- if (oldirq != PARPORT_IRQ_NONE)
- free_irq(oldirq, NULL);
-
-out_ok:
- pp->irq = newirq;
-
-out_unlock:
- spin_unlock_irqrestore (&pp->lock, flags);

+ if (pp->ops->change_irq)
+ {
+ retval = pp->ops->change_irq(pp, newirq);
+ if (!retval)
+ retval = count;
+ }
+ else
+ retval = -ENOSYS;
+
+unlock_and_return:
+ read_unlock_irqrestore(&pp->cad_lock, flags);
out:
return retval;
}
--- ./drivers/misc/parport_share.c.old Mon Aug 10 17:37:16 1998
+++ ./drivers/misc/parport_share.c Tue Sep 8 18:51:52 1998
@@ -55,10 +55,15 @@
return portlist;
}

-void parport_null_intr_func(int irq, void *dev_id, struct pt_regs *regs)
+void parport_intr_func(int irq, void *dev_id, struct pt_regs *regs)
{
- /* Null function - does nothing. IRQs are pointed here whenever
- there is no real handler for them. */
+ /* Generic function. This has always to be done. If some hardware
+ needs black magic before or after the high level call,
+ implement an own function. */
+ struct parport *p = dev_id;
+
+ if ( p && p->cad && p->cad->irq_func )
+ (*p->cad->irq_func)(irq, p->cad->private, regs);
}

struct parport *parport_register_port(unsigned long base, int irq, int dma,
@@ -355,19 +360,7 @@
port->cad = dev;
spin_unlock_irqrestore(&port->lock, flags);

- /* Swap the IRQ handlers. */
- if (port->irq != PARPORT_IRQ_NONE) {
- if (oldcad && oldcad->irq_func) {
- free_irq(port->irq, oldcad->private);
- request_irq(port->irq, parport_null_intr_func,
- SA_INTERRUPT, port->name, NULL);
- }
- if (dev->irq_func) {
- free_irq(port->irq, NULL);
- request_irq(port->irq, dev->irq_func,
- SA_INTERRUPT, dev->name, dev->private);
- }
- }
+ /* irqs are done by low level driver */

/* Restore control registers */
port->ops->restore_state(port, dev->state);
@@ -457,13 +450,6 @@

/* Save control registers */
port->ops->save_state(port, dev->state);
-
- /* Point IRQs somewhere harmless. */
- if (port->irq != PARPORT_IRQ_NONE && dev->irq_func) {
- free_irq(port->irq, dev->private);
- request_irq(port->irq, parport_null_intr_func,
- SA_INTERRUPT, port->name, NULL);
- }

/* If anybody is waiting, find out who's been there longest and
then wake them up. (Note: no locking required) */
--- ./drivers/misc/Makefile.old Mon Feb 23 21:26:49 1998
+++ ./drivers/misc/Makefile Sun Sep 20 07:53:53 1998
@@ -37,6 +37,20 @@
M_OBJS += parport_ax.o
endif
endif
+ ifeq ($(CONFIG_PARPORT_AMIGA),y)
+ LX_OBJS += parport_amiga.o
+ else
+ ifeq ($(CONFIG_PARPORT_AMIGA),m)
+ M_OBJS += parport_amiga.o
+ endif
+ endif
+ ifeq ($(CONFIG_PARPORT_MFC3),y)
+ LX_OBJS += parport_mfc3.o
+ else
+ ifeq ($(CONFIG_PARPORT_MFC3),m)
+ M_OBJS += parport_mfc3.o
+ endif
+ endif
LX_OBJS += parport_init.o
else
ifeq ($(CONFIG_PARPORT),m)
@@ -52,6 +66,12 @@
endif
ifeq ($(CONFIG_PARPORT_AX),m)
M_OBJS += parport_ax.o
+ endif
+ ifeq ($(CONFIG_PARPORT_AMIGA),m)
+ M_OBJS += parport_amiga.o
+ endif
+ ifeq ($(CONFIG_PARPORT_MFC3),m)
+ M_OBJS += parport_mfc3.o
endif
endif

--- ./drivers/misc/parport_amiga.c.old Tue Sep 8 18:51:52 1998
+++ ./drivers/misc/parport_amiga.c Sun Sep 27 14:36:36 1998
@@ -0,0 +1,301 @@
+/* Low-level parallel port routines for the Amiga buildin port
+ *
+ * Author: Joerg Dorchain <dorc...@wirbel.com>
+ *
+ * This is a complete rewrite of the code, but based heaviy upon the old
+ * lp_intern. code.
+ *
+ * The built-in Amiga parallel port provides one port at a fixed address
+ * with 8 bisdirecttional data lines (D0 - D7) and 3 bidirectional status
+ * lines (BUSY, POUT, SEL), 1 output control line /STROBE (raised automatically in
+ * hardware when the data register is accessed), and 1 input control line
+ * /ACK, able to cause an interrupt, but both not directly settable by
+ * software.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/parport.h>
+#include <asm/setup.h>
+#include <asm/amigahw.h>
+#include <asm/irq.h>
+#include <asm/amigaints.h>
+
+#undef DEBUG
+#ifdef DEBUG
+#define DPRINTK printk
+#else
+static inline int DPRINTK() {return 0;}
+#endif
+
+static struct parport *this_port = NULL;
+
+static void amiga_write_data(struct parport *p, unsigned char data)
+{
+DPRINTK("write_data %c\n",data);
+ /* Triggers also /STROBE. This behavior cannot be changed */
+ ciaa.prb = data;
+}
+
+static unsigned char amiga_read_data(struct parport *p)
+{
+ /* Triggers also /STROBE. This behavior cannot be changed */
+ return ciaa.prb;
+}
+
+#if 0
+static unsigned char control_pc_to_amiga(unsigned char control)
+{
+ unsigned char ret = 0;
+
+ if (control & PARPORT_CONTROL_DIRECTION) /* XXX: What is this? */
+ ;
+ if (control & PARPORT_CONTROL_INTEN) /* XXX: What is INTEN? */
+ ;
+ if (control & PARPORT_CONTROL_SELECT) /* XXX: What is SELECP? */
+ ;
+ if (control & PARPORT_CONTROL_INIT) /* INITP */
+ /* reset connected to cpu reset pin */;
+ if (control & PARPORT_CONTROL_AUTOFD) /* AUTOLF */
+ /* Not connected */;
+ if (control & PARPORT_CONTROL_STROBE) /* Strobe */
+ /* Handled only directly by hardware */;
+ return ret;
+}
+#endif
+
+static unsigned char control_amiga_to_pc(unsigned char control)
+{
+ return PARPORT_CONTROL_INTEN | PARPORT_CONTROL_SELECT |
+ PARPORT_CONTROL_AUTOFD | PARPORT_CONTROL_STROBE;
+ /* fake value: interrupt enable, select in, no reset,
+ no autolf, no strobe - seems to be closest the wiring diagram */
+}
+
+static void amiga_write_control(struct parport *p, unsigned char control)
+{
+DPRINTK("write_control %02x\n",control);
+ /* No implementation possible */
+}
+
+static unsigned char amiga_read_control( struct parport *p)
+{
+DPRINTK("read_control \n");
+ return control_amiga_to_pc(0);
+}
+
+static unsigned char amiga_frob_control( struct parport *p, unsigned char mask, unsigned char val)
+{
+ unsigned char old;
+
+DPRINTK("frob_control mask %02x, value %02x\n",mask,val);
+ old = amiga_read_control(p);
+ amiga_write_control(p, (old & ~mask) ^ val);
+ return old;
+}
+
+
+static unsigned char status_pc_to_amiga(unsigned char status)
+{
+ unsigned char ret = 1;
+
+ if (status & PARPORT_STATUS_BUSY) /* Busy */
+ ret &= ~1;
+ if (status & PARPORT_STATUS_ACK) /* Ack */
+ /* handled in hardware */;
+ if (status & PARPORT_STATUS_PAPEROUT) /* PaperOut */
+ ret |= 2;
+ if (status & PARPORT_STATUS_SELECT) /* select */
+ ret |= 4;
+ if (status & PARPORT_STATUS_ERROR) /* error */
+ /* not connected */;
+ return ret;
+}
+
+static unsigned char status_amiga_to_pc(unsigned char status)
+{
+ unsigned char ret = PARPORT_STATUS_BUSY | PARPORT_STATUS_ACK | PARPORT_STATUS_ERROR;
+
+ if (status & 1) /* Busy */
+ ret &= ~PARPORT_STATUS_BUSY;
+ if (status & 2) /* PaperOut */
+ ret |= PARPORT_STATUS_PAPEROUT;
+ if (status & 4) /* Selected */
+ ret |= PARPORT_STATUS_SELECT;
+ /* the rest is not connected or handled autonomously in hardware */
+
+ return ret;
+}
+
+static void amiga_write_status( struct parport *p, unsigned char status)
+{
+DPRINTK("write_status %02x\n",status);
+ ciab.pra |= (ciab.pra & 0xf8) | status_pc_to_amiga(status);
+}
+
+static unsigned char amiga_read_status(struct parport *p)
+{
+ unsigned char status;
+
+ status = status_amiga_to_pc(ciab.pra & 7);
+DPRINTK("read_status %02x\n", status);
+ return status;
+}
+
+static void amiga_change_mode( struct parport *p, int m)
+{
+ /* XXX: This port only has one mode, and I am
+ not sure about the corresponding PC-style mode*/
+}
+
+/* as this ports irq handling is already done, we use a generic funktion */
+
+static void amiga_release_resources(struct parport *p)
+{
+DPRINTK("realease_resources\n");
+ if (p->irq != PARPORT_IRQ_NONE)
+ free_irq(IRQ_AMIGA_CIAA_FLG, p);
+}
+
+static int amiga_claim_resources(struct parport *p)
+{
+DPRINTK("claim_resources\n");
+ return request_irq(IRQ_AMIGA_CIAA_FLG, parport_intr_func, 0, p->name, p);
+}
+
+static void amiga_init_state(struct parport_state *s)
+{
+ s->u.amiga.data = 0;
+ s->u.amiga.datadir = 255;
+ s->u.amiga.status = 0;
+ s->u.amiga.statusdir = 0;
+}
+
+static void amiga_save_state(struct parport *p, struct parport_state *s)
+{
+ s->u.amiga.data = ciaa.prb;
+ s->u.amiga.datadir = ciaa.ddrb;
+ s->u.amiga.status = ciab.pra & 7;
+ s->u.amiga.statusdir = ciab.ddra & 7;
+}
+
+static void amiga_restore_state(struct parport *p, struct parport_state *s)
+{
+ ciaa.prb = s->u.amiga.data;
+ ciaa.ddrb = s->u.amiga.datadir;
+ ciab.pra |= (ciab.pra & 0xf8) | s->u.amiga.status;
+ ciab.ddra |= (ciab.ddra & 0xf8) | s->u.amiga.statusdir;
+}
+
+static void amiga_enable_irq(struct parport *p)
+{
+ enable_irq(IRQ_AMIGA_CIAA_FLG);
+}
+
+static void amiga_disable_irq(struct parport *p)
+{
+ disable_irq(IRQ_AMIGA_CIAA_FLG);
+}
+
+static void amiga_inc_use_count(void)
+{
+ MOD_INC_USE_COUNT;
+}
+
+static void amiga_dec_use_count(void)
+{
+ MOD_DEC_USE_COUNT;
+}
+
+static struct parport_operations pp_amiga_ops = {
+ amiga_write_data,
+ amiga_read_data,
+
+ amiga_write_control,
+ amiga_read_control,
+ amiga_frob_control,
+
+ NULL, /* write_econtrol */
+ NULL, /* read_econtrol */
+ NULL, /* frob_econtrol */
+
+ amiga_write_status,
+ amiga_read_status,
+
+ NULL, /* write fifo */
+ NULL, /* read fifo */
+
+ amiga_change_mode,
+
+
+ amiga_release_resources,
+ amiga_claim_resources,
+
+
+ NULL, /* epp_write_data */
+ NULL, /* epp_read_data */
+ NULL, /* epp_write_addr */
+ NULL, /* epp_read_addr */
+ NULL, /* epp_check_timeout */
+
+ NULL, /* epp_write_block */
+ NULL, /* epp_read_block */
+
+ NULL, /* ecp_write_block */
+ NULL, /* ecp_read_block */
+
+ amiga_init_state,
+ amiga_save_state,
+ amiga_restore_state,
+
+ amiga_enable_irq,
+ amiga_disable_irq,
+ NULL, /* change_irq */
+
+ amiga_inc_use_count,
+ amiga_dec_use_count
+};
+
+/* ----------- Initialisation code --------------------------------- */
+
+__initfunc(int parport_amiga_init(void))
+{
+ struct parport *p;
+
+ if (MACH_IS_AMIGA && AMIGAHW_PRESENT(AMI_PARALLEL)) {
+ ciaa.ddrb = 0xff;
+ ciab.ddra &= 0xf8;
+ if (!(p = parport_register_port((unsigned long)&ciaa.prb,
+ IRQ_AMIGA_CIAA_FLG, PARPORT_DMA_NONE,
+ &pp_amiga_ops)))
+ return 0;
+ this_port = p;
+ printk(KERN_INFO "%s: Amiga built-in port using irq\n", p->name);
+ /* XXX: set operating mode */
+ parport_proc_register(p);
+ p->flags |= PARPORT_FLAG_COMA;
+
+ if (parport_probe_hook)
+ (*parport_probe_hook)(p);
+ return 1;
+
+ }
+ return 0;
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+ return ! parport_amiga_init();
+}
+
+void cleanup_module(void)
+{
+ if (!(this_port->flags & PARPORT_FLAG_COMA))
+ parport_quiesce(this_port);
+ parport_proc_unregister(this_port);
+ parport_unregister_port(this_port);
+}
+#endif
+
+
--- ./drivers/misc/parport_mfc3.c.old Sun Sep 20 04:47:33 1998
+++ ./drivers/misc/parport_mfc3.c Sun Sep 27 14:03:47 1998
@@ -0,0 +1,404 @@
+/* Low-level parallel port routines for the Multiface 3 card
+ *
+ * Author: Joerg Dorchain <dorc...@wirbel.com>
+ *
+ * (C) The elitist m68k Users(TM)
+ *
+ * based on the existing parport_amiga and lp_mfc
+ *
+ *
+ * From the MFC3 documentation:
+ *
+ * Miscellaneous PIA Details
+ * -------------------------
+ *
+ * The two open-drain interrupt outputs /IRQA and /IRQB are routed to
+ * /INT2 of the Z2 bus.
+ *
+ * The CPU data bus of the PIA (D0-D7) is connected to D8-D15 on the Z2
+ * bus. This means that any PIA registers are accessed at even addresses.
+ *
+ * Centronics Pin Connections for the PIA
+ * --------------------------------------
+ *
+ * The following table shows the connections between the PIA and the
+ * Centronics interface connector. These connections implement a single, but
+ * very complete, Centronics type interface. The Pin column gives the pin
+ * numbers of the PIA. The Centronics pin numbers can be found in the section
+ * "Parallel Connectors".
+ *
+ *
+ * Pin | PIA | Dir | Centronics Names
+ * -------+-----+-----+---------------------------------------------------------
+ * 19 | CB2 | --> | /STROBE (aka /DRDY)
+ * 10-17 | PBx | <-> | DATA0 - DATA7
+ * 18 | CB1 | <-- | /ACK
+ * 40 | CA1 | <-- | BUSY
+ * 3 | PA1 | <-- | PAPER-OUT (aka POUT)
+ * 4 | PA2 | <-- | SELECTED (aka SEL)
+ * 9 | PA7 | --> | /INIT (aka /RESET or /INPUT-PRIME)
+ * 6 | PA4 | <-- | /ERROR (aka /FAULT)
+ * 7 | PA5 | --> | DIR (aka /SELECT-IN)
+ * 8 | PA6 | --> | /AUTO-FEED-XT
+ * 39 | CA2 | --> | open
+ * 5 | PA3 | <-- | /ACK (same as CB1!)
+ * 2 | PA0 | <-- | BUSY (same as CA1!)
+ * -------+-----+-----+---------------------------------------------------------
+ *
+ * Should be enough to understand some of the driver.
+ */
+
+#include "multiface.h"
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/parport.h>
+#include <linux/delay.h>
+#include <linux/mc6821.h>
+#include <linux/zorro.h>
+#include <asm/setup.h>
+#include <asm/amigahw.h>
+#include <asm/irq.h>
+#include <asm/amigaints.h>
+
+/* Maximum Number of Cards supported */
+#define MAX_MFC 5
+
+#undef DEBUG
+#ifdef DEBUG
+#define DPRINTK printk
+#else
+static inline int DPRINTK() {return 0;}
+#endif
+
+static struct parport *this_port[MAX_MFC] = {NULL, };
+static volatile int dummy; /* for trigger readds */
+
+#define pia(dev) ((struct pia *)(dev->base))
+static struct parport_operations pp_mfc3_ops;
+
+static void mfc3_write_data(struct parport *p, unsigned char data)
+{
+DPRINTK("write_data %c\n",data);
+
+ dummy = pia(p)->pprb; /* clears irq bit */
+ /* Triggers also /STROBE.*/
+ pia(p)->pprb = data;
+}
+
+static unsigned char mfc3_read_data(struct parport *p)
+{
+ /* clears interupt bit. Triggers also /STROBE. */
+ return pia(p)->pprb;
+}
+
+static unsigned char control_pc_to_mfc3(unsigned char control)
+{
+ unsigned char ret = 32|64;
+
+ if (control & PARPORT_CONTROL_DIRECTION) /* XXX: What is this? */
+ ;
+ if (control & PARPORT_CONTROL_INTEN) /* XXX: What is INTEN? */
+ ;
+ if (control & PARPORT_CONTROL_SELECT) /* XXX: What is SELECP? */
+ ret &= ~32; /* /SELECT_IN */
+ if (control & PARPORT_CONTROL_INIT) /* INITP */
+ ret |= 128;
+ if (control & PARPORT_CONTROL_AUTOFD) /* AUTOLF */
+ ret &= ~64;
+ if (control & PARPORT_CONTROL_STROBE) /* Strobe */
+ /* Handled directly by hardware */;
+ return ret;
+}
+
+static unsigned char control_mfc3_to_pc(unsigned char control)
+{
+ unsigned char ret = PARPORT_CONTROL_INTEN | PARPORT_CONTROL_STROBE
+ | PARPORT_CONTROL_AUTOFD | PARPORT_CONTROL_SELECT;
+
+ if (control & 128) /* /INITP */
+ ret |= PARPORT_CONTROL_INIT;
+ if (control & 64) /* /AUTOLF */
+ ret &= ~PARPORT_CONTROL_AUTOFD;
+ if (control & 32) /* /SELECT_IN */
+ ret &= ~PARPORT_CONTROL_SELECT;
+ return ret;
+}
+
+static void mfc3_write_control(struct parport *p, unsigned char control)
+{
+DPRINTK("write_control %02x\n",control);
+ pia(p)->ppra = (pia(p)->ppra & 0x1f) | control_pc_to_mfc3(control);
+}
+
+static unsigned char mfc3_read_control( struct parport *p)
+{
+DPRINTK("read_control \n");
+ return control_mfc3_to_pc(pia(p)->ppra & 0xe0);
+}
+
+static unsigned char mfc3_frob_control( struct parport *p, unsigned char mask, unsigned char val)
+{
+ unsigned char old;
+
+DPRINTK("frob_control mask %02x, value %02x\n",mask,val);
+ old = mfc3_read_control(p);
+ mfc3_write_control(p, (old & ~mask) ^ val);
+ return old;
+}
+
+
+static unsigned char status_pc_to_mfc3(unsigned char status)
+{
+ unsigned char ret = 1;
+
+ if (status & PARPORT_STATUS_BUSY) /* Busy */
+ ret &= ~1;
+ if (status & PARPORT_STATUS_ACK) /* Ack */
+ ret |= 8;
+ if (status & PARPORT_STATUS_PAPEROUT) /* PaperOut */
+ ret |= 2;
+ if (status & PARPORT_STATUS_SELECT) /* select */
+ ret |= 4;
+ if (status & PARPORT_STATUS_ERROR) /* error */
+ ret |= 16;
+ return ret;
+}
+
+static unsigned char status_mfc3_to_pc(unsigned char status)
+{
+ unsigned char ret = PARPORT_STATUS_BUSY;
+
+ if (status & 1) /* Busy */
+ ret &= ~PARPORT_STATUS_BUSY;
+ if (status & 2) /* PaperOut */
+ ret |= PARPORT_STATUS_PAPEROUT;
+ if (status & 4) /* Selected */
+ ret |= PARPORT_STATUS_SELECT;
+ if (status & 8) /* Ack */
+ ret |= PARPORT_STATUS_ACK;
+ if (status & 16) /* /ERROR */
+ ret |= PARPORT_STATUS_ERROR;
+
+ return ret;
+}
+
+static void mfc3_write_status( struct parport *p, unsigned char status)
+{
+DPRINTK("write_status %02x\n",status);
+ pia(p)->ppra = (pia(p)->ppra & 0xe0) | status_pc_to_mfc3(status);
+}
+
+static unsigned char mfc3_read_status(struct parport *p)
+{
+ unsigned char status;
+
+ status = status_mfc3_to_pc(pia(p)->ppra & 0x1f);
+DPRINTK("read_status %02x\n", status);
+ return status;
+}
+
+static void mfc3_change_mode( struct parport *p, int m)
+{
+ /* XXX: This port only has one mode, and I am
+ not sure about the corresponding PC-style mode*/
+}
+
+static int use_cnt = 0;
+
+static void mfc3_intr_func(int irq, void *dev_id, struct pt_regs *regs)
+{
+ int i;
+
+ for( i = 0; i < MAX_MFC; i++)
+ if (this_port[i] != NULL)
+ if (pia(this_port[i])->crb & 128) { /* Board caused interrupt */
+ dummy = pia(this_port[i])->pprb; /* clear irq bit */
+ parport_intr_func(irq, this_port[i], regs);
+ }
+}
+
+static void mfc3_release_resources(struct parport *p)
+{
+DPRINTK("realease_resources\n");
+ if (p->irq != PARPORT_IRQ_NONE)
+ if (--use_cnt == 0)
+ free_irq(IRQ_AMIGA_PORTS, &pp_mfc3_ops);
+}
+
+static int mfc3_claim_resources(struct parport *p)
+{
+DPRINTK("claim_resources\n");
+ if (p->irq != PARPORT_IRQ_NONE)
+ if (use_cnt++ == 0)
+ if (request_irq(IRQ_AMIGA_PORTS, mfc3_intr_func, 0, p->name, &pp_mfc3_ops))
+ return use_cnt--;
+ return 0;
+}
+
+static void mfc3_init_state(struct parport_state *s)
+{
+ s->u.amiga.data = 0;
+ s->u.amiga.datadir = 255;
+ s->u.amiga.status = 0;
+ s->u.amiga.statusdir = 0xe0;
+}
+
+static void mfc3_save_state(struct parport *p, struct parport_state *s)
+{
+ s->u.amiga.data = pia(p)->pprb;
+ pia(p)->crb &= ~PIA_DDR;
+ s->u.amiga.datadir = pia(p)->pddrb;
+ pia(p)->crb |= PIA_DDR;
+ s->u.amiga.status = pia(p)->ppra;
+ pia(p)->cra &= ~PIA_DDR;
+ s->u.amiga.statusdir = pia(p)->pddrb;
+ pia(p)->cra |= PIA_DDR;
+}
+
+static void mfc3_restore_state(struct parport *p, struct parport_state *s)
+{
+ pia(p)->pprb = s->u.amiga.data;
+ pia(p)->crb &= ~PIA_DDR;
+ pia(p)->pddrb = s->u.amiga.datadir;
+ pia(p)->crb |= PIA_DDR;
+ pia(p)->ppra = s->u.amiga.status;
+ pia(p)->cra &= ~PIA_DDR;
+ pia(p)->pddrb = s->u.amiga.statusdir;
+ pia(p)->cra |= PIA_DDR;
+}
+
+static void mfc3_enable_irq(struct parport *p)
+{
+ pia(p)->crb |= PIA_C1_ENABLE_IRQ;
+}
+
+static void mfc3_disable_irq(struct parport *p)
+{
+ pia(p)->crb &= ~PIA_C1_ENABLE_IRQ;
+}
+
+static void mfc3_inc_use_count(void)
+{
+ MOD_INC_USE_COUNT;
+}
+
+static void mfc3_dec_use_count(void)
+{
+ MOD_DEC_USE_COUNT;
+}
+
+static struct parport_operations pp_mfc3_ops = {
+ mfc3_write_data,
+ mfc3_read_data,
+
+ mfc3_write_control,
+ mfc3_read_control,
+ mfc3_frob_control,
+
+ NULL, /* write_econtrol */
+ NULL, /* read_econtrol */
+ NULL, /* frob_econtrol */
+
+ mfc3_write_status,
+ mfc3_read_status,
+
+ NULL, /* write fifo */
+ NULL, /* read fifo */
+
+ mfc3_change_mode,
+
+
+ mfc3_release_resources,
+ mfc3_claim_resources,
+
+
+ NULL, /* epp_write_data */
+ NULL, /* epp_read_data */
+ NULL, /* epp_write_addr */
+ NULL, /* epp_read_addr */
+ NULL, /* epp_check_timeout */
+
+ NULL, /* epp_write_block */
+ NULL, /* epp_read_block */
+
+ NULL, /* ecp_write_block */
+ NULL, /* ecp_read_block */
+
+ mfc3_init_state,
+ mfc3_save_state,
+ mfc3_restore_state,
+
+ mfc3_enable_irq,
+ mfc3_disable_irq,
+ NULL, /* change_irq */
+
+ mfc3_inc_use_count,
+ mfc3_dec_use_count
+};
+
+/* ----------- Initialisation code --------------------------------- */
+
+__initfunc(int parport_mfc3_init(void))
+{
+ struct parport *p;
+ int pias = 0;
+ struct pia *pp;
+ unsigned int key = 0;
+ const struct ConfigDev *cd;
+
+ if (MACH_IS_AMIGA) {
+ while ((key = zorro_find(ZORRO_PROD_BSC_MULTIFACE_III, 0, key))) {
+ cd = zorro_get_board(key);
+ pp = (struct pia *)ZTWO_VADDR((((u_char *)cd->cd_BoardAddr)+PIABASE));
+ if (pias < MAX_MFC) {
+ pp->crb = 0;
+ pp->pddrb = 255; /* all data pins output */
+ pp->crb = PIA_DDR|32|8;
+ dummy = pp->pddrb; /* reading clears interrupt */
+ pp->cra = 0;
+ pp->pddra = 0xe0; /* /RESET, /DIR ,/AUTO-FEED output */
+ pp->cra = PIA_DDR;
+ pp->ppra = 0; /* reset printer */
+ udelay(10);
+ pp->ppra = 128;
+ if ((p = parport_register_port((unsigned long)pp,
+ IRQ_AMIGA_PORTS, PARPORT_DMA_NONE,
+ &pp_mfc3_ops))) {
+ this_port[pias++] = p;
+ printk(KERN_INFO "%s: Multiface III port using irq\n", p->name);
+ /* XXX: set operating mode */
+ parport_proc_register(p);
+ p->flags |= PARPORT_FLAG_COMA;
+ if (parport_probe_hook)
+ (*parport_probe_hook)(p);
+ zorro_config_board(key, 0);
+ p->private_data = (void *)key;
+ }
+ }
+ }
+ }
+ return pias;
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+ return ! parport_mfc3_init();
+}
+
+void cleanup_module(void)
+{
+ int i;
+
+ for (i = 0; i < MAX_MFC; i++)
+ if (this_port[i] != NULL) {
+ if (!(this_port[i]->flags & PARPORT_FLAG_COMA))
+ parport_quiesce(this_port[i]);
+ parport_proc_unregister(this_port[i]);
+ parport_unregister_port(this_port[i]);
+ zorro_unconfig_board((unsigned int)this_port[i]->private_data, 0);
+ }
+}
+#endif
+
+
--- ./drivers/misc/multiface.h.old Sun Sep 20 14:43:19 1998
+++ ./drivers/misc/multiface.h Sun Sep 20 14:43:07 1998
@@ -0,0 +1,20 @@
+#ifndef _MULTIFACE_H_
+#define _MULTIFACE_H_
+
+/*
+ * Defines for SerialMaster, Multiface Card II and Multiface Card III
+ * The addresses given below are offsets to the board base address
+ *
+ * 6.11.95 Joerg Dorchain (dorc...@mpi-sb.mpg.de)
+ *
+ */
+
+#define PIA_REG_PADWIDTH 255
+
+#define DUARTBASE 0x0000
+#define PITBASE 0x0100
+#define ROMBASE 0x0200
+#define PIABASE 0x4000
+
+#endif
+
--- ./include/linux/parport.h.old Mon Aug 10 17:38:36 1998
+++ ./include/linux/parport.h Sun Sep 27 14:01:10 1998
@@ -78,11 +78,20 @@
unsigned int ecr;
};

+/* used by both parport_amiga and parport_mfc3 */
+struct amiga_parport_state {
+ unsigned char data; /* ciaa.prb */
+ unsigned char datadir; /* ciaa.ddrb */
+ unsigned char status; /* ciab.pra & 7 */
+ unsigned char statusdir;/* ciab.ddrb & 7 */
+};
+
struct parport_state {
union {
struct pc_parport_state pc;
/* ARC has no state. */
/* AX uses same state information as PC */
+ struct amiga_parport_state amiga;
void *misc;
} u;
};
@@ -123,7 +132,7 @@

void (*enable_irq)(struct parport *);
void (*disable_irq)(struct parport *);
- int (*examine_irq)(struct parport *);
+ int (*change_irq)(struct parport *,int newirq);

void (*inc_use_count)(void);
void (*dec_use_count)(void);
@@ -293,6 +302,9 @@
parport_release(dev);
return parport_claim_or_block(dev);
}
+
+/* irq helper function */
+extern void parport_intr_func(int irq, void *dev_id, struct pt_regs *regs);

/* Flags used to identify what a device does. */
#define PARPORT_DEV_TRAN 0x0000 /* We're transient. */
--- ./include/linux/lp.h.old Sun Sep 27 13:57:03 1998
+++ ./include/linux/lp.h Sun Sep 27 15:02:48 1998
@@ -47,7 +47,12 @@
* I'll initialize it to 0.
*/

+#if defined(__sparc__) || defined(__mc68000__)
+/* These machines need some extra delay */
+#define LP_INIT_WAIT 1
+#else
#define LP_INIT_WAIT 0
+#endif

/* This is the amount of time that the driver waits for the printer to
* catch up when the printer's buffer appears to be filled. If you


0 new messages