patch-2.4.25 linux-2.4.25/drivers/parport/parport_ip22.c

Next file: linux-2.4.25/drivers/pci/pci.ids
Previous file: linux-2.4.25/drivers/parport/Makefile
Back to the patch index
Back to the overall index

diff -urN linux-2.4.24/drivers/parport/parport_ip22.c linux-2.4.25/drivers/parport/parport_ip22.c
@@ -0,0 +1,313 @@
+/*
+ * Low-level parallel port routines for the SGI Indy/Indigo2 builtin port
+ *
+ * Copyright (c) 2002 Vincent Stehlé <vincent.stehle@free.fr>
+ * (shamelessly based on other parport_xxx.c)
+ * See the "COPYING" license file at the top-level.
+ *
+ * PI1 registers have the same bits as the PC parallel port registers, but
+ * all PI1 bits are "direct"; i.e. no invertion: A 1 is TTL "high" (5 V),
+ * a 0 is TTL "low" (0 V). There are also some bits on the PI1, which have
+ * no equivalents on the PC. They are for non-SPP modes.
+ *
+ * Here follows a little summary of the signals and their meanings:
+ *
+ * A "/" in front of a signal means that the _bit_ is inverted: i.e. a "1"
+ * bit value means a TTL "low" (0 V) signal.
+ *
+ * A "-" in front of a signal means that it is low active: i.e. a TTL "low"
+ * (0 V) value means that the signal is active.
+ *
+ * Internal only signals are between ()'s.
+ *
+ * Control
+ * -------
+ *                   PC                     SGI
+ *
+ * 7 6 5 4 3 2 1 0
+ *  \ \ \ \ \ \ \ `- /-STROBE               -STROBE
+ *   \ \ \ \ \ \ `-- /-AUTO FEED            -AFD
+ *    \ \ \ \ \ `---  -INIT                 -INIT
+ *     \ \ \ \ `---- /-SELECT               -SLIN
+ *      \ \ \ `----- (IRQ 1=enabled)
+ *       \ \ `------ (DIRECTION 0=forward)
+ *        \ `-------                        (SEL ?)
+ *         `--------
+ *
+ * Status
+ * ------
+ *                   PC                     SGI
+ *
+ * 7 6 5 4 3 2 1 0
+ *  \ \ \ \ \ \ \ `-                         DEVID
+ *   \ \ \ \ \ \ `--                          " "
+ *    \ \ \ \ \ `---                         NOINK
+ *     \ \ \ \ `----  -ERROR                -ERROR
+ *      \ \ \ `-----   SELECT IN             ONLINE
+ *       \ \ `------   PAPER END             PE
+ *        \ `-------  -ACK                  -ACK
+ *         `-------- / BUSY                  BUSY
+ *
+ * Note that some of those information have been "guessed" with a multimeter
+ * and some spare nights :)
+ *
+ * Reminder: all functions await PC-style values, i.e. one should convert
+ *           status and control.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/parport.h>
+#include <asm/sgi/ioc.h>
+#include <asm/sgi/pi1.h>
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DPRINTK printk
+#else
+#define DPRINTK(x...)	do { } while (0)
+#endif
+
+const unsigned char control_invert = PARPORT_CONTROL_STROBE
+	| PARPORT_CONTROL_AUTOFD | PARPORT_CONTROL_SELECT;
+const unsigned char status_invert = PARPORT_STATUS_BUSY;
+
+static struct parport *this_port = NULL;
+
+static inline void debug_dump_registers(void)
+{
+#ifdef DEBUG
+	printk(KERN_DEBUG
+		"PI1 registers:\n"
+		"             data= %02x\n"
+		"          control= %02x\n"
+		"           status= %02x\n"
+		"      dma control= %02x\n"
+		" interrupt status= %02x\n"
+		"   interrupt mask= %02x\n"
+		"          timer 1= %02x\n"
+		"          timer 2= %02x\n"
+		"          timer 3= %02x\n"
+		"          timer 4= %02x\n"
+		,
+		sgioc->pport.data,
+		sgioc->pport.ctrl,
+		sgioc->pport.status,
+		sgioc->pport.dmactrl,
+		sgioc->pport.intstat,
+		sgioc->pport.intmask,
+		sgioc->pport.timer1,
+		sgioc->pport.timer2,
+		sgioc->pport.timer3,
+		sgioc->pport.timer4
+	);
+#endif
+}
+
+static unsigned char pi1_read_data(struct parport *p)
+{
+	unsigned char data = sgioc->pport.data;
+	DPRINTK("pi1_read_data: %#x\n", data);
+	return data;
+}
+
+static void pi1_write_data(struct parport *p, unsigned char data)
+{
+	DPRINTK("pi1_write_data: %#x\n", data);
+	sgioc->pport.data = data;
+}
+
+static unsigned char pi1_read_control(struct parport *p)
+{
+	const unsigned char mask = PARPORT_CONTROL_STROBE
+		| PARPORT_CONTROL_AUTOFD | PARPORT_CONTROL_INIT
+		| PARPORT_CONTROL_SELECT;
+	unsigned char pctrl = sgioc->pport.ctrl,
+		control = ((pctrl & mask) ^ control_invert);
+	DPRINTK("pi1_read_control: %#x, %#x\n", pctrl, control);
+	return control;
+}
+
+static void pi1_write_control(struct parport *p, unsigned char control)
+{
+	const unsigned char mask = PARPORT_CONTROL_STROBE
+		| PARPORT_CONTROL_AUTOFD | PARPORT_CONTROL_INIT
+		| PARPORT_CONTROL_SELECT,
+	/* we enforce some necessary bits */
+		force = 0x30;
+	unsigned char pctrl = ((control & mask) ^ control_invert) | force;
+	DPRINTK("pi1_write_control: %#x, %#x\n", control, pctrl);
+	sgioc->pport.ctrl = pctrl;
+}
+
+static unsigned char pi1_frob_control(struct parport *p,
+	unsigned char mask, unsigned char val)
+{
+	unsigned char old;
+	DPRINTK(KERN_DEBUG "pi1_frob_control mask %02x, value %02x\n",mask,val);
+	old = pi1_read_control(p);
+	pi1_write_control(p, (old & ~mask) ^ val);
+	return old;
+}
+
+static unsigned char pi1_read_status(struct parport *p)
+{
+	const unsigned mask = PARPORT_STATUS_ERROR | PARPORT_STATUS_SELECT
+		| PARPORT_STATUS_PAPEROUT | PARPORT_STATUS_ACK
+		| PARPORT_STATUS_BUSY;
+	unsigned char pstat = sgioc->pport.status,
+		status = ((pstat & mask) ^ status_invert);
+	DPRINTK("pi1_read_status: %#x, %#x\n", pstat, status);
+	return status;
+}
+
+static void pi1_init_state(struct pardevice *d, struct parport_state *s)
+{
+	DPRINTK("pi1_init_state\n");
+}
+
+static void pi1_save_state(struct parport *p, struct parport_state *s)
+{
+	DPRINTK("pi1_save_state\n");
+}
+
+static void pi1_restore_state(struct parport *p, struct parport_state *s)
+{
+	DPRINTK("pi1_restore_state\n");
+}
+
+static void pi1_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	DPRINTK("pi1_interrupt\n");
+	parport_generic_irq(irq, (struct parport *) dev_id, regs);
+}
+
+static void pi1_enable_irq(struct parport *p)
+{
+	DPRINTK("pi1_enable_irq\n");
+}
+
+static void pi1_disable_irq(struct parport *p)
+{
+	DPRINTK("pi1_disable_irq\n");
+}
+
+static void pi1_data_forward(struct parport *p)
+{
+	DPRINTK("pi1_data_forward\n");
+	sgioc->pport.ctrl &= ~PI1_CTRL_DIR;
+}
+
+static void pi1_data_reverse(struct parport *p)
+{
+	DPRINTK("pi1_data_reverse\n");
+	sgioc->pport.ctrl |= PI1_CTRL_DIR;
+}
+
+static void pi1_inc_use_count(void)
+{
+	DPRINTK("pi1_inc_use_count\n");
+	MOD_INC_USE_COUNT;
+}
+
+static void pi1_dec_use_count(void)
+{
+	DPRINTK("pi1_dec_use_count\n");
+	MOD_DEC_USE_COUNT;
+}
+
+static struct parport_operations pi1_ops = {
+	pi1_write_data,
+	pi1_read_data,
+	pi1_write_control,
+	pi1_read_control,
+	pi1_frob_control,
+	pi1_read_status,
+	pi1_enable_irq,
+	pi1_disable_irq,
+	pi1_data_forward,
+	pi1_data_reverse,
+	pi1_init_state,
+	pi1_save_state,
+	pi1_restore_state,
+	pi1_inc_use_count,
+	pi1_dec_use_count,
+	parport_ieee1284_epp_write_data,
+	parport_ieee1284_epp_read_data,
+	parport_ieee1284_epp_write_addr,
+	parport_ieee1284_epp_read_addr,
+	parport_ieee1284_ecp_write_data,
+	parport_ieee1284_ecp_read_data,
+	parport_ieee1284_ecp_write_addr,
+	parport_ieee1284_write_compat,
+	parport_ieee1284_read_nibble,
+	parport_ieee1284_read_byte
+};
+
+static void init_hardware(void)
+{
+	sgioc->pport.intmask = 0xfc;
+	sgioc->pport.dmactrl = 1;
+	sgioc->pport.ctrl = 0x3f;
+	sgioc->pport.timer1 = 0;
+	sgioc->pport.timer2 = 0;
+	sgioc->pport.timer3 = 0;
+	sgioc->pport.timer4 = 0;
+	sgioc->pport.data = 0;
+}
+
+static int __init pi1_init(void)
+{
+	struct parport *p;
+
+	DPRINTK("pi1_init\n");
+	p = parport_register_port((unsigned long) &sgioc->pport.data,
+				  PARPORT_IRQ_NONE, PARPORT_DMA_NONE,
+				  &pi1_ops);
+	if (!p)
+		return -EBUSY;
+
+/* TODO
+	err = request_irq(IRQ_AMIGA_CIAA_FLG, amiga_interrupt, 0, p->name, p);
+	if (err)
+		goto out_irq;
+*/
+	
+	/* tell what we are capable of */
+	p->modes = PARPORT_MODE_PCSPP;
+
+/* TODO
+	 | PARPORT_MODE_TRISTATE;*/
+
+	/* remember for exit */
+	this_port = p;
+
+	/* put hardware into known initial state */
+	init_hardware();
+
+	printk(KERN_INFO "%s: SGI PI1\n", p->name);
+	parport_proc_register(p);
+	parport_announce_port(p);
+
+	return 0;
+}
+
+static void __exit pi1_exit(void)
+{
+	DPRINTK("pi1_exit\n");
+	if (this_port->irq != PARPORT_IRQ_NONE)
+		free_irq(this_port->irq, this_port);
+
+	parport_proc_unregister(this_port);
+	parport_unregister_port(this_port);
+}
+
+MODULE_AUTHOR("Vincent Stehle <vincent.stehle@free.fr>");
+MODULE_DESCRIPTION("Driver for SGI Indy/Indigo2 parallel port");
+MODULE_SUPPORTED_DEVICE("SGI PI1 parallel port");
+MODULE_LICENSE("GPL");
+
+module_init(pi1_init);
+module_exit(pi1_exit);

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)