From: parport_sunbpp switched to keeping track of the ports it had created; in module_exit it uses the private list instead of messing with parport_enumerate(). Added check for sbus_ioremap() failure in port initialization. --- drivers/parport/parport_sunbpp.c | 84 +++++++++++++++++++++++---------------- 1 files changed, 50 insertions(+), 34 deletions(-) diff -puN drivers/parport/parport_sunbpp.c~parport-10-sunbpp-track-ports drivers/parport/parport_sunbpp.c --- 25/drivers/parport/parport_sunbpp.c~parport-10-sunbpp-track-ports 2004-02-18 23:44:04.000000000 -0800 +++ 25-akpm/drivers/parport/parport_sunbpp.c 2004-02-18 23:44:04.000000000 -0800 @@ -286,39 +286,49 @@ static struct parport_operations parport .owner = THIS_MODULE, }; +typedef struct { + struct list_head list; + struct parport *port; +} Node; +/* no locks, everything's serialized */ +static LIST_HEAD(port_list); + static int __init init_one_port(struct sbus_dev *sdev) { struct parport *p; /* at least in theory there may be a "we don't dma" case */ struct parport_operations *ops; unsigned long base; - int irq, dma, err, size; + int irq, dma, err = 0, size; struct bpp_regs *regs; unsigned char value_tcr; + Node *node; dprintk((KERN_DEBUG "init_one_port(%p): ranges, alloc_io, ", sdev)); + node = kmalloc(sizeof(Node), GFP_KERNEL); + if (!node) + goto out0; + irq = sdev->irqs[0]; base = sbus_ioremap(&sdev->resource[0], 0, sdev->reg_addrs[0].reg_size, "sunbpp"); + if (!base) + goto out1; + size = sdev->reg_addrs[0].reg_size; dma = PARPORT_DMA_NONE; dprintk(("alloc(ppops), ")); ops = kmalloc (sizeof (struct parport_operations), GFP_KERNEL); - if (!ops) { - sbus_iounmap(base, size); - return 0; - } + if (!ops) + goto out2; memcpy (ops, &parport_sunbpp_ops, sizeof (struct parport_operations)); dprintk(("register_port\n")); - if (!(p = parport_register_port(base, irq, dma, ops))) { - kfree(ops); - sbus_iounmap(base, size); - return 0; - } + if (!(p = parport_register_port(base, irq, dma, ops))) + goto out3; p->size = size; @@ -327,14 +337,10 @@ static int __init init_one_port(struct s if ((err = request_irq(p->irq, parport_sunbpp_interrupt, SA_SHIRQ, p->name, p)) != 0) { dprintk(("ERROR %d\n", err)); - parport_put_port(p); - kfree(ops); - sbus_iounmap(base, size); - return err; - } else { - dprintk(("OK\n")); - parport_sunbpp_enable_irq(p); + goto out4; } + dprintk(("OK\n")); + parport_sunbpp_enable_irq(p); regs = (struct bpp_regs *)p->base; dprintk((KERN_DEBUG "forward\n")); @@ -343,9 +349,22 @@ static int __init init_one_port(struct s sbus_writeb(value_tcr, ®s->p_tcr); printk(KERN_INFO "%s: sunbpp at 0x%lx\n", p->name, p->base); + node->port = p; + list_add(&node->list, &port_list); parport_announce_port (p); return 1; + +out4: + parport_put_port(p); +out3: + kfree(ops); +out2: + sbus_iounmap(base, size); +out1: + kfree(node); +out0: + return err; } static int __init parport_sunbpp_init(void) @@ -365,24 +384,21 @@ static int __init parport_sunbpp_init(vo static void __exit parport_sunbpp_exit(void) { - struct parport *p = parport_enumerate(); - - while (p) { - struct parport *next = p->next; - - if (1/*p->modes & PARPORT_MODE_PCSPP*/) { - struct parport_operations *ops = p->ops; - parport_remove_port(p); - - if (p->irq != PARPORT_IRQ_NONE) { - parport_sunbpp_disable_irq(p); - free_irq(p->irq, p); - } - sbus_iounmap(p->base, p->size); - parport_put_port(p); - kfree (ops); + while (!list_empty(port_list)) { + Node *node = list_entry(port_list.next, Node, list); + struct parport *p = node->port; + struct parport_operations *ops = p->ops; + parport_remove_port(p); + + if (p->irq != PARPORT_IRQ_NONE) { + parport_sunbpp_disable_irq(p); + free_irq(p->irq, p); } - p = next; + sbus_iounmap(p->base, p->size); + parport_put_port(p); + kfree (ops); + list_del(&node->list); + kfree (node); } } _