Philip Blundell (philip@vger.rutgers.edu)
Sat, 27 Dec 1997 07:48:20 -0500 (EST)
Hi.
Here are the current parport patches against 2.1.76. Please check them
out; if there are no problems I'll try to get them merged into Linus'
tree.
p.
diff -u /vger/u4/philip/linus/linux/drivers/misc/Makefile /vger/u4/philip/linux/drivers/misc/Makefile
--- /vger/u4/philip/linus/linux/drivers/misc/Makefile Sat Nov 29 19:19:40 1997
+++ /vger/u4/philip/linux/drivers/misc/Makefile Mon Dec 22 05:35:37 1997
@@ -48,10 +48,10 @@
M_OBJS += parport.o
endif
ifeq ($(CONFIG_PARPORT_PC),m)
- MX_OBJS += parport_pc.o
+ M_OBJS += parport_pc.o
endif
ifeq ($(CONFIG_PARPORT_AX),m)
- MX_OBJS += parport_ax.o
+ M_OBJS += parport_ax.o
endif
endif
diff -u /vger/u4/philip/linus/linux/drivers/misc/parport_ax.c /vger/u4/philip/linux/drivers/misc/parport_ax.c
--- /vger/u4/philip/linus/linux/drivers/misc/parport_ax.c Sat Dec 6 14:58:23 1997
+++ /vger/u4/philip/linux/drivers/misc/parport_ax.c Mon Dec 22 05:35:38 1997
@@ -1,4 +1,4 @@
-/* $Id: parport_ax.c,v 1.2 1997/10/25 17:27:03 philip Exp $
+/* $Id: parport_ax.c,v 1.4 1997/12/22 01:49:27 ecd Exp $
* Parallel-port routines for Sun Ultra/AX architecture
*
* Author: Eddie C. Dost <ecd@skynet.be>
@@ -18,6 +18,7 @@
#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/malloc.h>
+#include <linux/init.h>
#include <linux/parport.h>
@@ -515,8 +516,13 @@
return 1;
}
-int
-parport_ax_init(void)
+EXPORT_NO_SYMBOLS;
+
+#ifdef MODULE
+int init_module(void)
+#else
+__initfunc(int parport_ax_init(void))
+#endif
{
struct linux_ebus *ebus;
struct linux_ebus_device *edev;
@@ -525,17 +531,10 @@
for_all_ebusdev(edev, ebus)
if (!strcmp(edev->prom_name, "ecpp"))
count += init_one_port(edev);
- return count;
+ return count ? 0 : -ENODEV;
}
#ifdef MODULE
-
-int
-init_module(void)
-{
- return (parport_ax_init() ? 0 : 1);
-}
-
void
cleanup_module(void)
{
diff -u /vger/u4/philip/linus/linux/drivers/misc/parport_ieee1284.c /vger/u4/philip/linux/drivers/misc/parport_ieee1284.c
--- /vger/u4/philip/linus/linux/drivers/misc/parport_ieee1284.c Mon Dec 1 14:06:01 1997
+++ /vger/u4/philip/linux/drivers/misc/parport_ieee1284.c Wed Dec 3 04:22:39 1997
@@ -1,4 +1,4 @@
-/* $Id: parport_ieee1284.c,v 1.4 1997/10/19 21:37:21 philip Exp $
+/* $Id: parport_ieee1284.c,v 1.5 1997/12/01 03:36:51 davem Exp $
* IEEE-1284 implementation for parport.
*
* Authors: Phil Blundell <Philip.Blundell@pobox.com>
diff -u /vger/u4/philip/linus/linux/drivers/misc/parport_init.c /vger/u4/philip/linux/drivers/misc/parport_init.c
--- /vger/u4/philip/linus/linux/drivers/misc/parport_init.c Sat Nov 29 19:19:41 1997
+++ /vger/u4/philip/linux/drivers/misc/parport_init.c Mon Dec 22 16:51:47 1997
@@ -68,8 +68,6 @@
#else
__initfunc(int parport_init(void))
{
- struct parport *pb;
-
if (io[0] == PARPORT_DISABLE)
return 1;
diff -u /vger/u4/philip/linus/linux/drivers/misc/parport_pc.c /vger/u4/philip/linux/drivers/misc/parport_pc.c
--- /vger/u4/philip/linus/linux/drivers/misc/parport_pc.c Sat Dec 6 14:58:23 1997
+++ /vger/u4/philip/linux/drivers/misc/parport_pc.c Mon Dec 22 17:02:26 1997
@@ -1,4 +1,4 @@
-/* Parallel-port routines for PC architecture
+/* Low-level parallel-port routines for PC-style hardware.
*
* Authors: Phil Blundell <Philip.Blundell@pobox.com>
* Tim Waugh <tim@cyberelk.demon.co.uk>
@@ -8,6 +8,28 @@
* based on work by Grant Guenther <grant@torque.net> and Phil Blundell.
*/
+/* This driver should work with any hardware that is broadly compatible
+ * with that in the IBM PC. This applies to the majority of integrated
+ * I/O chipsets that are commonly available. The expected register
+ * layout is:
+ *
+ * base+0 data
+ * base+1 status
+ * base+2 control
+ *
+ * In addition, there are some optional registers:
+ *
+ * base+3 EPP command
+ * base+4 EPP
+ * base+0x400 ECP config A
+ * base+0x401 ECP config B
+ * base+0x402 ECP control
+ *
+ * All registers are 8 bits wide and read/write. If your hardware differs
+ * only in register addresses (eg because your registers are on 32-bit
+ * word boundaries) then you can alter the constants below to accomodate this.
+ */
+
#include <linux/stddef.h>
#include <linux/tasks.h>
@@ -26,6 +48,8 @@
#include <linux/parport.h>
+/* --- register definitions ------------------------------- */
+
#define ECONTROL 0x402
#define CONFIGB 0x401
#define CONFIGA 0x400
@@ -34,225 +58,223 @@
#define STATUS 0x1
#define DATA 0
-#define PC_MAX_PORTS 8
+/* Maximum number of ports to support. It is useless to set this greater
+ than PARPORT_MAX (in <linux/parport.h>). */
+#define PARPORT_PC_MAX_PORTS 8
-static void pc_null_intr_func(int irq, void *dev_id, struct pt_regs *regs)
+static void parport_pc_null_intr_func(int irq, void *dev_id, struct pt_regs *regs)
{
/* NULL function - Does nothing */
return;
}
-#if 0
-static void pc_write_epp(struct parport *p, unsigned int d)
+void parport_pc_write_epp(struct parport *p, unsigned int d)
{
outb(d, p->base+EPPREG);
}
-#endif
-static unsigned int pc_read_epp(struct parport *p)
+unsigned int parport_pc_read_epp(struct parport *p)
{
return (unsigned int)inb(p->base+EPPREG);
}
-static unsigned int pc_read_configb(struct parport *p)
+unsigned int parport_pc_read_configb(struct parport *p)
{
return (unsigned int)inb(p->base+CONFIGB);
}
-static void pc_write_data(struct parport *p, unsigned int d)
+void parport_pc_write_data(struct parport *p, unsigned int d)
{
outb(d, p->base+DATA);
}
-static unsigned int pc_read_data(struct parport *p)
+unsigned int parport_pc_read_data(struct parport *p)
{
return (unsigned int)inb(p->base+DATA);
}
-static void pc_write_control(struct parport *p, unsigned int d)
+void parport_pc_write_control(struct parport *p, unsigned int d)
{
outb(d, p->base+CONTROL);
}
-static unsigned int pc_read_control(struct parport *p)
+unsigned int parport_pc_read_control(struct parport *p)
{
return (unsigned int)inb(p->base+CONTROL);
}
-static unsigned int pc_frob_control(struct parport *p, unsigned int mask, unsigned int val)
+unsigned int parport_pc_frob_control(struct parport *p, unsigned int mask, unsigned int val)
{
unsigned int old = (unsigned int)inb(p->base+CONTROL);
outb(((old & ~mask) ^ val), p->base+CONTROL);
return old;
}
-static void pc_write_status(struct parport *p, unsigned int d)
+void parport_pc_write_status(struct parport *p, unsigned int d)
{
outb(d, p->base+STATUS);
}
-static unsigned int pc_read_status(struct parport *p)
+unsigned int parport_pc_read_status(struct parport *p)
{
return (unsigned int)inb(p->base+STATUS);
}
-static void pc_write_econtrol(struct parport *p, unsigned int d)
+void parport_pc_write_econtrol(struct parport *p, unsigned int d)
{
outb(d, p->base+ECONTROL);
}
-static unsigned int pc_read_econtrol(struct parport *p)
+unsigned int parport_pc_read_econtrol(struct parport *p)
{
return (unsigned int)inb(p->base+ECONTROL);
}
-static unsigned int pc_frob_econtrol(struct parport *p, unsigned int mask, unsigned int val)
+unsigned int parport_pc_frob_econtrol(struct parport *p, unsigned int mask, unsigned int val)
{
unsigned int old = (unsigned int)inb(p->base+ECONTROL);
outb(((old & ~mask) ^ val), p->base+ECONTROL);
return old;
}
-static void pc_change_mode(struct parport *p, int m)
+void parport_pc_change_mode(struct parport *p, int m)
{
/* FIXME */
}
-static void pc_write_fifo(struct parport *p, unsigned int v)
+void parport_pc_write_fifo(struct parport *p, unsigned int v)
{
/* FIXME */
}
-static unsigned int pc_read_fifo(struct parport *p)
+unsigned int parport_pc_read_fifo(struct parport *p)
{
return 0; /* FIXME */
}
-static void pc_disable_irq(struct parport *p)
+void parport_pc_disable_irq(struct parport *p)
{
- /* FIXME */
+ parport_pc_frob_control(p, 0x10, 0);
}
-static void pc_enable_irq(struct parport *p)
+void parport_pc_enable_irq(struct parport *p)
{
- /* FIXME */
+ parport_pc_frob_control(p, 0x10, 0x10);
}
-static void pc_release_resources(struct parport *p)
+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);
}
-static int pc_claim_resources(struct parport *p)
+int parport_pc_claim_resources(struct parport *p)
{
/* FIXME check that resources are free */
if (p->irq != PARPORT_IRQ_NONE)
- request_irq(p->irq, pc_null_intr_func, 0, p->name, NULL);
+ request_irq(p->irq, parport_pc_null_intr_func, 0, p->name, p);
request_region(p->base, p->size, p->name);
if (p->modes & PARPORT_MODE_PCECR)
request_region(p->base+0x400, 3, p->name);
return 0;
}
-static void pc_save_state(struct parport *p, struct parport_state *s)
+void parport_pc_save_state(struct parport *p, struct parport_state *s)
{
- s->u.pc.ctr = pc_read_control(p);
- s->u.pc.ecr = pc_read_econtrol(p);
+ s->u.pc.ctr = parport_pc_read_control(p);
+ s->u.pc.ecr = parport_pc_read_econtrol(p);
}
-static void pc_restore_state(struct parport *p, struct parport_state *s)
+void parport_pc_restore_state(struct parport *p, struct parport_state *s)
{
- pc_write_control(p, s->u.pc.ctr);
- pc_write_econtrol(p, s->u.pc.ecr);
+ parport_pc_write_control(p, s->u.pc.ctr);
+ parport_pc_write_econtrol(p, s->u.pc.ecr);
}
-static unsigned int pc_epp_read_block(struct parport *p, void *buf, unsigned int length)
+unsigned int parport_pc_epp_read_block(struct parport *p, void *buf, unsigned int length)
{
return 0; /* FIXME */
}
-static unsigned int pc_epp_write_block(struct parport *p, void *buf, unsigned int length)
+unsigned int parport_pc_epp_write_block(struct parport *p, void *buf, unsigned int length)
{
return 0; /* FIXME */
}
-static unsigned int pc_ecp_read_block(struct parport *p, void *buf, unsigned int length, void (*fn)(struct parport *, void *, unsigned int), void *handle)
+unsigned int parport_pc_ecp_read_block(struct parport *p, void *buf, unsigned int length, void (*fn)(struct parport *, void *, unsigned int), void *handle)
{
return 0; /* FIXME */
}
-static unsigned int pc_ecp_write_block(struct parport *p, void *buf, unsigned int length, void (*fn)(struct parport *, void *, unsigned int), void *handle)
+unsigned int parport_pc_ecp_write_block(struct parport *p, void *buf, unsigned int length, void (*fn)(struct parport *, void *, unsigned int), void *handle)
{
return 0; /* FIXME */
}
-static int pc_examine_irq(struct parport *p)
+int parport_pc_examine_irq(struct parport *p)
{
return 0; /* FIXME */
}
-static void pc_inc_use_count(void)
+void parport_pc_inc_use_count(void)
{
#ifdef MODULE
MOD_INC_USE_COUNT;
#endif
}
-static void pc_dec_use_count(void)
+void parport_pc_dec_use_count(void)
{
#ifdef MODULE
MOD_DEC_USE_COUNT;
#endif
}
-static struct parport_operations pc_ops =
+struct parport_operations parport_pc_ops =
{
- pc_write_data,
- pc_read_data,
+ parport_pc_write_data,
+ parport_pc_read_data,
- pc_write_control,
- pc_read_control,
- pc_frob_control,
+ parport_pc_write_control,
+ parport_pc_read_control,
+ parport_pc_frob_control,
- pc_write_econtrol,
- pc_read_econtrol,
- pc_frob_econtrol,
+ parport_pc_write_econtrol,
+ parport_pc_read_econtrol,
+ parport_pc_frob_econtrol,
- pc_write_status,
- pc_read_status,
+ parport_pc_write_status,
+ parport_pc_read_status,
- pc_write_fifo,
- pc_read_fifo,
+ parport_pc_write_fifo,
+ parport_pc_read_fifo,
- pc_change_mode,
+ parport_pc_change_mode,
- pc_release_resources,
- pc_claim_resources,
+ parport_pc_release_resources,
+ parport_pc_claim_resources,
- pc_epp_write_block,
- pc_epp_read_block,
+ parport_pc_epp_write_block,
+ parport_pc_epp_read_block,
- pc_ecp_write_block,
- pc_ecp_read_block,
+ parport_pc_ecp_write_block,
+ parport_pc_ecp_read_block,
- pc_save_state,
- pc_restore_state,
+ parport_pc_save_state,
+ parport_pc_restore_state,
- pc_enable_irq,
- pc_disable_irq,
- pc_examine_irq,
+ parport_pc_enable_irq,
+ parport_pc_disable_irq,
+ parport_pc_examine_irq,
- pc_inc_use_count,
- pc_dec_use_count
+ parport_pc_inc_use_count,
+ parport_pc_dec_use_count
};
-/******************************************************
- * DMA detection section:
- */
+/* --- DMA detection -------------------------------------- */
/*
* Prepare DMA channels from 0-8 to transmit towards buffer
@@ -289,10 +311,10 @@
for (i = 0; i < 8; i++)
if (dma & (1 << i)) {
- cli();
- enable_dma(i);
- sti();
- }
+ cli();
+ enable_dma(i);
+ sti();
+ }
return dma;
}
@@ -325,13 +347,13 @@
/* Only if supports ECP mode */
static int programmable_dma_support(struct parport *pb)
{
- int dma, oldstate = pc_read_econtrol(pb);
+ int dma, oldstate = parport_pc_read_econtrol(pb);
- pc_write_econtrol(pb, 0xe0); /* Configuration MODE */
+ parport_pc_write_econtrol(pb, 0xe0); /* Configuration MODE */
- dma = pc_read_configb(pb) & 0x07;
+ dma = parport_pc_read_configb(pb) & 0x07;
- pc_write_econtrol(pb, oldstate);
+ parport_pc_write_econtrol(pb, oldstate);
if (dma == 0 || dma == 4) /* Jumper selection */
return PARPORT_DMA_NONE;
@@ -405,9 +427,7 @@
return retv;
}
-/******************************************************
- * MODE detection section:
- */
+/* --- Mode detection ------------------------------------- */
/*
* Clear TIMEOUT BIT in EPP MODE
@@ -416,15 +436,15 @@
{
int r;
- if (!(pc_read_status(pb) & 0x01))
+ if (!(parport_pc_read_status(pb) & 0x01))
return 1;
/* To clear timeout some chips require double read */
- pc_read_status(pb);
- r = pc_read_status(pb);
- pc_write_status(pb, r | 0x01); /* Some reset by writing 1 */
- pc_write_status(pb, r & 0xfe); /* Others by writing 0 */
- r = pc_read_status(pb);
+ parport_pc_read_status(pb);
+ r = parport_pc_read_status(pb);
+ parport_pc_write_status(pb, r | 0x01); /* Some reset by writing 1 */
+ parport_pc_write_status(pb, r & 0xfe); /* Others by writing 0 */
+ r = parport_pc_read_status(pb);
return !(r & 0x01);
}
@@ -436,12 +456,12 @@
static int parport_SPP_supported(struct parport *pb)
{
/* Do a simple read-write test to make sure the port exists. */
- pc_write_control(pb, 0xc);
- pc_write_data(pb, 0xaa);
- if (pc_read_data(pb) != 0xaa) return 0;
+ parport_pc_write_control(pb, 0xc);
+ parport_pc_write_data(pb, 0xaa);
+ if (parport_pc_read_data(pb) != 0xaa) return 0;
- pc_write_data(pb, 0x55);
- if (pc_read_data(pb) != 0x55) return 0;
+ parport_pc_write_data(pb, 0x55);
+ if (parport_pc_read_data(pb) != 0x55) return 0;
return PARPORT_MODE_PCSPP;
}
@@ -460,36 +480,36 @@
*/
static int parport_ECR_present(struct parport *pb)
{
- unsigned int r, octr = pc_read_control(pb),
- oecr = pc_read_econtrol(pb);
+ unsigned int r, octr = parport_pc_read_control(pb),
+ oecr = parport_pc_read_econtrol(pb);
- r = pc_read_control(pb);
- if ((pc_read_econtrol(pb) & 0x3) == (r & 0x3)) {
- pc_write_control(pb, r ^ 0x2 ); /* Toggle bit 1 */
-
- r = pc_read_control(pb);
- if ((pc_read_econtrol(pb) & 0x2) == (r & 0x2)) {
- pc_write_control(pb, octr);
+ r = parport_pc_read_control(pb);
+ if ((parport_pc_read_econtrol(pb) & 0x3) == (r & 0x3)) {
+ parport_pc_write_control(pb, r ^ 0x2 ); /* Toggle bit 1 */
+
+ r = parport_pc_read_control(pb);
+ if ((parport_pc_read_econtrol(pb) & 0x2) == (r & 0x2)) {
+ parport_pc_write_control(pb, octr);
return 0; /* Sure that no ECR register exists */
}
}
- if ((pc_read_econtrol(pb) & 0x3 ) != 0x1)
+ if ((parport_pc_read_econtrol(pb) & 0x3 ) != 0x1)
return 0;
- pc_write_econtrol(pb, 0x34);
- if (pc_read_econtrol(pb) != 0x35)
+ parport_pc_write_econtrol(pb, 0x34);
+ if (parport_pc_read_econtrol(pb) != 0x35)
return 0;
- pc_write_econtrol(pb, oecr);
- pc_write_control(pb, octr);
+ parport_pc_write_econtrol(pb, oecr);
+ parport_pc_write_control(pb, octr);
return PARPORT_MODE_PCECR;
}
static int parport_ECP_supported(struct parport *pb)
{
- int i, oecr = pc_read_econtrol(pb);
+ int i, oecr = parport_pc_read_econtrol(pb);
/* If there is no ECR, we have no hope of supporting ECP. */
if (!(pb->modes & PARPORT_MODE_PCECR))
@@ -500,11 +520,11 @@
* it doesn't support ECP or FIFO MODE
*/
- pc_write_econtrol(pb, 0xc0); /* TEST FIFO */
- for (i=0; i < 1024 && (pc_read_econtrol(pb) & 0x01); i++)
- pc_write_fifo(pb, 0xaa);
+ parport_pc_write_econtrol(pb, 0xc0); /* TEST FIFO */
+ for (i=0; i < 1024 && (parport_pc_read_econtrol(pb) & 0x01); i++)
+ parport_pc_write_fifo(pb, 0xaa);
- pc_write_econtrol(pb, oecr);
+ parport_pc_write_econtrol(pb, oecr);
return (i==1024)?0:PARPORT_MODE_PCECP;
}
@@ -526,14 +546,14 @@
if (!epp_clear_timeout(pb))
return 0; /* No way to clear timeout */
- pc_write_control(pb, pc_read_control(pb) | 0x20);
- pc_write_control(pb, pc_read_control(pb) | 0x10);
+ parport_pc_write_control(pb, parport_pc_read_control(pb) | 0x20);
+ parport_pc_write_control(pb, parport_pc_read_control(pb) | 0x10);
epp_clear_timeout(pb);
- pc_read_epp(pb);
+ parport_pc_read_epp(pb);
udelay(30); /* Wait for possible EPP timeout */
- if (pc_read_status(pb) & 0x01) {
+ if (parport_pc_read_status(pb) & 0x01) {
epp_clear_timeout(pb);
return PARPORT_MODE_PCEPP;
}
@@ -543,17 +563,17 @@
static int parport_ECPEPP_supported(struct parport *pb)
{
- int mode, oecr = pc_read_econtrol(pb);
+ int mode, oecr = parport_pc_read_econtrol(pb);
if (!(pb->modes & PARPORT_MODE_PCECR))
return 0;
/* Search for SMC style EPP+ECP mode */
- pc_write_econtrol(pb, 0x80);
+ parport_pc_write_econtrol(pb, 0x80);
mode = parport_EPP_supported(pb);
- pc_write_econtrol(pb, oecr);
+ parport_pc_write_econtrol(pb, oecr);
return mode?PARPORT_MODE_PCECPEPP:0;
}
@@ -577,42 +597,41 @@
static int parport_PS2_supported(struct parport *pb)
{
- int ok = 0, octr = pc_read_control(pb);
+ int ok = 0, octr = parport_pc_read_control(pb);
epp_clear_timeout(pb);
- pc_write_control(pb, octr | 0x20); /* try to tri-state the buffer */
+ parport_pc_write_control(pb, octr | 0x20); /* try to tri-state the buffer */
- pc_write_data(pb, 0x55);
- if (pc_read_data(pb) != 0x55) ok++;
+ parport_pc_write_data(pb, 0x55);
+ if (parport_pc_read_data(pb) != 0x55) ok++;
- pc_write_data(pb, 0xaa);
- if (pc_read_data(pb) != 0xaa) ok++;
+ parport_pc_write_data(pb, 0xaa);
+ if (parport_pc_read_data(pb) != 0xaa) ok++;
- pc_write_control(pb, octr); /* cancel input mode */
+ parport_pc_write_control(pb, octr); /* cancel input mode */
return ok?PARPORT_MODE_PCPS2:0;
}
static int parport_ECPPS2_supported(struct parport *pb)
{
- int mode, oecr = pc_read_econtrol(pb);
+ int mode, oecr = parport_pc_read_econtrol(pb);
if (!(pb->modes & PARPORT_MODE_PCECR))
return 0;
- pc_write_econtrol(pb, 0x20);
+ parport_pc_write_econtrol(pb, 0x20);
mode = parport_PS2_supported(pb);
- pc_write_econtrol(pb, oecr);
+ parport_pc_write_econtrol(pb, oecr);
return mode?PARPORT_MODE_PCECPPS2:0;
}
-/******************************************************
- * IRQ detection section:
- *
- * This code is for detecting ECP interrupts (due to problems with the
+/* --- IRQ detection -------------------------------------- */
+
+/* This code is for detecting ECP interrupts (due to problems with the
* monolithic interrupt probing routines).
*
* In short this is a voting system where the interrupt with the most
@@ -667,11 +686,11 @@
/* Only if supports ECP mode */
static int programmable_irq_support(struct parport *pb)
{
- int irq, oecr = pc_read_econtrol(pb);
+ int irq, oecr = parport_pc_read_econtrol(pb);
- pc_write_econtrol(pb,0xE0); /* Configuration MODE */
+ parport_pc_write_econtrol(pb,0xE0); /* Configuration MODE */
- irq = (pc_read_configb(pb) >> 3) & 0x07;
+ irq = (parport_pc_read_configb(pb) >> 3) & 0x07;
switch(irq){
case 2:
@@ -687,26 +706,26 @@
irq += 7;
}
- pc_write_econtrol(pb, oecr);
+ parport_pc_write_econtrol(pb, oecr);
return irq;
}
static int irq_probe_ECP(struct parport *pb)
{
- int irqs, i, oecr = pc_read_econtrol(pb);
+ int irqs, i, oecr = parport_pc_read_econtrol(pb);
probe_irq_off(probe_irq_on()); /* Clear any interrupts */
irqs = open_intr_election();
- pc_write_econtrol(pb, 0x00); /* Reset FIFO */
- pc_write_econtrol(pb, 0xd0); /* TEST FIFO + nErrIntrEn */
+ parport_pc_write_econtrol(pb, 0x00); /* Reset FIFO */
+ parport_pc_write_econtrol(pb, 0xd0); /* TEST FIFO + nErrIntrEn */
/* If Full FIFO sure that WriteIntrThresold is generated */
- for (i=0; i < 1024 && !(pc_read_econtrol(pb) & 0x02) ; i++)
- pc_write_fifo(pb, 0xaa);
+ for (i=0; i < 1024 && !(parport_pc_read_econtrol(pb) & 0x02) ; i++)
+ parport_pc_write_fifo(pb, 0xaa);
pb->irq = close_intr_election(irqs);
- pc_write_econtrol(pb, oecr);
+ parport_pc_write_econtrol(pb, oecr);
return pb->irq;
}
@@ -716,7 +735,7 @@
*/
static int irq_probe_EPP(struct parport *pb)
{
- int irqs, octr = pc_read_control(pb);
+ int irqs, octr = parport_pc_read_control(pb);
#ifndef ADVANCED_DETECT
return PARPORT_IRQ_NONE;
@@ -726,27 +745,27 @@
irqs = open_intr_election();
if (pb->modes & PARPORT_MODE_PCECR)
- pc_write_econtrol(pb, pc_read_econtrol(pb) | 0x10);
+ parport_pc_write_econtrol(pb, parport_pc_read_econtrol(pb) | 0x10);
epp_clear_timeout(pb);
- pc_write_control(pb, pc_read_control(pb) | 0x20);
- pc_write_control(pb, pc_read_control(pb) | 0x10);
+ parport_pc_write_control(pb, parport_pc_read_control(pb) | 0x20);
+ parport_pc_write_control(pb, parport_pc_read_control(pb) | 0x10);
epp_clear_timeout(pb);
/* Device isn't expecting an EPP read
* and generates an IRQ.
*/
- pc_read_epp(pb);
+ parport_pc_read_epp(pb);
udelay(20);
pb->irq = close_intr_election(irqs);
- pc_write_control(pb, octr);
+ parport_pc_write_control(pb, octr);
return pb->irq;
}
static int irq_probe_SPP(struct parport *pb)
{
- int irqs, octr = pc_read_control(pb);
+ int irqs, octr = parport_pc_read_control(pb);
#ifndef ADVANCED_DETECT
return PARPORT_IRQ_NONE;
@@ -756,26 +775,26 @@
irqs = probe_irq_on();
if (pb->modes & PARPORT_MODE_PCECR)
- pc_write_econtrol(pb, 0x10);
+ parport_pc_write_econtrol(pb, 0x10);
- pc_write_data(pb,0x00);
- pc_write_control(pb,0x00);
- pc_write_control(pb,0x0c);
+ parport_pc_write_data(pb,0x00);
+ parport_pc_write_control(pb,0x00);
+ parport_pc_write_control(pb,0x0c);
udelay(5);
- pc_write_control(pb,0x0d);
+ parport_pc_write_control(pb,0x0d);
udelay(5);
- pc_write_control(pb,0x0c);
+ parport_pc_write_control(pb,0x0c);
udelay(25);
- pc_write_control(pb,0x08);
+ parport_pc_write_control(pb,0x08);
udelay(25);
- pc_write_control(pb,0x0c);
+ parport_pc_write_control(pb,0x0c);
udelay(50);
pb->irq = probe_irq_off(irqs);
if (pb->irq <= 0)
pb->irq = PARPORT_IRQ_NONE; /* No interrupt detected */
- pc_write_control(pb, octr);
+ parport_pc_write_control(pb, octr);
return pb->irq;
}
@@ -796,10 +815,10 @@
if (pb->irq == PARPORT_IRQ_NONE &&
(pb->modes & PARPORT_MODE_PCECPEPP)) {
- int oecr = pc_read_econtrol(pb);
- pc_write_econtrol(pb, 0x80);
+ int oecr = parport_pc_read_econtrol(pb);
+ parport_pc_write_econtrol(pb, 0x80);
pb->irq = irq_probe_EPP(pb);
- pc_write_econtrol(pb, oecr);
+ parport_pc_write_econtrol(pb, oecr);
}
epp_clear_timeout(pb);
@@ -815,14 +834,16 @@
return pb->irq;
}
+/* --- Initialisation code -------------------------------- */
+
static int probe_one_port(unsigned long int base, int irq, int dma)
{
struct parport tmpport, *p;
if (check_region(base, 3)) return 0;
tmpport.base = base;
- tmpport.ops = &pc_ops;
+ tmpport.ops = &parport_pc_ops;
if (!(parport_SPP_supported(&tmpport))) return 0;
- if (!(p = parport_register_port(base, irq, dma, &pc_ops))) return 0;
+ if (!(p = parport_register_port(base, irq, dma, &parport_pc_ops))) return 0;
p->modes = PARPORT_MODE_PCSPP | parport_PS2_supported(p);
if (p->base != 0x3bc) {
if (!check_region(base+0x400,3)) {
@@ -866,8 +887,8 @@
p->flags |= PARPORT_FLAG_COMA;
/* Done probing. Now put the port into a sensible start-up state. */
- pc_write_control(p, 0xc);
- pc_write_data(p, 0);
+ parport_pc_write_control(p, 0xc);
+ parport_pc_write_data(p, 0);
if (parport_probe_hook)
(*parport_probe_hook)(p);
@@ -882,7 +903,7 @@
/* Only probe the ports we were given. */
do {
count += probe_one_port(*(io++), *(irq++), *(dma++));
- } while (*io && (++i < PC_MAX_PORTS));
+ } while (*io && (++i < PARPORT_PC_MAX_PORTS));
} else {
/* Probe all the likely ports. */
count += probe_one_port(0x3bc, PARPORT_IRQ_AUTO, PARPORT_DMA_AUTO);
@@ -893,12 +914,12 @@
}
#ifdef MODULE
-static int io[PC_MAX_PORTS+1] = { [0 ... PC_MAX_PORTS] = 0 };
-static int dma[PC_MAX_PORTS] = { [0 ... PC_MAX_PORTS-1] = PARPORT_DMA_AUTO };
-static int irq[PC_MAX_PORTS] = { [0 ... PC_MAX_PORTS-1] = PARPORT_IRQ_AUTO };
-MODULE_PARM(io, "1-" __MODULE_STRING(PC_MAX_PORTS) "i");
-MODULE_PARM(irq, "1-" __MODULE_STRING(PC_MAX_PORTS) "i");
-MODULE_PARM(dma, "1-" __MODULE_STRING(PC_MAX_PORTS) "i");
+static int io[PARPORT_PC_MAX_PORTS+1] = { [0 ... PARPORT_PC_MAX_PORTS] = 0 };
+static int dma[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_DMA_AUTO };
+static int irq[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_IRQ_AUTO };
+MODULE_PARM(io, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "i");
+MODULE_PARM(irq, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "i");
+MODULE_PARM(dma, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "i");
int init_module(void)
{
diff -u /vger/u4/philip/linus/linux/drivers/misc/parport_share.c /vger/u4/philip/linux/drivers/misc/parport_share.c
--- /vger/u4/philip/linus/linux/drivers/misc/parport_share.c Mon Dec 1 17:49:02 1997
+++ /vger/u4/philip/linux/drivers/misc/parport_share.c Mon Dec 22 17:03:36 1997
@@ -1,4 +1,4 @@
-/* $Id: parport_share.c,v 1.8 1997/11/08 18:55:29 philip Exp $
+/* $Id: parport_share.c,v 1.10 1997/12/22 22:03:36 philip Exp $
* Parallel-port resource manager code.
*
* Authors: David Campbell <campbell@tirian.che.curtin.edu.au>
@@ -279,10 +279,16 @@
/* Swap the IRQ handlers. */
if (dev->port->irq != PARPORT_IRQ_NONE) {
- free_irq(dev->port->irq, pd1?pd1->private:NULL);
- request_irq(dev->port->irq, dev->irq_func ? dev->irq_func :
- parport_null_intr_func, SA_INTERRUPT, dev->name,
- dev->private);
+ if (pd1 && pd1->irq_func) {
+ free_irq(dev->port->irq,pd1->private);
+ request_irq(dev->port->irq, parport_null_intr_func,
+ SA_INTERRUPT, dev->port->name, NULL);
+ }
+ if (dev->irq_func) {
+ free_irq(dev->port->irq, NULL);
+ request_irq(dev->port->irq, dev->irq_func,
+ SA_INTERRUPT, dev->name, dev->private);
+ }
}
/* Restore control registers */
@@ -306,7 +312,7 @@
dev->port->ops->save_state(dev->port, dev->state);
/* Point IRQs somewhere harmless. */
- if (dev->port->irq != PARPORT_IRQ_NONE) {
+ if (dev->port->irq != PARPORT_IRQ_NONE && dev->irq_func) {
free_irq(dev->port->irq, dev->private);
request_irq(dev->port->irq, parport_null_intr_func,
SA_INTERRUPT, dev->port->name, NULL);
--- /vger/u4/philip/linus/linux/drivers/char/lp.c Sun Nov 30 17:00:38 1997
+++ /vger/u4/philip/linux/drivers/char/lp.c Mon Dec 22 16:56:52 1997
@@ -1,4 +1,6 @@
/*
+ * Generic parallel printer driver
+ *
* Copyright (C) 1992 by Jim Weigand and Linus Torvalds
* Copyright (C) 1992,1993 by Michael K. Johnson
* - Thanks much to Gunter Windau for pointing out to me where the error
@@ -11,12 +13,55 @@
* lp_read (Status readback) support added by Carsten Gross,
* carsten@sol.wohnheim.uni-ulm.de
* Support for parport by Philip Blundell <Philip.Blundell@pobox.com>
- * Reverted interrupt to polling at runtime if more than one device is parport
- * registered and joined the interrupt and polling code.
- * by Andrea Arcangeli <arcangeli@mbox.queen.it>
+ * parport_sharing hacking by Andrea Arcangeli <arcangeli@mbox.queen.it>
*/
-/* This driver is about due for a rewrite. */
+/* This driver should, in theory, work with any parallel port that has an
+ * appropriate low-level driver; all I/O is done through the parport abstraction
+ * layer. There is a performance penalty for this, but parallel ports are
+ * comparitively low-speed devices anyway. It should be possible to eliminate or
+ * reduce this overhead in the common case, as well.
+ *
+ * If this driver is built into the kernel, you can configure it using the kernel
+ * command-line... For example:
+ *
+ * lp=parport1,none,parport2 (bind lp0 to parport1, disable lp1 and
+ * bind lp2 to parport2)
+ *
+ * lp=auto (assign lp devices to all ports that
+ * have printers attached, as determined
+ * by the IEEE-1284 autoprobe)
+ *
+ * lp=reset (reset the printer during initialisation)
+ *
+ * lp=off (disable the printer driver entirely)
+ *
+ * If the driver is loaded as a module, similar functionality is available using
+ * module parameters. The equivalent of the above commands would be:
+ *
+ * # insmod lp.o parport=1,-1,2 (use -1 for disabled ports, since module
+ * parameters do not allow you to mix textual
+ * and numeric values)
+ *
+ * # insmod lp.o autoprobe=1
+ *
+ * # insmod lp.0 reset=1
+ */
+
+/* COMPATIBILITY WITH OLD KERNELS
+ *
+ * Under Linux 2.0 and previous versions, lp devices were bound to ports at
+ * particular I/O addresses, as follows:
+ *
+ * lp0 0x3bc
+ * lp1 0x378
+ * lp2 0x278
+ *
+ * The new driver, by default, binds lp devices to parport devices as it
+ * finds them. This means that if you only have one port, it will be bound
+ * to lp0 regardless of its I/O address. If you need the old behaviour, you
+ * can force it using the parameters described above.
+ */
#include <linux/module.h>
@@ -26,31 +71,24 @@
#include <linux/major.h>
#include <linux/sched.h>
#include <linux/malloc.h>
-#include <linux/ioport.h>
#include <linux/fcntl.h>
#include <linux/delay.h>
+#include <linux/parport.h>
+#include <linux/lp.h>
+
#include <asm/irq.h>
-#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/system.h>
-#include <linux/parport.h>
-#include <linux/lp.h>
/* if you have more than 3 printers, remember to increase LP_NO */
-struct lp_struct lp_table[] =
-{
- {NULL, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, 0, 0, 0, 0,
- {0}},
- {NULL, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, 0, 0, 0, 0,
- {0}},
- {NULL, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, 0, 0, 0, 0,
- {0}}
-};
#define LP_NO 3
-/* Device name */
-static char *dev_name = "lp";
+struct lp_struct lp_table[LP_NO] =
+{
+ [0 ... LP_NO-1] = {NULL, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT,
+ NULL, NULL, 0, 0, 0, 0, {0}}
+};
/* Test if printer is ready (and optionally has no error conditions) */
#define LP_READY(minor, status) \
@@ -64,10 +102,7 @@
#undef LP_DEBUG
#undef LP_READ_DEBUG
-/* Magic numbers */
-#define AUTO -3
-#define OFF -2
-#define UNSPEC -1
+/* --- parport support functions ------------------------------- */
static inline void lp_parport_release (int minor)
{
@@ -81,22 +116,27 @@
sleep_on (&lp_table[minor].lp_wait_q);
}
-static inline void lp_schedule (int minor)
+static void lp_wakeup(void *ref)
{
- if (lp_table[minor].should_relinquish) {
- lp_parport_release (minor);
- schedule ();
- lp_parport_claim (minor);
- }
- else
- schedule ();
-}
+ struct lp_struct *lp_dev = (struct lp_struct *) ref;
+ if (!waitqueue_active (&lp_dev->lp_wait_q))
+ return; /* Wake up whom? */
-static int lp_preempt (void *handle)
+ /* Claim the Parport */
+ if (parport_claim(lp_dev->dev))
+ return; /* Shouldn't happen */
+
+ wake_up(&lp_dev->lp_wait_q);
+}
+
+static int lp_preempt(void *handle)
{
struct lp_struct *lps = (struct lp_struct *)handle;
+ if (waitqueue_active (&lps->lp_wait_q))
+ wake_up_interruptible(&lps->lp_wait_q);
+
/* Just remember that someone wants the port */
lps->should_relinquish = 1;
@@ -104,12 +144,34 @@
return 1;
}
+/* --- low-level port access ----------------------------------- */
+
+#define r_dtr(x) (parport_read_data(lp_table[(x)].dev->port))
+#define r_str(x) (parport_read_status(lp_table[(x)].dev->port))
+#define w_ctr(x,y) do { parport_write_control(lp_table[(x)].dev->port, (y)); } while (0)
+#define w_dtr(x,y) do { parport_write_data(lp_table[(x)].dev->port, (y)); } while (0)
+
+static inline void lp_schedule (int minor)
+{
+ if (lp_table[minor].should_relinquish) {
+ lp_parport_release (minor);
+ schedule ();
+ lp_parport_claim (minor);
+ }
+ else
+ schedule ();
+}
+
static int lp_reset(int minor)
{
+ int retval;
+ lp_parport_claim(minor);
w_ctr(minor, LP_PSELECP);
udelay(LP_DELAY);
w_ctr(minor, LP_PSELECP | LP_PINITP);
- return r_str(minor);
+ retval = r_str(minor);
+ lp_parport_release(minor);
+ return retval;
}
static inline int must_use_polling(int minor)
@@ -118,7 +180,7 @@
lp_table[minor].dev->port->devices->next;
}
-static inline int lp_char(char lpchar, int minor, int use_polling)
+static inline int lp_char(char lpchar, int minor)
{
int status;
unsigned int wait = 0;
@@ -128,26 +190,32 @@
do {
status = r_str(minor);
count++;
- if (need_resched)
+ if (need_resched || lp_table[minor].should_relinquish)
lp_schedule (minor);
- } while (((use_polling && !LP_READY(minor, status)) ||
- (!use_polling && !(status & LP_PBUSY))) &&
- (count < LP_CHAR(minor)));
+ } while (!LP_READY(minor, status) && count < LP_CHAR(minor));
- if (count == LP_CHAR(minor) ||
- (!use_polling && !LP_CAREFUL_READY(minor, status)))
+ if (count == LP_CHAR(minor))
return 0;
+
w_dtr(minor, lpchar);
stats = &LP_STAT(minor);
stats->chars++;
/* 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
/* 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
/* take strobe low */
w_ctr(minor, LP_PSELECP | LP_PINITP);
/* update waittime statistics */
@@ -171,18 +239,41 @@
struct lp_struct *lp_dev = (struct lp_struct *) dev_id;
if (waitqueue_active (&lp_dev->lp_wait_q))
- wake_up(&lp_dev->lp_wait_q);
+ wake_up_interruptible(&lp_dev->lp_wait_q);
}
+#define LP_POLLING(minor) lp_table[minor].dev->port->irq == PARPORT_IRQ_NONE
+
static void lp_error(int minor)
{
- if (must_use_polling(minor)) {
+ if (LP_POLLING(minor) || lp_table[minor].should_relinquish) {
current->state = TASK_INTERRUPTIBLE;
current->timeout = jiffies + LP_TIMEOUT_POLLED;
lp_schedule (minor);
}
}
+static int lp_check_status(int minor) {
+ unsigned char status = r_str(minor);
+ if ((status & LP_POUTPA)) {
+ printk(KERN_INFO "lp%d out of paper\n", minor);
+ if (LP_F(minor) & LP_ABORT)
+ return 1;
+ lp_error(minor);
+ } else if (!(status & LP_PSELECD)) {
+ printk(KERN_INFO "lp%d off-line\n", minor);
+ if (LP_F(minor) & LP_ABORT)
+ return 1;
+ lp_error(minor);
+ } else if (!(status & LP_PERRORP)) {
+ printk(KERN_ERR "lp%d printer error\n", minor);
+ if (LP_F(minor) & LP_ABORT)
+ return 1;
+ lp_error(minor);
+ }
+ return 0;
+}
+
static inline int lp_write_buf(unsigned int minor, const char *buf, int count)
{
unsigned long copy_size;
@@ -202,7 +293,7 @@
copy_from_user(lp->lp_buffer, buf, copy_size);
while (copy_size) {
- if (lp_char(lp->lp_buffer[bytes_written], minor, must_use_polling(minor))) {
+ if (lp_char(lp->lp_buffer[bytes_written], minor)) {
--copy_size;
++bytes_written;
lp_table[minor].runchars++;
@@ -210,36 +301,24 @@
int rc = total_bytes_written + bytes_written;
if (lp_table[minor].runchars > LP_STAT(minor).maxrun)
LP_STAT(minor).maxrun = lp_table[minor].runchars;
- status = r_str(minor);
- if ((status & LP_POUTPA)) {
- printk(KERN_INFO "lp%d out of paper\n", minor);
- if (LP_F(minor) & LP_ABORT)
- return rc ? rc : -ENOSPC;
- lp_error(minor);
- } else if (!(status & LP_PSELECD)) {
- printk(KERN_INFO "lp%d off-line\n", minor);
- if (LP_F(minor) & LP_ABORT)
- return rc ? rc : -EIO;
- lp_error(minor);
- } else if (!(status & LP_PERRORP)) {
- printk(KERN_ERR "lp%d printer error\n", minor);
- if (LP_F(minor) & LP_ABORT)
- return rc ? rc : -EIO;
- lp_error(minor);
- }
-
LP_STAT(minor).sleeps++;
- if (must_use_polling(minor)) {
+ if (LP_POLLING(minor)) {
+ lp_polling:
+ if (lp_check_status(minor))
+ return rc ? rc : -EIO;
#ifdef LP_DEBUG
printk(KERN_DEBUG "lp%d sleeping at %d characters for %d jiffies\n", minor, lp_table[minor].runchars, LP_TIME(minor));
#endif
- lp_table[minor].runchars = 0;
current->state = TASK_INTERRUPTIBLE;
current->timeout = jiffies + LP_TIME(minor);
lp_schedule (minor);
} else {
cli();
+ if (lp_table[minor].should_relinquish) {
+ sti();
+ goto lp_polling;
+ }
enable_irq(lp->dev->port->irq);
w_ctr(minor, LP_PSELECP|LP_PINITP|LP_PINTEN);
status = r_str(minor);
@@ -249,14 +328,16 @@
sti();
continue;
}
- lp_table[minor].runchars = 0;
current->timeout = jiffies + LP_TIMEOUT_INTERRUPT;
interruptible_sleep_on(&lp->lp_wait_q);
-
w_ctr(minor, LP_PSELECP | LP_PINITP);
sti();
+ if (lp_check_status(minor))
+ return rc ? rc : -EIO;
}
+ lp_table[minor].runchars = 0;
+
if (signal_pending(current)) {
if (total_bytes_written + bytes_written)
return total_bytes_written + bytes_written;
@@ -292,7 +373,7 @@
lp_parport_claim (minor);
retv = lp_write_buf(minor, buf, count);
-
+
lp_parport_release (minor);
return retv;
}
@@ -307,14 +388,15 @@
static int lp_read_nibble(int minor)
{
unsigned char i;
- i=r_str(minor)>>3;
- i&=~8;
- if ( ( i & 0x10) == 0) i|=8;
- return(i & 0x0f);
+ i = r_str(minor)>>3;
+ i &= ~8;
+ if ((i & 0x10) == 0) i |= 8;
+ return (i & 0x0f);
}
-static void lp_select_in_high(int minor) {
- w_ctr(minor, (r_ctr(minor) | 8));
+static inline void lp_select_in_high(int minor)
+{
+ parport_frob_control(lp_table[minor].dev->port, 8, 8);
}
/* Status readback confirming to ieee1284 */
@@ -351,26 +433,27 @@
return temp-buf; /* End of file */
}
for (i=0; i<=(count*2); i++) {
- w_ctr(minor, r_ctr(minor) | 2); /* AutoFeed high */
+ parport_frob_control(lp_table[minor].dev->port, 2, 2); /* AutoFeed high */
do {
- status=(r_str(minor) & 0x40);
+ status = (r_str(minor) & 0x40);
udelay(50);
counter++;
if (need_resched)
schedule ();
- } while ( (status == 0x40) && (counter < 20) );
- if ( counter == 20 ) { /* Timeout */
+ } while ((status == 0x40) && (counter < 20));
+ if (counter == 20) {
+ /* Timeout */
#ifdef LP_READ_DEBUG
printk(KERN_DEBUG "lp_read: (Autofeed high) timeout\n");
-#endif
- w_ctr(minor, r_ctr(minor) & ~2);
+#endif
+ parport_frob_control(lp_table[minor].dev->port, 2, 0);
lp_select_in_high(minor);
parport_release(lp_table[minor].dev);
return temp-buf; /* end the read at timeout */
}
counter=0;
- z=lp_read_nibble(minor);
- w_ctr(minor, r_ctr(minor) & ~2); /* AutoFeed low */
+ z = lp_read_nibble(minor);
+ parport_frob_control(lp_table[minor].dev->port, 2, 0); /* AutoFeed low */
do {
status=(r_str(minor) & 0x40);
udelay(20);
@@ -571,19 +654,27 @@
lp_release
};
-static int parport[LP_NO] = { UNSPEC, };
+/* --- initialisation code ------------------------------------- */
#ifdef MODULE
-#define lp_init init_module
+
+static int parport[LP_NO] = { [0 ... LP_NO-1] = LP_PARPORT_UNSPEC };
+static int reset = 0;
+static int autoprobe = 0;
+
MODULE_PARM(parport, "1-" __MODULE_STRING(LP_NO) "i");
+MODULE_PARM(reset, "i");
+MODULE_PARM(autoprobe, "i");
#else
+static int parport[LP_NO] __initdata = { [0 ... LP_NO-1] = LP_PARPORT_UNSPEC };
+static int reset __initdata = 0;
+
static int parport_ptr = 0;
-void lp_setup(char *str, int *ints)
+__initfunc(void lp_setup(char *str, int *ints))
{
- /* Ugh. */
if (!strncmp(str, "parport", 7)) {
int n = simple_strtoul(str+7, NULL, 10);
if (parport_ptr < LP_NO)
@@ -592,11 +683,15 @@
printk(KERN_INFO "lp: too many ports, %s ignored.\n",
str);
} else if (!strcmp(str, "auto")) {
- parport[0] = AUTO;
+ parport[0] = LP_PARPORT_AUTO;
+ } else if (!strcmp(str, "none")) {
+ parport_ptr++;
+ } else if (!strcmp(str, "reset")) {
+ reset = 1;
} else {
if (ints[0] == 0 || ints[1] == 0) {
/* disable driver on "lp=" or "lp=0" */
- parport[0] = OFF;
+ parport[0] = LP_PARPORT_OFF;
} else {
printk(KERN_WARNING "warning: 'lp=0x%x' is deprecated, ignored\n", ints[1]);
}
@@ -605,87 +700,92 @@
#endif
-void lp_wakeup(void *ref)
+int lp_register(int nr, struct parport *port)
{
- struct lp_struct *lp_dev = (struct lp_struct *) ref;
-
- if (!waitqueue_active (&lp_dev->lp_wait_q))
- return; /* Wake up whom? */
+ lp_table[nr].dev = parport_register_device(port, "lp",
+ lp_preempt, lp_wakeup,
+ lp_interrupt,
+ PARPORT_DEV_TRAN,
+ (void *) &lp_table[nr]);
+ if (lp_table[nr].dev == NULL)
+ return 1;
+ lp_table[nr].flags |= LP_EXIST;
+ init_waitqueue (&lp_table[nr].lp_wait_q);
- /* Claim the Parport */
- if (parport_claim(lp_dev->dev))
- return; /* Shouldn't happen */
+ if (reset)
+ lp_reset(nr);
- wake_up(&lp_dev->lp_wait_q);
-}
+ printk(KERN_INFO "lp%d: using %s (%s).\n", nr, port->name,
+ (port->irq == PARPORT_IRQ_NONE)?"polling":"interrupt-driven");
-static int inline lp_searchfor(int list[], int a)
-{
- int i;
- for (i = 0; i < LP_NO && list[i] != UNSPEC; i++) {
- if (list[i] == a) return 1;
- }
return 0;
}
int lp_init(void)
{
- int count = 0;
- struct parport *pb;
-
- if (parport[0] == OFF) return 0;
-
- pb = parport_enumerate();
-
- while (pb) {
- /* We only understand PC-style ports. */
- if (pb->modes & PARPORT_MODE_PCSPP) {
- if (parport[0] == UNSPEC ||
- lp_searchfor(parport, count) ||
- (parport[0] == AUTO &&
- pb->probe_info.class == PARPORT_CLASS_PRINTER)) {
- lp_table[count].dev =
- parport_register_device(pb, dev_name,
- lp_preempt, lp_wakeup,
- lp_interrupt, PARPORT_DEV_TRAN,
- (void *) &lp_table[count]);
- lp_table[count].flags |= LP_EXIST;
- init_waitqueue (&lp_table[count].lp_wait_q);
- lp_parport_claim (count);
- lp_reset (count);
- lp_parport_release (count);
- printk(KERN_INFO "lp%d: using %s (%s).\n",
- count, pb->name, (pb->irq == PARPORT_IRQ_NONE)?"polling":"interrupt-driven");
+ unsigned int count = 0;
+ struct parport *port;
+
+ switch (parport[0])
+ {
+ case LP_PARPORT_OFF:
+ return 0;
+
+ case LP_PARPORT_UNSPEC:
+ case LP_PARPORT_AUTO:
+ for (port = parport_enumerate(); port; port = port->next) {
+
+ if (parport[0] == LP_PARPORT_AUTO &&
+ port->probe_info.class != PARPORT_CLASS_PRINTER)
+ continue;
+
+ if (!lp_register(count, port))
+ if (++count == LP_NO)
+ break;
+ }
+ break;
+
+ default:
+ for (count = 0; count < LP_NO; count++) {
+ if (parport[count] != LP_PARPORT_UNSPEC) {
+ char buffer[16];
+ sprintf(buffer, "parport%d", parport[count]);
+ for (port = parport_enumerate(); port;
+ port = port->next) {
+ if (!strcmp(port->name, buffer)) {
+ (void) lp_register(count, port);
+ break;
+ }
+ }
}
- if (++count == LP_NO)
- break;
}
- pb = pb->next;
- }
+ break;
+ }
- /* Successful specified devices increase count
- * Unsuccessful specified devices increase failed
- */
- if (count) {
+ if (count) {
if (register_chrdev(LP_MAJOR, "lp", &lp_fops)) {
printk("lp: unable to get major %d\n", LP_MAJOR);
return -EIO;
}
- return 0;
+ } else {
+ printk(KERN_INFO "lp: driver loaded but no devices found\n");
}
- printk(KERN_INFO "lp: driver loaded but no devices found\n");
-#ifdef MODULE
return 0;
-#else
- return 1;
-#endif
}
#ifdef MODULE
+int init_module(void)
+{
+ if (autoprobe)
+ parport[0] = LP_PARPORT_AUTO;
+
+ return lp_init();
+}
+
void cleanup_module(void)
{
- int offset;
+ unsigned int offset;
unregister_chrdev(LP_MAJOR, "lp");
for (offset = 0; offset < LP_NO; offset++) {
--- /vger/u4/philip/linus/linux/include/linux/lp.h Tue Aug 26 17:52:45 1997
+++ /vger/u4/philip/linux/include/linux/lp.h Mon Dec 22 16:53:57 1997
@@ -7,6 +7,11 @@
* Interrupt support added 1993 Nigel Gamble
*/
+/* Magic numbers for defining port-device mappings */
+#define LP_PARPORT_AUTO -3
+#define LP_PARPORT_OFF -2
+#define LP_PARPORT_UNSPEC -1
+
/*
* Per POSIX guidelines, this module reserves the LP and lp prefixes
* These are the lp_table[minor].flags flags...
@@ -88,20 +93,6 @@
#define LP_BUFFER_SIZE 256
#define LP_BASE(x) lp_table[(x)].dev->port->base
-
-#define r_dtr(x) inb(LP_BASE(x))
-#define r_str(x) inb(LP_BASE(x)+1)
-#define r_ctr(x) inb(LP_BASE(x)+2)
-#define r_epp(x) inb(LP_BASE(x)+4)
-#define r_fifo(x) inb(LP_BASE(x)+0x400)
-#define r_ecr(x) inb(LP_BASE(x)+0x402)
-
-#define w_dtr(x,y) outb((y), LP_BASE(x))
-#define w_str(x,y) outb((y), LP_BASE(x)+1)
-#define w_ctr(x,y) outb((y), LP_BASE(x)+2)
-#define w_epp(x,y) outb((y), LP_BASE(x)+4)
-#define w_fifo(x,y) outb((y), LP_BASE(x)+0x400)
-#define w_ecr(x,y) outb((y), LP_BASE(x)+0x402)
struct lp_stats {
unsigned long chars;
-- 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:17:14 EST