[PARPORT] Amiga-Parport-driver


Joerg Dorchain (dorchain@wirbel.com)
Thu, 27 Aug 1998 11:16:34 +0200 (MET DST)


Hi all,

I currently spent my holidays doing a parport driver for the Amiga
built-in port. Based on that, the other existing m68k-printer-driver
should be easily adapted to support at least printing.

Consider it beta. I works for me (with a Star SG-10 ancient
dot-matrix-printer and a HP DeskJet 660C). The main problem was (is) that
the current parport is very PC-oriented when it comes to the hardware.
Although I got the PC-parallel-port programming description from the Web,
I still don't understand all the functions that a hardware driver has to
provide. (e.g. the amiga does handshaking in hardware, which is about the
same as EPP handshake, but supports fewer lines). I have the feel that a
function asking the driver for the hardware capabilities is missing (Or
didn't I see it? Or is it not fitting our case?)

The next driver I am trying to will be the MFC-III prarallel port. Ok,
simple printing will work within one day, but this card has really every
signal pin programmable, by software or to do some automatic hardware
handshake. It should be able to do plip or parallel ZIP-drives or even
some more. But I could need a more specific describtion of the
PC-hardware and to functions provided by the driver accessing it.
Can someone point me to it?

Please try this patch and report errors (succeses also!). The usual "if
it blows your PC..." disclaimer applies.

Oh, before I forget, this is relative to 2.1.115 (hi Franky!), but shuld
apply to other recent kernels without bigger rejects.

Have fun,

Joerg

--- ./arch/m68k/config.in.old Fri Jan 13 11:10:52 1978
+++ ./arch/m68k/config.in Wed Dec 10 17:42:27 1902
@@ -102,6 +102,15 @@
   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
+ fi
+ fi
+fi
 endmenu
 
 source drivers/block/Config.in
@@ -266,9 +275,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 Jan 15 12:02:25 1978
+++ ./drivers/char/lp.c Thu Aug 27 09:27:37 1998
@@ -211,7 +211,7 @@
 #endif
         /* must wait before taking strobe high, and after taking strobe
            low, according spec. Some printers need it, others don't. */
-#ifndef __sparc__
+#if !defined(__sparc__) && !defined(__mc68000__)
         while (wait != LP_WAIT(minor)) /* FIXME: should be a udelay() */
                 wait++;
 #else
@@ -219,7 +219,7 @@
 #endif
         /* control port takes strobe high */
         w_ctr(minor, LP_PSELECP | LP_PINITP | LP_PSTROBE);
-#ifndef __sparc__
+#if !defined(__sparc__) && !defined(__mc68000__)
         while (wait) /* FIXME: should be a udelay() */
                 wait--;
 #else
@@ -316,6 +316,7 @@
         unsigned long total_bytes_written = 0;
         unsigned long bytes_written;
         struct lp_struct *lp = &lp_table[minor];
+ unsigned long flags;
 
         if (minor >= LP_NO)
                 return -ENXIO;
@@ -384,6 +385,11 @@
                                         current->timeout = jiffies + LP_TIME(minor);
                                         lp_schedule (minor);
                                 } else {
+ /* Replace cli()/sti() by
+ cli()/restore_flags.
+ It's a must for other architectures
+ and doesn't break i386 */
+ save_flags(flags);
                                         cli();
                                         if (LP_PREEMPTED(minor))
                                         {
@@ -394,7 +400,7 @@
                                                  * envinroment to avoid parport sharing
                                                  * starvation.
                                                  */
- sti();
+ restore_flags(flags);
                                                 goto lp_polling;
                                         }
                                         if (!lp_table[minor].irq_detected)
@@ -402,7 +408,7 @@
                                                 current->timeout = jiffies + LP_TIMEOUT_INTERRUPT;
                                                 interruptible_sleep_on(&lp->wait_q);
                                         }
- sti();
+ restore_flags(flags);
                                 }
                         }
                 }
--- ./drivers/misc/Makefile.old Fri Jan 13 11:42:23 1978
+++ ./drivers/misc/Makefile Fri Jan 13 11:43:58 1978
@@ -37,6 +37,13 @@
       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
   LX_OBJS += parport_init.o
 else
   ifeq ($(CONFIG_PARPORT),m)
@@ -52,6 +59,9 @@
   endif
   ifeq ($(CONFIG_PARPORT_AX),m)
     M_OBJS += parport_ax.o
+ endif
+ ifeq ($(CONFIG_PARPORT_AMIGA),m)
+ M_OBJS += parport_amiga.o
   endif
 endif
 
--- ./drivers/misc/parport_amiga.c.old Sun Jan 15 12:39:35 1978
+++ ./drivers/misc/parport_amiga.c Thu Aug 27 09:04:34 1998
@@ -0,0 +1,299 @@
+/* Low-level parallel port routines for the Amiga buildin port
+ *
+ * Author: Joerg Dorchain <dorchain@wirbel.com>
+ *
+ * This is a complete rewrite of the code, but based heaviy upon the old
+ * lp_intern.c code.
+ */
+
+#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 void amiga_write_data(struct parport *p, unsigned char data)
+{
+DPRINTK("write_data %c\n",data);
+ ciaa.prb = data;
+}
+
+static unsigned char amiga_read_data(struct parport *p)
+{
+ return ciaa.prb;
+}
+
+#if 0
+static unsigned char control_pc_to_amiga(unsigned char control)
+{
+ unsigned char ret = 0;
+
+ if (control & 0x10) /* XXX: What is INTEN? */
+ ;
+ if (control & 0x08) /* XXX: What is SELECP? */
+ ;
+ if (control & 0x04) /* INITP */
+ /* reset connected to cpu reset pin */;
+ if (control & 0x02) /* AUTOLF */
+ /* Not connected */;
+ if (control & 0x01) /* Strobe */
+ /* Handled only directly by hardware */;
+ return ret;
+}
+#endif
+
+static unsigned char control_amiga_to_pc(unsigned char control)
+{
+ return 0x1b;
+ /* fake value: interrupt enable, select in, no reset,
+ no autolf, no strobe - seems to be closet the 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 & 0x80) /* Busy */
+ ret &= ~1;
+ if (status & 0x40) /* Ack */
+ /* handled in hardware */;
+ if (status & 0x20) /* PaperOut */
+ ret |= 2;
+ if (status & 0x10) /* select */
+ ret |= 4;
+ if (status & 0x08) /* error */
+ /* not connected */;
+ return ret;
+}
+
+static unsigned char status_amiga_to_pc(unsigned char status)
+{
+ unsigned char ret = 0x80 + 0x40 + 0x08;
+
+ if (status & 1) /* Busy */
+ ret &= ~0x80;
+ if (status & 2) /* PaperOut */
+ ret |= 0x20;
+ if (status & 4) /* Selected */
+ ret |= 0x10;
+ /* 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)
+{
+ /* What's this for? */
+}
+
+static void amiga_intr_func(int irq, void *dev_id, struct pt_regs *regs)
+{
+ /* nothing to do */
+}
+
+static void amiga_release_resources(struct parport *p)
+{
+DPRINTK("realease_resources\n");
+ free_irq(IRQ_AMIGA_CIAA_FLG, &ciaa.prb);
+}
+
+static int amiga_claim_resources(struct parport *p)
+{
+DPRINTK("claim_resources\n");
+ return request_irq(IRQ_AMIGA_CIAA_FLG, amiga_intr_func, 0, p->name, &ciaa.prb);
+}
+
+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 int amiga_examine_irq(struct parport *p)
+{
+ return 0; /* XXX Not possible */
+}
+
+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,
+ amiga_examine_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;
+ printk(KERN_INFO "%s: Amiga built-in port using irq\n", p->name);
+ 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)
+{
+ struct parport *p = parport_enumerate(), *next;
+
+ while (p) {
+ next = p->next;
+ if (p->ops == &pp_amiga_ops) {
+ if (!(p->flags & PARPORT_FLAG_COMA))
+ parport_quiesce(p);
+ parport_proc_unregister(p);
+ parport_unregister_port(p);
+ }
+ p = next;
+ }
+}
+#endif
+
+
--- ./drivers/misc/parport_init.c.old Sun Jan 15 12:41:54 1978
+++ ./drivers/misc/parport_init.c Sun Jan 15 12:44:21 1978
@@ -122,6 +122,9 @@
 #ifdef CONFIG_PARPORT_AX
         parport_ax_init();
 #endif
+#ifdef CONFIG_PARPORT_AMIGA
+ parport_amiga_init();
+#endif
         return 0;
 }
 #endif
--- ./include/linux/parport.h.old Wed Aug 26 09:55:29 1998
+++ ./include/linux/parport.h Wed Aug 26 10:16:07 1998
@@ -78,11 +78,19 @@
         unsigned int ecr;
 };
 
+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;
 };

-- To unsubscribe, send mail to: linux-parport-request@torque.net --
-- with the single word "unsubscribe" in the body of the message. --



This archive was generated by hypermail 2.0b3 on Wed 30 Dec 1998 - 10:18:08 EST