From: viro@parcelfarce.linux.theplanet.co.uk * switched to proper parport_driver. --- 25-akpm/drivers/scsi/ppa.c | 287 ++++++++++++++++++++++----------------------- 25-akpm/drivers/scsi/ppa.h | 2 2 files changed, 145 insertions(+), 144 deletions(-) diff -puN drivers/scsi/ppa.c~PPA7-ppa_attach-RC1 drivers/scsi/ppa.c --- 25/drivers/scsi/ppa.c~PPA7-ppa_attach-RC1 Wed Jan 14 13:35:50 2004 +++ 25-akpm/drivers/scsi/ppa.c Wed Jan 14 13:35:50 2004 @@ -34,13 +34,11 @@ typedef struct { unsigned wanted:1; /* Parport sharing busy flag */ wait_queue_head_t *waiting; struct Scsi_Host *host; + struct list_head list; } ppa_struct; #include "ppa.h" -#define NO_HOSTS 4 -static ppa_struct ppa_hosts[NO_HOSTS]; - static inline ppa_struct *ppa_dev(struct Scsi_Host *host) { return *(ppa_struct **)&host->hostdata; @@ -103,124 +101,9 @@ static inline void ppa_pb_release(ppa_st parport_release(dev->dev); } -/*************************************************************************** - * Parallel port probing routines * - ***************************************************************************/ - /* * Start of Chipset kludges */ -static Scsi_Host_Template ppa_template; - -static int ppa_probe(ppa_struct *dev, struct parport *pb) -{ - struct Scsi_Host *host; - DECLARE_WAIT_QUEUE_HEAD(waiting); - DEFINE_WAIT(wait); - int ports; - int err; - int modes, ppb, ppb_hi; - - memset(dev, 0, sizeof(dev)); - dev->base = -1; - dev->mode = PPA_AUTODETECT; - dev->recon_tmo = PPA_RECON_TMO; - init_waitqueue_head(&waiting); - dev->dev = parport_register_device(pb, "ppa", NULL, ppa_wakeup, - NULL, 0, dev); - - if (!dev->dev) - return -ENOMEM; - - /* Claim the bus so it remembers what we do to the control - * registers. [ CTR and ECP ] - */ - err = -EBUSY; - dev->waiting = &waiting; - prepare_to_wait(&waiting, &wait, TASK_UNINTERRUPTIBLE); - if (ppa_pb_claim(dev)) - schedule_timeout(3 * HZ); - if (dev->wanted) { - printk(KERN_ERR "ppa%d: failed to claim parport because " - "a pardevice is owning the port for too long " - "time!\n", dev - ppa_hosts); - ppa_pb_dismiss(dev); - dev->waiting = NULL; - finish_wait(&waiting, &wait); - goto out; - } - dev->waiting = NULL; - finish_wait(&waiting, &wait); - ppb = dev->base = dev->dev->port->base; - ppb_hi = dev->dev->port->base_hi; - w_ctr(ppb, 0x0c); - modes = dev->dev->port->modes; - - /* Mode detection works up the chain of speed - * This avoids a nasty if-then-else-if-... tree - */ - dev->mode = PPA_NIBBLE; - - if (modes & PARPORT_MODE_TRISTATE) - dev->mode = PPA_PS2; - - if (modes & PARPORT_MODE_ECP) { - w_ecr(ppb_hi, 0x20); - dev->mode = PPA_PS2; - } - if ((modes & PARPORT_MODE_EPP) && (modes & PARPORT_MODE_ECP)) - w_ecr(ppb_hi, 0x80); - - /* Done configuration */ - - err = ppa_init(dev); - ppa_pb_release(dev); - - if (err) - goto out; - - /* now the glue ... */ - switch (dev->mode) { - case PPA_NIBBLE: - ports = 3; - break; - case PPA_PS2: - ports = 3; - break; - case PPA_EPP_8: - case PPA_EPP_16: - case PPA_EPP_32: - ports = 8; - break; - default: /* Never gets here */ - BUG(); - } - - INIT_WORK(&dev->ppa_tq, ppa_interrupt, dev); - - err = -ENOMEM; - host = scsi_host_alloc(&ppa_template, sizeof(ppa_struct *)); - if (!host) - goto out; - list_add_tail(&host->sht_legacy_list, &ppa_template.legacy_hosts); - host->io_port = pb->base; - host->n_io_port = ports; - host->dma_channel = -1; - host->unique_id = dev - ppa_hosts; - *(ppa_struct **)&host->hostdata = dev; - dev->host = host; - err = scsi_add_host(host, NULL); - if (err) - goto out1; - scsi_scan_host(host); - return 0; -out1: - list_del(&host->sht_legacy_list); - scsi_host_put(host); -out: - parport_unregister_device(dev->dev); - return err; -} /* This is to give the ppa driver a way to modify the timings (and other * parameters) by writing to the /proc/scsi/ppa/0 file. @@ -1112,45 +995,165 @@ static Scsi_Host_Template ppa_template = .can_queue = 1, }; -static int __init ppa_driver_init(void) +/*************************************************************************** + * Parallel port probing routines * + ***************************************************************************/ + +static LIST_HEAD(ppa_hosts); + +static int __ppa_attach(struct parport *pb) { - struct parport *pb = parport_enumerate(); - int i, nhosts; + struct Scsi_Host *host; + DECLARE_WAIT_QUEUE_HEAD(waiting); + DEFINE_WAIT(wait); + ppa_struct *dev; + int ports; + int modes, ppb, ppb_hi; + int err = -ENOMEM; - INIT_LIST_HEAD(&ppa_template.legacy_hosts); + dev = kmalloc(sizeof(ppa_struct), GFP_KERNEL); + if (!dev) + return -ENOMEM; + memset(dev, 0, sizeof(dev)); + dev->base = -1; + dev->mode = PPA_AUTODETECT; + dev->recon_tmo = PPA_RECON_TMO; + init_waitqueue_head(&waiting); + dev->dev = parport_register_device(pb, "ppa", NULL, ppa_wakeup, + NULL, 0, dev); - printk("ppa: Version %s\n", PPA_VERSION); - nhosts = 0; + if (!dev->dev) + goto out; - if (!pb) { - printk("ppa: parport reports no devices.\n"); - return 0; + /* Claim the bus so it remembers what we do to the control + * registers. [ CTR and ECP ] + */ + err = -EBUSY; + dev->waiting = &waiting; + prepare_to_wait(&waiting, &wait, TASK_UNINTERRUPTIBLE); + if (ppa_pb_claim(dev)) + schedule_timeout(3 * HZ); + if (dev->wanted) { + printk(KERN_ERR "ppa%d: failed to claim parport because " + "a pardevice is owning the port for too long " + "time!\n", pb->number); + ppa_pb_dismiss(dev); + dev->waiting = NULL; + finish_wait(&waiting, &wait); + goto out1; } + dev->waiting = NULL; + finish_wait(&waiting, &wait); + ppb = dev->base = dev->dev->port->base; + ppb_hi = dev->dev->port->base_hi; + w_ctr(ppb, 0x0c); + modes = dev->dev->port->modes; + + /* Mode detection works up the chain of speed + * This avoids a nasty if-then-else-if-... tree + */ + dev->mode = PPA_NIBBLE; - for (i = 0; pb; i++, pb = pb->next) { - ppa_struct *dev = &ppa_hosts[i]; - if (ppa_probe(dev, pb)) - nhosts++; + if (modes & PARPORT_MODE_TRISTATE) + dev->mode = PPA_PS2; + + if (modes & PARPORT_MODE_ECP) { + w_ecr(ppb_hi, 0x20); + dev->mode = PPA_PS2; } + if ((modes & PARPORT_MODE_EPP) && (modes & PARPORT_MODE_ECP)) + w_ecr(ppb_hi, 0x80); - return nhosts ? 0 : -ENODEV; + /* Done configuration */ + + err = ppa_init(dev); + ppa_pb_release(dev); + + if (err) + goto out1; + + /* now the glue ... */ + switch (dev->mode) { + case PPA_NIBBLE: + ports = 3; + break; + case PPA_PS2: + ports = 3; + break; + case PPA_EPP_8: + case PPA_EPP_16: + case PPA_EPP_32: + ports = 8; + break; + default: /* Never gets here */ + BUG(); + } + + INIT_WORK(&dev->ppa_tq, ppa_interrupt, dev); + + err = -ENOMEM; + host = scsi_host_alloc(&ppa_template, sizeof(ppa_struct *)); + if (!host) + goto out1; + host->io_port = pb->base; + host->n_io_port = ports; + host->dma_channel = -1; + host->unique_id = pb->number; + *(ppa_struct **)&host->hostdata = dev; + dev->host = host; + list_add_tail(&dev->list, &ppa_hosts); + err = scsi_add_host(host, NULL); + if (err) + goto out2; + scsi_scan_host(host); + return 0; +out2: + list_del_init(&dev->list); + scsi_host_put(host); +out1: + parport_unregister_device(dev->dev); +out: + kfree(dev); + return err; } -static void __exit ppa_driver_exit(void) +static void ppa_attach(struct parport *pb) { - struct scsi_host_template *sht = &ppa_template; - struct Scsi_Host *host, *s; + __ppa_attach(pb); +} - list_for_each_entry(host, &sht->legacy_hosts, sht_legacy_list) - scsi_remove_host(host); - list_for_each_entry_safe(host, s, &sht->legacy_hosts, sht_legacy_list) { - ppa_struct *dev = ppa_dev(host); - list_del(&host->sht_legacy_list); - scsi_host_put(host); - parport_unregister_device(dev->dev); +static void ppa_detach(struct parport *pb) +{ + ppa_struct *dev; + list_for_each_entry(dev, &ppa_hosts, list) { + if (dev->dev->port == pb) { + list_del_init(&dev->list); + scsi_remove_host(dev->host); + scsi_host_put(dev->host); + parport_unregister_device(dev->dev); + kfree(dev); + break; + } } } +static struct parport_driver ppa_driver = { + .name = "ppa", + .attach = ppa_attach, + .detach = ppa_detach, +}; + +static int __init ppa_driver_init(void) +{ + printk("ppa: Version %s\n", PPA_VERSION); + return parport_register_driver(&ppa_driver); +} + +static void __exit ppa_driver_exit(void) +{ + parport_unregister_driver(&ppa_driver); +} + module_init(ppa_driver_init); module_exit(ppa_driver_exit); MODULE_LICENSE("GPL"); diff -puN drivers/scsi/ppa.h~PPA7-ppa_attach-RC1 drivers/scsi/ppa.h --- 25/drivers/scsi/ppa.h~PPA7-ppa_attach-RC1 Wed Jan 14 13:35:50 2004 +++ 25-akpm/drivers/scsi/ppa.h Wed Jan 14 13:35:50 2004 @@ -147,7 +147,5 @@ static char *PPA_MODE_STRING[] = #endif static int ppa_engine(ppa_struct *, Scsi_Cmnd *); -static int ppa_init(ppa_struct *); -static void ppa_interrupt(void *); #endif /* _PPA_H */ _