summaryrefslogtreecommitdiffstats
path: root/drivers/misc
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1998-05-07 02:55:41 +0000
committerRalf Baechle <ralf@linux-mips.org>1998-05-07 02:55:41 +0000
commitdcec8a13bf565e47942a1751a9cec21bec5648fe (patch)
tree548b69625b18cc2e88c3e68d0923be546c9ebb03 /drivers/misc
parent2e0f55e79c49509b7ff70ff1a10e1e9e90a3dfd4 (diff)
o Merge with Linux 2.1.99.
o Fix ancient bug in the ELF loader making ldd crash. o Fix ancient bug in the keyboard code for SGI, SNI and Jazz.
Diffstat (limited to 'drivers/misc')
-rw-r--r--drivers/misc/parport_init.c69
-rw-r--r--drivers/misc/parport_pc.c307
-rw-r--r--drivers/misc/parport_procfs.c169
-rw-r--r--drivers/misc/parport_share.c28
4 files changed, 241 insertions, 332 deletions
diff --git a/drivers/misc/parport_init.c b/drivers/misc/parport_init.c
index 31753dc1a..9b90bae8b 100644
--- a/drivers/misc/parport_init.c
+++ b/drivers/misc/parport_init.c
@@ -20,7 +20,7 @@
#ifndef MODULE
static int io[PARPORT_MAX+1] __initdata = { [0 ... PARPORT_MAX] = 0 };
-static int irq[PARPORT_MAX] __initdata = { [0 ... PARPORT_MAX-1] = PARPORT_IRQ_NONE };
+static int irq[PARPORT_MAX] __initdata = { [0 ... PARPORT_MAX-1] = PARPORT_IRQ_PROBEONLY };
static int dma[PARPORT_MAX] __initdata = { [0 ... PARPORT_MAX-1] = PARPORT_DMA_NONE };
extern int parport_pc_init(int *io, int *irq, int *dma);
@@ -30,26 +30,68 @@ static int parport_setup_ptr __initdata = 0;
__initfunc(void parport_setup(char *str, int *ints))
{
- if (ints[0] == 0 || ints[1] == 0) {
- /* Disable parport if "parport=" or "parport=0" in cmdline */
+ if (ints[0] == 0) {
+ if (str && !strncmp(str, "auto", 4)) {
+ irq[0] = PARPORT_IRQ_AUTO;
+ dma[0] = PARPORT_DMA_AUTO;
+ }
+ else if (str)
+ printk (KERN_ERR "parport: `%s': huh?\n", str);
+ else
+ printk (KERN_ERR "parport: parport=.. what?\n");
+
+ return;
+ }
+ else if (ints[1] == 0) {
+ /* Disable parport if "parport=0" in cmdline */
io[0] = PARPORT_DISABLE;
return;
}
+
if (parport_setup_ptr < PARPORT_MAX) {
+ char *sep;
io[parport_setup_ptr] = ints[1];
- if (ints[0]>1) {
+ irq[parport_setup_ptr] = PARPORT_IRQ_NONE;
+ dma[parport_setup_ptr] = PARPORT_DMA_NONE;
+ if (ints[0] > 1) {
irq[parport_setup_ptr] = ints[2];
- if (ints[0]>2) dma[parport_setup_ptr] = ints[3];
+ if (ints[0] > 2) {
+ dma[parport_setup_ptr] = ints[3];
+ goto done;
+ }
+
+ if (str == NULL)
+ goto done;
+
+ goto dma_from_str;
}
- parport_setup_ptr++;
- } else {
- printk(KERN_ERR "parport=0x%x", ints[1]);
- if (ints[0]>1) {
- printk(",%d", ints[2]);
- if (ints[0]>2) printk(",%d", ints[3]);
+ else if (str == NULL)
+ goto done;
+ else if (!strncmp(str, "auto", 4))
+ irq[parport_setup_ptr] = PARPORT_IRQ_AUTO;
+ else if (strncmp(str, "none", 4) != 0) {
+ printk(KERN_ERR "parport: bad irq `%s'\n", str);
+ return;
}
- printk(" ignored, too many ports.\n");
- }
+
+ if ((sep = strchr(str, ',')) == NULL) goto done;
+ str = sep+1;
+ dma_from_str:
+ if (!strncmp(str, "auto", 4))
+ dma[parport_setup_ptr] = PARPORT_DMA_AUTO;
+ else if (strncmp(str, "none", 4) != 0) {
+ char *ep;
+ dma[parport_setup_ptr] = simple_strtoul(str, &ep, 0);
+ if (ep == str) {
+ printk(KERN_ERR "parport: bad dma `%s'\n",
+ str);
+ return;
+ }
+ }
+ done:
+ parport_setup_ptr++;
+ } else
+ printk(KERN_ERR "parport=%s ignored, too many ports\n", str);
}
#endif
@@ -100,6 +142,7 @@ EXPORT_SYMBOL(parport_wait_peripheral);
EXPORT_SYMBOL(parport_proc_register);
EXPORT_SYMBOL(parport_proc_unregister);
EXPORT_SYMBOL(parport_probe_hook);
+EXPORT_SYMBOL(parport_parse_irqs);
void inc_parport_count(void)
{
diff --git a/drivers/misc/parport_pc.c b/drivers/misc/parport_pc.c
index bd542b4fd..7396e2e11 100644
--- a/drivers/misc/parport_pc.c
+++ b/drivers/misc/parport_pc.c
@@ -36,7 +36,6 @@
#include <asm/ptrace.h>
#include <asm/io.h>
-#include <asm/dma.h>
#include <linux/module.h>
#include <linux/delay.h>
@@ -163,9 +162,9 @@ void parport_pc_release_resources(struct parport *p)
int parport_pc_claim_resources(struct parport *p)
{
- /* FIXME check that resources are free */
+ int err;
if (p->irq != PARPORT_IRQ_NONE)
- request_irq(p->irq, parport_pc_null_intr_func, 0, p->name, NULL);
+ if ((err = request_irq(p->irq, parport_pc_null_intr_func, 0, p->name, NULL)) != 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);
@@ -276,159 +275,6 @@ struct parport_operations parport_pc_ops =
parport_pc_dec_use_count
};
-/* --- DMA detection -------------------------------------- */
-
-/*
- * Prepare DMA channels from 0-8 to transmit towards buffer
- */
-static int parport_prepare_dma(char *buff, int size)
-{
- int tmp = 0;
- int i,retv;
-
- for (i = 0; i < 8; i++) {
- retv = request_dma(i, "probe");
- if (retv)
- continue;
- tmp |= 1 << i;
-
- cli();
- disable_dma(i);
- clear_dma_ff(i);
- set_dma_addr(i, virt_to_bus(buff));
- set_dma_count(i, size);
- set_dma_mode(i, DMA_MODE_READ);
- sti();
- }
-
- return tmp;
-}
-
-/*
- * Activate all DMA channels passed in dma
- */
-static int parport_enable_dma(int dma)
-{
- int i;
-
- for (i = 0; i < 8; i++)
- if (dma & (1 << i)) {
- cli();
- enable_dma(i);
- sti();
- }
-
- return dma;
-}
-
-static int parport_detect_dma_transfer(int dma, int size)
-{
- int i,n,retv;
- int count=0;
-
- retv = PARPORT_DMA_NONE;
- for (i = 0; i < 8; i++)
- if (dma & (1 << i)) {
- disable_dma(i);
- clear_dma_ff(i);
- n = get_dma_residue(i);
- if (n != size) {
- retv = i;
- if (count > 0) {
- retv = PARPORT_DMA_NONE; /* Multiple DMA's */
- printk(KERN_ERR "parport: multiple DMA detected. Huh?\n");
- }
- count++;
- }
- free_dma(i);
- }
-
- return retv;
-}
-
-/* Only if supports ECP mode */
-static int programmable_dma_support(struct parport *pb)
-{
- unsigned char dma, oldstate = parport_pc_read_econtrol(pb);
-
- parport_pc_write_econtrol(pb, 0xe0); /* Configuration MODE */
-
- dma = parport_pc_read_configb(pb) & 0x07;
-
- parport_pc_write_econtrol(pb, oldstate);
-
- if (dma == 0 || dma == 4) /* Jumper selection */
- return PARPORT_DMA_NONE;
- else
- return dma;
-}
-
-/* Only called if port supports ECP mode.
- *
- * The only restriction on DMA channels is that it has to be
- * between 0 to 7 (inclusive). Used only in an ECP mode, DMAs are
- * considered a shared resource and hence they should be registered
- * when needed and then immediately unregistered.
- *
- * DMA autoprobes for ECP mode are known not to work for some
- * main board BIOS configs. I had to remove everything from the
- * port, set the mode to SPP, reboot to DOS, set the mode to ECP,
- * and reboot again, then I got IRQ probes and DMA probes to work.
- * [Is the BIOS doing a device detection?]
- *
- * A value of PARPORT_DMA_NONE is allowed indicating no DMA support.
- *
- * if( 0 < DMA < 4 )
- * 1Byte DMA transfer
- * else // 4 < DMA < 8
- * 2Byte DMA transfer
- *
- */
-static int parport_dma_probe(struct parport *pb)
-{
- int dma,retv;
- unsigned char dsr,dsr_read;
- char *buff;
-
- retv = programmable_dma_support(pb);
- if (retv != PARPORT_DMA_NONE)
- return retv;
-
- if (!(buff = kmalloc(2048, GFP_KERNEL | GFP_DMA))) {
- printk(KERN_ERR "parport: memory squeeze\n");
- return PARPORT_DMA_NONE;
- }
-
- dsr = pb->ops->read_control(pb);
- dsr_read = (dsr & ~(0x20)) | 0x04; /* Direction == read */
-
- pb->ops->write_econtrol(pb, 0xc0); /* ECP MODE */
- pb->ops->write_control(pb, dsr_read );
- dma = parport_prepare_dma(buff, 1000);
- pb->ops->write_econtrol(pb, 0xd8); /* ECP FIFO + enable DMA */
- parport_enable_dma(dma);
- udelay(500); /* Give some for DMA tranfer */
- retv = parport_detect_dma_transfer(dma, 1000);
-
- /*
- * National Semiconductors only supports DMA tranfers
- * in ECP MODE
- */
- if (retv == PARPORT_DMA_NONE) {
- pb->ops->write_econtrol(pb, 0x60); /* ECP MODE */
- pb->ops->write_control(pb, dsr_read );
- dma=parport_prepare_dma(buff,1000);
- pb->ops->write_econtrol(pb, 0x68); /* ECP FIFO + enable DMA */
- parport_enable_dma(dma);
- udelay(500); /* Give some for DMA tranfer */
- retv = parport_detect_dma_transfer(dma, 1000);
- }
-
- kfree(buff);
-
- return retv;
-}
-
/* --- Mode detection ------------------------------------- */
/*
@@ -458,6 +304,7 @@ static int epp_clear_timeout(struct parport *pb)
static int parport_SPP_supported(struct parport *pb)
{
/* Do a simple read-write test to make sure the port exists. */
+ parport_pc_write_econtrol(pb, 0xc);
parport_pc_write_control(pb, 0xc);
parport_pc_write_data(pb, 0xaa);
if (parport_pc_read_data(pb) != 0xaa) return 0;
@@ -482,8 +329,9 @@ static int parport_SPP_supported(struct parport *pb)
*/
static int parport_ECR_present(struct parport *pb)
{
- unsigned char r, octr = parport_pc_read_control(pb),
- oecr = parport_pc_read_econtrol(pb);
+ unsigned char r, octr = parport_pc_read_control(pb);
+ unsigned char oecr = parport_pc_read_econtrol(pb);
+ unsigned char tmp;
r = parport_pc_read_control(pb);
if ((parport_pc_read_econtrol(pb) & 0x3) == (r & 0x3)) {
@@ -500,12 +348,14 @@ static int parport_ECR_present(struct parport *pb)
return 0;
parport_pc_write_econtrol(pb, 0x34);
- if (parport_pc_read_econtrol(pb) != 0x35)
- return 0;
+ tmp = parport_pc_read_econtrol(pb);
parport_pc_write_econtrol(pb, oecr);
parport_pc_write_control(pb, octr);
+ if (tmp != 0x35)
+ return 0;
+
return PARPORT_MODE_PCECR;
}
@@ -637,58 +487,6 @@ static int parport_ECPPS2_supported(struct parport *pb)
/* --- 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
- * "votes" is the elected interrupt (it SHOULD work...)
- *
- * This is horribly x86-specific at the moment. I'm not convinced it
- * belongs at all.
- */
-
-static int intr_vote[16];
-
-static void parport_vote_intr_func(int irq, void *dev_id, struct pt_regs *regs)
-{
- intr_vote[irq]++;
- return;
-}
-
-static long open_intr_election(void)
-{
- long tmp = 0;
- int i;
-
- /* We ignore the timer - irq 0 */
- for (i = 1; i < 16; i++) {
- intr_vote[i] = 0;
- if (request_irq(i, parport_vote_intr_func,
- SA_INTERRUPT, "probe", intr_vote) == 0)
- tmp |= 1 << i;
- }
- return tmp;
-}
-
-static int close_intr_election(long tmp)
-{
- int irq = PARPORT_IRQ_NONE;
- int i;
-
- /* We ignore the timer - irq 0 */
- for (i = 1; i < 16; i++)
- if (tmp & (1 << i)) {
- if (intr_vote[i]) {
- if (irq != PARPORT_IRQ_NONE)
- /* More than one interrupt */
- return PARPORT_IRQ_NONE;
- irq = i;
- }
- free_irq(i, intr_vote);
- }
- return irq;
-}
-
/* Only if supports ECP mode */
static int programmable_irq_support(struct parport *pb)
{
@@ -710,20 +508,23 @@ static int programmable_irq_support(struct parport *pb)
static int irq_probe_ECP(struct parport *pb)
{
int irqs, i;
- unsigned char oecr = parport_pc_read_econtrol(pb);
- probe_irq_off(probe_irq_on()); /* Clear any interrupts */
- irqs = open_intr_election();
+ sti();
+ irqs = probe_irq_on();
- parport_pc_write_econtrol(pb, 0x00); /* Reset FIFO */
- parport_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 && !(parport_pc_read_econtrol(pb) & 0x02) ; i++)
parport_pc_write_fifo(pb, 0xaa);
- pb->irq = close_intr_election(irqs);
- parport_pc_write_econtrol(pb, oecr);
+ pb->irq = probe_irq_off(irqs);
+ parport_pc_write_econtrol(pb, 0x00);
+
+ if (pb->irq <= 0)
+ pb->irq = PARPORT_IRQ_NONE;
+
return pb->irq;
}
@@ -735,30 +536,36 @@ static int irq_probe_EPP(struct parport *pb)
{
int irqs;
unsigned char octr = parport_pc_read_control(pb);
+ unsigned char oecr = parport_pc_read_econtrol(pb);
#ifndef ADVANCED_DETECT
return PARPORT_IRQ_NONE;
#endif
- probe_irq_off(probe_irq_on()); /* Clear any interrupts */
- irqs = open_intr_election();
+ sti();
+ irqs = probe_irq_on();
if (pb->modes & PARPORT_MODE_PCECR)
- parport_pc_write_econtrol(pb, parport_pc_read_econtrol(pb) | 0x10);
+ parport_pc_frob_econtrol (pb, 0x10, 0x10);
epp_clear_timeout(pb);
- parport_pc_write_control(pb, parport_pc_read_control(pb) | 0x20);
- parport_pc_write_control(pb, parport_pc_read_control(pb) | 0x10);
+ parport_pc_frob_control (pb, 0x20, 0x20);
+ parport_pc_frob_control (pb, 0x10, 0x10);
epp_clear_timeout(pb);
- /* Device isn't expecting an EPP read
+ /* Device isn't expecting an EPP read
* and generates an IRQ.
*/
parport_pc_read_epp(pb);
udelay(20);
- pb->irq = close_intr_election(irqs);
+ pb->irq = probe_irq_off (irqs);
+ parport_pc_write_econtrol(pb, oecr);
parport_pc_write_control(pb, octr);
+
+ if (pb->irq <= 0)
+ pb->irq = PARPORT_IRQ_NONE;
+
return pb->irq;
}
@@ -766,6 +573,7 @@ static int irq_probe_SPP(struct parport *pb)
{
int irqs;
unsigned char octr = parport_pc_read_control(pb);
+ unsigned char oecr = parport_pc_read_econtrol(pb);
#ifndef ADVANCED_DETECT
return PARPORT_IRQ_NONE;
@@ -794,6 +602,7 @@ static int irq_probe_SPP(struct parport *pb)
if (pb->irq <= 0)
pb->irq = PARPORT_IRQ_NONE; /* No interrupt detected */
+ parport_pc_write_econtrol(pb, oecr);
parport_pc_write_control(pb, octr);
return pb->irq;
}
@@ -807,16 +616,19 @@ static int irq_probe_SPP(struct parport *pb)
*/
static int parport_irq_probe(struct parport *pb)
{
- if (pb->modes & PARPORT_MODE_PCECR)
+ unsigned char oecr = parport_pc_read_econtrol (pb);
+
+ if (pb->modes & PARPORT_MODE_PCECR) {
pb->irq = programmable_irq_support(pb);
+ if (pb->irq != PARPORT_IRQ_NONE)
+ goto out;
+ }
if (pb->modes & PARPORT_MODE_PCECP)
pb->irq = irq_probe_ECP(pb);
-
+
if (pb->irq == PARPORT_IRQ_NONE &&
(pb->modes & PARPORT_MODE_PCECPEPP)) {
- int oecr = parport_pc_read_econtrol(pb);
- parport_pc_write_econtrol(pb, 0x80);
pb->irq = irq_probe_EPP(pb);
parport_pc_write_econtrol(pb, oecr);
}
@@ -831,6 +643,8 @@ static int parport_irq_probe(struct parport *pb)
if (pb->irq == PARPORT_IRQ_NONE)
pb->irq = irq_probe_SPP(pb);
+out:
+ parport_pc_write_econtrol (pb, oecr);
return pb->irq;
}
@@ -839,6 +653,7 @@ static int parport_irq_probe(struct parport *pb)
static int probe_one_port(unsigned long int base, int irq, int dma)
{
struct parport tmpport, *p;
+ int probedirq = PARPORT_IRQ_NONE;
if (check_region(base, 3)) return 0;
tmpport.base = base;
tmpport.ops = &parport_pc_ops;
@@ -862,12 +677,16 @@ static int probe_one_port(unsigned long int base, int irq, int dma)
if (p->irq == PARPORT_IRQ_AUTO) {
p->irq = PARPORT_IRQ_NONE;
parport_irq_probe(p);
+ } else if (p->irq == PARPORT_IRQ_PROBEONLY) {
+ p->irq = PARPORT_IRQ_NONE;
+ parport_irq_probe(p);
+ probedirq = p->irq;
+ p->irq = PARPORT_IRQ_NONE;
}
if (p->irq != PARPORT_IRQ_NONE)
printk(", irq %d", p->irq);
if (p->dma == PARPORT_DMA_AUTO)
- p->dma = (p->modes & PARPORT_MODE_PCECP)?
- parport_dma_probe(p):PARPORT_DMA_NONE;
+ p->dma = PARPORT_DMA_NONE;
if (p->dma != PARPORT_DMA_NONE)
printk(", dma %d", p->dma);
printk(" [");
@@ -883,10 +702,13 @@ static int probe_one_port(unsigned long int base, int irq, int dma)
}
#undef printmode
printk("]\n");
+ if (probedirq != PARPORT_IRQ_NONE)
+ printk("%s: detected irq %d; use procfs to enable interrupt-driven operation.\n", p->name, probedirq);
parport_proc_register(p);
p->flags |= PARPORT_FLAG_COMA;
/* Done probing. Now put the port into a sensible start-up state. */
+ parport_pc_write_econtrol(p, 0xc);
parport_pc_write_control(p, 0xc);
parport_pc_write_data(p, 0);
@@ -906,9 +728,9 @@ int parport_pc_init(int *io, int *irq, int *dma)
} while (*io && (++i < PARPORT_PC_MAX_PORTS));
} else {
/* Probe all the likely ports. */
- count += probe_one_port(0x3bc, PARPORT_IRQ_AUTO, PARPORT_DMA_AUTO);
- count += probe_one_port(0x378, PARPORT_IRQ_AUTO, PARPORT_DMA_AUTO);
- count += probe_one_port(0x278, PARPORT_IRQ_AUTO, PARPORT_DMA_AUTO);
+ count += probe_one_port(0x3bc, irq[0], dma[0]);
+ count += probe_one_port(0x378, irq[0], dma[0]);
+ count += probe_one_port(0x278, irq[0], dma[0]);
}
/* Give any attached devices a chance to gather their thoughts */
@@ -921,15 +743,22 @@ int parport_pc_init(int *io, int *irq, int *dma)
#ifdef MODULE
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 };
+static int dma[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_DMA_NONE };
+static int irqval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_IRQ_PROBEONLY };
+static const char *irq[PARPORT_PC_MAX_PORTS] = { NULL, };
MODULE_PARM(io, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "i");
-MODULE_PARM(irq, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "i");
+MODULE_PARM(irq, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s");
MODULE_PARM(dma, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "i");
int init_module(void)
{
- return (parport_pc_init(io, irq, dma)?0:1);
+ /* Work out how many ports we have, then get parport_share to parse
+ the irq values. */
+ unsigned int i;
+ for (i = 0; i < PARPORT_PC_MAX_PORTS && io[i]; i++);
+ parport_parse_irqs(i, irq, irqval);
+
+ return (parport_pc_init(io, irqval, dma)?0:1);
}
void cleanup_module(void)
diff --git a/drivers/misc/parport_procfs.c b/drivers/misc/parport_procfs.c
index d038a7771..97717448c 100644
--- a/drivers/misc/parport_procfs.c
+++ b/drivers/misc/parport_procfs.c
@@ -4,6 +4,7 @@
* Tim Waugh <tim@cyberelk.demon.co.uk>
* Philip Blundell <philb@gnu.org>
* Andrea Arcangeli <arcangeli@mbox.queen.it>
+ * Riccardo Facchetti <fizban@tin.it>
*
* based on work by Grant Guenther <grant@torque.net>
* and Philip Blundell
@@ -11,6 +12,7 @@
#include <linux/stddef.h>
#include <linux/tasks.h>
+#include <linux/ctype.h>
#include <asm/ptrace.h>
#include <asm/io.h>
#include <asm/dma.h>
@@ -32,55 +34,74 @@ extern void parport_null_intr_func(int irq, void *dev_id, struct pt_regs *regs);
static int irq_write_proc(struct file *file, const char *buffer,
unsigned long count, void *data)
{
- int newirq, oldirq;
+ int retval = -EINVAL;
+ int newirq = PARPORT_IRQ_NONE;
struct parport *pp = (struct parport *)data;
-
- if (count > 5 ) /* more than 4 digits + \n for a irq 0x?? 0?? ?? */
- return -EOVERFLOW;
-
- if (buffer[0] < 32 || !strncmp(buffer, "none", 4)) {
- newirq = PARPORT_IRQ_NONE;
- } else {
- if (buffer[0] == '0') {
- if (buffer[1] == 'x')
- newirq = simple_strtoul(&buffer[2], 0, 16);
- else
- newirq = simple_strtoul(&buffer[1], 0, 8);
- } else {
- newirq = simple_strtoul(buffer, 0, 10);
- }
- }
+ struct pardevice *cad = pp->cad;
+ int oldirq = pp->irq;
+
+/*
+ * We can have these valid cases:
+ * "none" (count == 4 || count == 5)
+ * decimal number (count == 2 || count == 3)
+ * octal number (count == 3 || count == 4)
+ * hex number (count == 4 || count == 5)
+ * all other cases are -EINVAL
+ *
+ * Note: newirq is alredy set up to NONE.
+ *
+ * -RF
+ */
+ if (count > 5 || count < 1)
+ goto out;
- if (newirq >= NR_IRQS)
- return -EOVERFLOW;
+ if (isdigit(buffer[0]))
+ newirq = simple_strtoul(buffer, NULL, 0);
+ else if (strncmp(buffer, "none", 4) != 0) {
+ if (buffer[0] < 32)
+ /* Things like '\n' are harmless */
+ retval = count;
- if (pp->irq != PARPORT_IRQ_NONE && !(pp->flags & PARPORT_FLAG_COMA)) {
- if (pp->cad != NULL && pp->cad->irq_func != NULL)
- free_irq(pp->irq, pp->cad->private);
- else
- free_irq(pp->irq, NULL);
+ goto out;
}
- oldirq = pp->irq;
- pp->irq = newirq;
+ retval = count;
+
+ if (oldirq == newirq)
+ goto out;
- if (pp->irq != PARPORT_IRQ_NONE && !(pp->flags & PARPORT_FLAG_COMA)) {
- struct pardevice *cad = pp->cad;
+ if (pp->flags & PARPORT_FLAG_COMA)
+ goto out_ok;
- if (cad == NULL)
- request_irq(pp->irq, parport_null_intr_func,
- SA_INTERRUPT, pp->name, NULL);
+ if (newirq != PARPORT_IRQ_NONE) {
+ void (*handler)(int, void *, struct pt_regs *);
+
+ if (cad && cad->irq_func)
+ handler = cad->irq_func;
else
- request_irq(pp->irq, cad->irq_func ? cad->irq_func :
- parport_null_intr_func, SA_INTERRUPT,
- cad->name, cad->private);
+ handler = parport_null_intr_func;
+
+ retval = request_irq(newirq, handler,
+ SA_INTERRUPT,
+ cad ? cad->name : pp->name,
+ cad ? cad->private : NULL);
+ if (retval)
+ goto out;
+ else retval = count;
}
- if (oldirq != PARPORT_IRQ_NONE && newirq == PARPORT_IRQ_NONE &&
- pp->cad != NULL && pp->cad->irq_func != NULL)
- pp->cad->irq_func(pp->irq, pp->cad->private, NULL);
+ if (oldirq != PARPORT_IRQ_NONE) {
+ if (cad && cad->irq_func)
+ free_irq(oldirq, cad->private);
+ else
+ free_irq(oldirq, NULL);
+ }
- return count;
+out_ok:
+ pp->irq = newirq;
+
+out:
+ return retval;
}
static int irq_read_proc(char *page, char **start, off_t off,
@@ -167,6 +188,20 @@ static inline void destroy_proc_entry(struct proc_dir_entry *root,
*d = NULL;
}
+static void destroy_proc_tree(struct parport *pp) {
+ if (pp->pdir.entry) {
+ if (pp->pdir.irq)
+ destroy_proc_entry(pp->pdir.entry, &pp->pdir.irq);
+ if (pp->pdir.devices)
+ destroy_proc_entry(pp->pdir.entry, &pp->pdir.devices);
+ if (pp->pdir.hardware)
+ destroy_proc_entry(pp->pdir.entry, &pp->pdir.hardware);
+ if (pp->pdir.probe)
+ destroy_proc_entry(pp->pdir.entry, &pp->pdir.probe);
+ destroy_proc_entry(base, &pp->pdir.entry);
+ }
+}
+
static struct proc_dir_entry *new_proc_entry(const char *name, mode_t mode,
struct proc_dir_entry *parent,
unsigned short ino)
@@ -220,8 +255,6 @@ void parport_proc_cleanup(void)
int parport_proc_register(struct parport *pp)
{
- static const char *proc_msg = KERN_ERR "%s: Trouble with /proc.\n";
-
memset(&pp->pdir, 0, sizeof(struct parport_dir));
if (base == NULL) {
@@ -233,63 +266,43 @@ int parport_proc_register(struct parport *pp)
sizeof(pp->pdir.name));
pp->pdir.entry = new_proc_entry(pp->pdir.name, S_IFDIR, base, 0);
- if (pp->pdir.entry == NULL) {
- printk(proc_msg, pp->name);
- return 1;
- }
+ if (pp->pdir.entry == NULL)
+ goto out_fail;
pp->pdir.irq = new_proc_entry("irq", S_IFREG | S_IRUGO | S_IWUSR,
pp->pdir.entry, 0);
- if (pp->pdir.irq == NULL) {
- printk(proc_msg, pp->name);
- destroy_proc_entry(base, &pp->pdir.entry);
- return 1;
- }
+ if (pp->pdir.irq == NULL)
+ goto out_fail;
+
pp->pdir.irq->read_proc = irq_read_proc;
pp->pdir.irq->write_proc = irq_write_proc;
pp->pdir.irq->data = pp;
pp->pdir.devices = new_proc_entry("devices", 0, pp->pdir.entry, 0);
- if (pp->pdir.devices == NULL) {
- printk(proc_msg, pp->name);
- destroy_proc_entry(pp->pdir.entry, &pp->pdir.irq);
- destroy_proc_entry(base, &pp->pdir.entry);
- return 1;
- }
+ if (pp->pdir.devices == NULL)
+ goto out_fail;
+
pp->pdir.devices->read_proc = devices_read_proc;
pp->pdir.devices->data = pp;
pp->pdir.hardware = new_proc_entry("hardware", 0, pp->pdir.entry, 0);
- if (pp->pdir.hardware == NULL) {
- printk(proc_msg, pp->name);
- destroy_proc_entry(pp->pdir.entry, &pp->pdir.devices);
- destroy_proc_entry(pp->pdir.entry, &pp->pdir.irq);
- destroy_proc_entry(base, &pp->pdir.entry);
- return 1;
- }
+ if (pp->pdir.hardware == NULL)
+ goto out_fail;
+
pp->pdir.hardware->read_proc = hardware_read_proc;
pp->pdir.hardware->data = pp;
return 0;
+
+out_fail:
+
+ printk(KERN_ERR "%s: failure registering /proc/ entry.\n", pp->name);
+ destroy_proc_tree(pp);
+ return 1;
}
int parport_proc_unregister(struct parport *pp)
{
- if (pp->pdir.entry) {
- if (pp->pdir.irq)
- destroy_proc_entry(pp->pdir.entry, &pp->pdir.irq);
-
- if (pp->pdir.devices)
- destroy_proc_entry(pp->pdir.entry, &pp->pdir.devices);
-
- if (pp->pdir.hardware)
- destroy_proc_entry(pp->pdir.entry, &pp->pdir.hardware);
-
- if (pp->pdir.probe)
- destroy_proc_entry(pp->pdir.entry, &pp->pdir.probe);
-
- destroy_proc_entry(base, &pp->pdir.entry);
- }
-
+ destroy_proc_tree(pp);
return 0;
}
diff --git a/drivers/misc/parport_share.c b/drivers/misc/parport_share.c
index bd0ae3c8b..7da49fae4 100644
--- a/drivers/misc/parport_share.c
+++ b/drivers/misc/parport_share.c
@@ -1,4 +1,4 @@
-/* $Id: parport_share.c,v 1.11 1998/03/26 10:38:32 ralf Exp $
+/* $Id: parport_share.c,v 1.14 1998/05/04 19:05:05 ralf Exp $
* Parallel-port resource manager code.
*
* Authors: David Campbell <campbell@tirian.che.curtin.edu.au>
@@ -34,7 +34,7 @@
#undef PARPORT_PARANOID
-#define PARPORT_DEFAULT_TIMESLICE (HZ/10)
+#define PARPORT_DEFAULT_TIMESLICE (HZ/5)
static struct parport *portlist = NULL, *portlist_tail = NULL;
static int portcount = 0;
@@ -398,6 +398,7 @@ void parport_release(struct pardevice *dev)
{
struct parport *port = dev->port;
struct pardevice *pd;
+ unsigned long flags;
/* Make sure that dev is the current device */
if (port->cad != dev) {
@@ -405,7 +406,9 @@ void parport_release(struct pardevice *dev)
"when not owner\n", port->name, dev->name);
return;
}
+ spin_lock_irqsave(&port->lock, flags);
port->cad = NULL;
+ spin_unlock_irqrestore(&port->lock, flags);
/* Save control registers */
port->ops->save_state(port, dev->state);
@@ -441,3 +444,24 @@ void parport_release(struct pardevice *dev)
pd->wakeup(pd->private);
}
}
+
+void parport_parse_irqs(int nports, const char *irqstr[], int irqval[])
+{
+ unsigned int i;
+ for (i = 0; i < nports && irqstr[i]; i++) {
+ if (!strncmp(irqstr[i], "auto", 4))
+ irqval[i] = PARPORT_IRQ_AUTO;
+ else if (!strncmp(irqstr[i], "none", 4))
+ irqval[i] = PARPORT_IRQ_NONE;
+ else {
+ char *ep;
+ unsigned long r = simple_strtoul(irqstr[i], &ep, 0);
+ if (ep != irqstr[i])
+ irqval[i] = r;
+ else {
+ printk("parport: bad irq specifier `%s'\n", irqstr[i]);
+ return;
+ }
+ }
+ }
+}