X-Git-Url: https://git.karo-electronics.de/?a=blobdiff_plain;f=drivers%2Fnet%2Firda%2Fsmsc-ircc2.c;h=bbcfc8ec35a1556892adf1cbe87fc7f36dc23295;hb=c1e14a6ea2ae34993f431d2eb9a0f228ac3574eb;hp=dd89bda1f1315914349fe692029108b30dd6262a;hpb=ddbf9ef385bfbef897210733abfb73cb9b94ecec;p=mv-sheeva.git diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c index dd89bda1f13..bbcfc8ec35a 100644 --- a/drivers/net/irda/smsc-ircc2.c +++ b/drivers/net/irda/smsc-ircc2.c @@ -11,6 +11,7 @@ * Copyright (c) 2002 Daniele Peri * All Rights Reserved. * Copyright (c) 2002 Jean Tourrilhes + * Copyright (c) 2006 Linus Walleij * * * Based on smc-ircc.c: @@ -53,6 +54,7 @@ #include #include #include +#include #include #include @@ -60,6 +62,9 @@ #include #include +#ifdef CONFIG_PCI +#include +#endif #include #include @@ -99,6 +104,22 @@ MODULE_PARM_DESC(ircc_transceiver, "Transceiver type"); /* Types */ +#ifdef CONFIG_PCI +struct smsc_ircc_subsystem_configuration { + unsigned short vendor; /* PCI vendor ID */ + unsigned short device; /* PCI vendor ID */ + unsigned short subvendor; /* PCI subsystem vendor ID */ + unsigned short subdevice; /* PCI sybsystem device ID */ + unsigned short sir_io; /* I/O port for SIR */ + unsigned short fir_io; /* I/O port for FIR */ + unsigned char fir_irq; /* FIR IRQ */ + unsigned char fir_dma; /* FIR DMA */ + unsigned short cfg_base; /* I/O port for chip configuration */ + int (*preconfigure)(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf); /* Preconfig function */ + const char *name; /* name shown as info */ +}; +#endif + struct smsc_transceiver { char *name; void (*set_for_speed)(int fir_base, u32 speed); @@ -201,6 +222,16 @@ static int __init smsc_superio_flat(const struct smsc_chip *chips, unsigned shor static int __init smsc_superio_paged(const struct smsc_chip *chips, unsigned short cfg_base, char *type); static int __init smsc_superio_fdc(unsigned short cfg_base); static int __init smsc_superio_lpc(unsigned short cfg_base); +#ifdef CONFIG_PCI +static int __init preconfigure_smsc_chip(struct smsc_ircc_subsystem_configuration *conf); +static int __init preconfigure_through_82801(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf); +static int __init preconfigure_through_ali(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf); +static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg, + unsigned short ircc_fir, + unsigned short ircc_sir, + unsigned char ircc_dma, + unsigned char ircc_irq); +#endif /* Transceivers specific functions */ @@ -213,14 +244,15 @@ static int smsc_ircc_probe_transceiver_smsc_ircc_atc(int fir_base); /* Power Management */ -static int smsc_ircc_suspend(struct device *dev, pm_message_t state, u32 level); -static int smsc_ircc_resume(struct device *dev, u32 level); +static int smsc_ircc_suspend(struct platform_device *dev, pm_message_t state); +static int smsc_ircc_resume(struct platform_device *dev); -static struct device_driver smsc_ircc_driver = { - .name = SMSC_IRCC2_DRIVER_NAME, - .bus = &platform_bus_type, +static struct platform_driver smsc_ircc_driver = { .suspend = smsc_ircc_suspend, .resume = smsc_ircc_resume, + .driver = { + .name = SMSC_IRCC2_DRIVER_NAME, + }, }; /* Transceivers for SMSC-ircc */ @@ -345,12 +377,19 @@ static int __init smsc_ircc_init(void) IRDA_DEBUG(1, "%s\n", __FUNCTION__); - ret = driver_register(&smsc_ircc_driver); + ret = platform_driver_register(&smsc_ircc_driver); if (ret) { IRDA_ERROR("%s, Can't register driver!\n", driver_name); return ret; } +#ifdef CONFIG_PCI + if (smsc_ircc_preconfigure_subsystems(ircc_cfg, ircc_fir, ircc_sir, ircc_dma, ircc_irq) < 0) { + /* Ignore errors from preconfiguration */ + IRDA_ERROR("%s, Preconfiguration failed !\n", driver_name); + } +#endif + dev_count = 0; if (ircc_fir > 0 && ircc_sir > 0) { @@ -377,7 +416,7 @@ static int __init smsc_ircc_init(void) } if (ret) - driver_unregister(&smsc_ircc_driver); + platform_driver_unregister(&smsc_ircc_driver); return ret; } @@ -490,7 +529,7 @@ static int __init smsc_ircc_open(unsigned int fir_base, unsigned int sir_base, u err = PTR_ERR(self->pldev); goto err_out5; } - dev_set_drvdata(&self->pldev->dev, self); + platform_set_drvdata(self->pldev, self); IRDA_MESSAGE("IrDA: Registered device %s\n", dev->name); dev_count++; @@ -638,21 +677,14 @@ static void smsc_ircc_setup_qos(struct smsc_ircc_cb *self) */ static void smsc_ircc_init_chip(struct smsc_ircc_cb *self) { - int iobase, ir_mode, ctrl, fast; - - IRDA_ASSERT(self != NULL, return;); - - iobase = self->io.fir_base; - ir_mode = IRCC_CFGA_IRDA_SIR_A; - ctrl = 0; - fast = 0; + int iobase = self->io.fir_base; register_bank(iobase, 0); outb(IRCC_MASTER_RESET, iobase + IRCC_MASTER); outb(0x00, iobase + IRCC_MASTER); register_bank(iobase, 1); - outb(((inb(iobase + IRCC_SCE_CFGA) & 0x87) | ir_mode), + outb(((inb(iobase + IRCC_SCE_CFGA) & 0x87) | IRCC_CFGA_IRDA_SIR_A), iobase + IRCC_SCE_CFGA); #ifdef smsc_669 /* Uses pin 88/89 for Rx/Tx */ @@ -666,10 +698,10 @@ static void smsc_ircc_init_chip(struct smsc_ircc_cb *self) outb(SMSC_IRCC2_FIFO_THRESHOLD, iobase + IRCC_FIFO_THRESHOLD); register_bank(iobase, 4); - outb((inb(iobase + IRCC_CONTROL) & 0x30) | ctrl, iobase + IRCC_CONTROL); + outb((inb(iobase + IRCC_CONTROL) & 0x30), iobase + IRCC_CONTROL); register_bank(iobase, 0); - outb(fast, iobase + IRCC_LCR_A); + outb(0, iobase + IRCC_LCR_A); smsc_ircc_set_sir_speed(self, SMSC_IRCC2_C_IRDA_FALLBACK_SPEED); @@ -1556,6 +1588,46 @@ static int ircc_is_receiving(struct smsc_ircc_cb *self) } #endif /* unused */ +static int smsc_ircc_request_irq(struct smsc_ircc_cb *self) +{ + int error; + + error = request_irq(self->io.irq, smsc_ircc_interrupt, 0, + self->netdev->name, self->netdev); + if (error) + IRDA_DEBUG(0, "%s(), unable to allocate irq=%d, err=%d\n", + __FUNCTION__, self->io.irq, error); + + return error; +} + +static void smsc_ircc_start_interrupts(struct smsc_ircc_cb *self) +{ + unsigned long flags; + + spin_lock_irqsave(&self->lock, flags); + + self->io.speed = 0; + smsc_ircc_change_speed(self, SMSC_IRCC2_C_IRDA_FALLBACK_SPEED); + + spin_unlock_irqrestore(&self->lock, flags); +} + +static void smsc_ircc_stop_interrupts(struct smsc_ircc_cb *self) +{ + int iobase = self->io.fir_base; + unsigned long flags; + + spin_lock_irqsave(&self->lock, flags); + + register_bank(iobase, 0); + outb(0, iobase + IRCC_IER); + outb(IRCC_MASTER_RESET, iobase + IRCC_MASTER); + outb(0x00, iobase + IRCC_MASTER); + + spin_unlock_irqrestore(&self->lock, flags); +} + /* * Function smsc_ircc_net_open (dev) @@ -1567,7 +1639,6 @@ static int smsc_ircc_net_open(struct net_device *dev) { struct smsc_ircc_cb *self; char hwname[16]; - unsigned long flags; IRDA_DEBUG(1, "%s\n", __FUNCTION__); @@ -1575,6 +1646,11 @@ static int smsc_ircc_net_open(struct net_device *dev) self = netdev_priv(dev); IRDA_ASSERT(self != NULL, return 0;); + if (self->io.suspended) { + IRDA_DEBUG(0, "%s(), device is suspended\n", __FUNCTION__); + return -EAGAIN; + } + if (request_irq(self->io.irq, smsc_ircc_interrupt, 0, dev->name, (void *) dev)) { IRDA_DEBUG(0, "%s(), unable to allocate irq=%d\n", @@ -1582,11 +1658,7 @@ static int smsc_ircc_net_open(struct net_device *dev) return -EAGAIN; } - spin_lock_irqsave(&self->lock, flags); - /*smsc_ircc_sir_start(self);*/ - self->io.speed = 0; - smsc_ircc_change_speed(self, SMSC_IRCC2_C_IRDA_FALLBACK_SPEED); - spin_unlock_irqrestore(&self->lock, flags); + smsc_ircc_start_interrupts(self); /* Give self a hardware name */ /* It would be cool to offer the chip revision here - Jean II */ @@ -1639,37 +1711,63 @@ static int smsc_ircc_net_close(struct net_device *dev) irlap_close(self->irlap); self->irlap = NULL; - free_irq(self->io.irq, dev); + smsc_ircc_stop_interrupts(self); + + /* if we are called from smsc_ircc_resume we don't have IRQ reserved */ + if (!self->io.suspended) + free_irq(self->io.irq, dev); + disable_dma(self->io.dma); free_dma(self->io.dma); return 0; } -static int smsc_ircc_suspend(struct device *dev, pm_message_t state, u32 level) +static int smsc_ircc_suspend(struct platform_device *dev, pm_message_t state) { - struct smsc_ircc_cb *self = dev_get_drvdata(dev); + struct smsc_ircc_cb *self = platform_get_drvdata(dev); - IRDA_MESSAGE("%s, Suspending\n", driver_name); + if (!self->io.suspended) { + IRDA_DEBUG(1, "%s, Suspending\n", driver_name); - if (level == SUSPEND_DISABLE && !self->io.suspended) { - smsc_ircc_net_close(self->netdev); + rtnl_lock(); + if (netif_running(self->netdev)) { + netif_device_detach(self->netdev); + smsc_ircc_stop_interrupts(self); + free_irq(self->io.irq, self->netdev); + disable_dma(self->io.dma); + } self->io.suspended = 1; + rtnl_unlock(); } return 0; } -static int smsc_ircc_resume(struct device *dev, u32 level) +static int smsc_ircc_resume(struct platform_device *dev) { - struct smsc_ircc_cb *self = dev_get_drvdata(dev); - - if (level == RESUME_ENABLE && self->io.suspended) { - - smsc_ircc_net_open(self->netdev); + struct smsc_ircc_cb *self = platform_get_drvdata(dev); + + if (self->io.suspended) { + IRDA_DEBUG(1, "%s, Waking up\n", driver_name); + + rtnl_lock(); + smsc_ircc_init_chip(self); + if (netif_running(self->netdev)) { + if (smsc_ircc_request_irq(self)) { + /* + * Don't fail resume process, just kill this + * network interface + */ + unregister_netdevice(self->netdev); + } else { + enable_dma(self->io.dma); + smsc_ircc_start_interrupts(self); + netif_device_attach(self->netdev); + } + } self->io.suspended = 0; - - IRDA_MESSAGE("%s, Waking up\n", driver_name); + rtnl_unlock(); } return 0; } @@ -1682,9 +1780,6 @@ static int smsc_ircc_resume(struct device *dev, u32 level) */ static int __exit smsc_ircc_close(struct smsc_ircc_cb *self) { - int iobase; - unsigned long flags; - IRDA_DEBUG(1, "%s\n", __FUNCTION__); IRDA_ASSERT(self != NULL, return -1;); @@ -1694,22 +1789,7 @@ static int __exit smsc_ircc_close(struct smsc_ircc_cb *self) /* Remove netdevice */ unregister_netdev(self->netdev); - /* Make sure the irq handler is not exectuting */ - spin_lock_irqsave(&self->lock, flags); - - /* Stop interrupts */ - iobase = self->io.fir_base; - register_bank(iobase, 0); - outb(0, iobase + IRCC_IER); - outb(IRCC_MASTER_RESET, iobase + IRCC_MASTER); - outb(0x00, iobase + IRCC_MASTER); -#if 0 - /* Reset to SIR mode */ - register_bank(iobase, 1); - outb(IRCC_CFGA_IRDA_SIR_A|IRCC_CFGA_TX_POLARITY, iobase + IRCC_SCE_CFGA); - outb(IRCC_CFGB_IR, iobase + IRCC_SCE_CFGB); -#endif - spin_unlock_irqrestore(&self->lock, flags); + smsc_ircc_stop_interrupts(self); /* Release the PORTS that this driver is using */ IRDA_DEBUG(0, "%s(), releasing 0x%03x\n", __FUNCTION__, @@ -1746,7 +1826,7 @@ static void __exit smsc_ircc_cleanup(void) smsc_ircc_close(dev_self[i]); } - driver_unregister(&smsc_ircc_driver); + platform_driver_unregister(&smsc_ircc_driver); } /* @@ -2242,6 +2322,280 @@ static int __init smsc_superio_lpc(unsigned short cfg_base) return ret; } +/* + * Look for some specific subsystem setups that need + * pre-configuration not properly done by the BIOS (especially laptops) + * This code is based in part on smcinit.c, tosh1800-smcinit.c + * and tosh2450-smcinit.c. The table lists the device entries + * for ISA bridges with an LPC (Local Peripheral Configurator) + * that are in turn used to configure the SMSC device with default + * SIR and FIR I/O ports, DMA and IRQ. + */ +#ifdef CONFIG_PCI +#define PCIID_VENDOR_INTEL 0x8086 +#define PCIID_VENDOR_ALI 0x10b9 +static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __devinitdata = { + { + .vendor = PCIID_VENDOR_INTEL, /* Intel 82801DBM LPC bridge */ + .device = 0x24cc, + .subvendor = 0x103c, + .subdevice = 0x088c, + .sir_io = 0x02f8, /* Quite certain these are the same for nc8000 as for nc6000 */ + .fir_io = 0x0130, + .fir_irq = 0x09, + .fir_dma = 0x03, + .cfg_base = 0x004e, + .preconfigure = preconfigure_through_82801, + .name = "HP nc8000", + }, + { + .vendor = PCIID_VENDOR_INTEL, /* Intel 82801DBM LPC bridge */ + .device = 0x24cc, + .subvendor = 0x103c, + .subdevice = 0x0890, + .sir_io = 0x02f8, + .fir_io = 0x0130, + .fir_irq = 0x09, + .fir_dma = 0x03, + .cfg_base = 0x004e, + .preconfigure = preconfigure_through_82801, + .name = "HP nc6000", + }, + { + .vendor = PCIID_VENDOR_INTEL, /* Intel 82801DB/DBL (ICH4/ICH4-L) LPC Interface Bridge */ + .device = 0x24c0, + .subvendor = 0x1179, + .subdevice = 0xffff, /* 0xffff is "any", Not sure, 0x0001 or 0x0002 */ + .sir_io = 0x03f8, + .fir_io = 0x0130, + .fir_irq = 0x07, + .fir_dma = 0x01, + .cfg_base = 0x002e, + .preconfigure = preconfigure_through_82801, + .name = "Toshiba Satellite 2450", + }, + { + .vendor = PCIID_VENDOR_INTEL, /* Intel 82801CAM ISA bridge */ + .device = 0x248c, /* Some use 24cc? */ + .subvendor = 0x1179, + .subdevice = 0xffff, /* 0xffff is "any", Not sure, 0x0001 or 0x0002 */ + .sir_io = 0x03f8, + .fir_io = 0x0130, + .fir_irq = 0x03, + .fir_dma = 0x03, + .cfg_base = 0x002e, + .preconfigure = preconfigure_through_82801, + .name = "Toshiba Satellite 5100/5200, Tecra 9100", + }, + { + .vendor = PCIID_VENDOR_ALI, /* ALi M1533/M1535 PCI to ISA Bridge [Aladdin IV/V/V+] */ + .device = 0x1533, + .subvendor = 0x1179, + .subdevice = 0xffff, /* 0xffff is "any", Not sure, 0x0001 or 0x0002 */ + .sir_io = 0x02e8, + .fir_io = 0x02f8, + .fir_irq = 0x07, + .fir_dma = 0x03, + .cfg_base = 0x002e, + .preconfigure = preconfigure_through_ali, + .name = "Toshiba Satellite 1800", + }, + { } // Terminator +}; + + +/* + * This sets up the basic SMSC parameters (FIR port, SIR port, FIR DMA, FIR IRQ) + * through the chip configuration port. + */ +static int __init preconfigure_smsc_chip(struct smsc_ircc_subsystem_configuration *conf) +{ + unsigned short iobase = conf->cfg_base; + unsigned char tmpbyte; + + outb(LPC47N227_CFGACCESSKEY, iobase); // enter configuration state + outb(SMSCSIOFLAT_DEVICEID_REG, iobase); // set for device ID + tmpbyte = inb(iobase +1); // Read device ID + IRDA_DEBUG(0, "Detected Chip id: 0x%02x, setting up registers...\n",tmpbyte); + + /* Disable UART1 and set up SIR I/O port */ + outb(0x24, iobase); // select CR24 - UART1 base addr + outb(0x00, iobase + 1); // disable UART1 + outb(SMSCSIOFLAT_UART2BASEADDR_REG, iobase); // select CR25 - UART2 base addr + outb( (conf->sir_io >> 2), iobase + 1); // bits 2-9 of 0x3f8 + tmpbyte = inb(iobase + 1); + if (tmpbyte != (conf->sir_io >> 2) ) { + IRDA_WARNING("ERROR: could not configure SIR ioport.\n"); + return -ENXIO; + } + + /* Set up FIR IRQ channel for UART2 */ + outb(SMSCSIOFLAT_UARTIRQSELECT_REG, iobase); // select CR28 - UART1,2 IRQ select + tmpbyte = inb(iobase + 1); + tmpbyte &= SMSCSIOFLAT_UART1IRQSELECT_MASK; // Do not touch the UART1 portion + tmpbyte |= (conf->fir_irq & SMSCSIOFLAT_UART2IRQSELECT_MASK); + outb(tmpbyte, iobase + 1); + tmpbyte = inb(iobase + 1) & SMSCSIOFLAT_UART2IRQSELECT_MASK; + if (tmpbyte != conf->fir_irq) { + IRDA_WARNING("ERROR: could not configure FIR IRQ channel.\n"); + return -ENXIO; + } + + /* Set up FIR I/O port */ + outb(SMSCSIOFLAT_FIRBASEADDR_REG, iobase); // CR2B - SCE (FIR) base addr + outb((conf->fir_io >> 3), iobase + 1); + tmpbyte = inb(iobase + 1); + if (tmpbyte != (conf->fir_io >> 3) ) { + IRDA_WARNING("ERROR: could not configure FIR I/O port.\n"); + return -ENXIO; + } + + /* Set up FIR DMA channel */ + outb(SMSCSIOFLAT_FIRDMASELECT_REG, iobase); // CR2C - SCE (FIR) DMA select + outb((conf->fir_dma & LPC47N227_FIRDMASELECT_MASK), iobase + 1); // DMA + tmpbyte = inb(iobase + 1) & LPC47N227_FIRDMASELECT_MASK; + if (tmpbyte != (conf->fir_dma & LPC47N227_FIRDMASELECT_MASK)) { + IRDA_WARNING("ERROR: could not configure FIR DMA channel.\n"); + return -ENXIO; + } + + outb(SMSCSIOFLAT_UARTMODE0C_REG, iobase); // CR0C - UART mode + tmpbyte = inb(iobase + 1); + tmpbyte &= ~SMSCSIOFLAT_UART2MODE_MASK | SMSCSIOFLAT_UART2MODE_VAL_IRDA; + outb(tmpbyte, iobase + 1); // enable IrDA (HPSIR) mode, high speed + + outb(LPC47N227_APMBOOTDRIVE_REG, iobase); // CR07 - Auto Pwr Mgt/boot drive sel + tmpbyte = inb(iobase + 1); + outb(tmpbyte | LPC47N227_UART2AUTOPWRDOWN_MASK, iobase + 1); // enable UART2 autopower down + + /* This one was not part of tosh1800 */ + outb(0x0a, iobase); // CR0a - ecp fifo / ir mux + tmpbyte = inb(iobase + 1); + outb(tmpbyte | 0x40, iobase + 1); // send active device to ir port + + outb(LPC47N227_UART12POWER_REG, iobase); // CR02 - UART 1,2 power + tmpbyte = inb(iobase + 1); + outb(tmpbyte | LPC47N227_UART2POWERDOWN_MASK, iobase + 1); // UART2 power up mode, UART1 power down + + outb(LPC47N227_FDCPOWERVALIDCONF_REG, iobase); // CR00 - FDC Power/valid config cycle + tmpbyte = inb(iobase + 1); + outb(tmpbyte | LPC47N227_VALID_MASK, iobase + 1); // valid config cycle done + + outb(LPC47N227_CFGEXITKEY, iobase); // Exit configuration + + return 0; +} + +/* 82801CAM registers */ +#define VID 0x00 +#define DID 0x02 +#define PIRQA_ROUT 0x60 +#define PCI_DMA_C 0x90 +#define COM_DEC 0xe0 +#define LPC_EN 0xe6 +#define GEN2_DEC 0xec +/* + * Sets up the I/O range using the 82801CAM ISA bridge, 82801DBM LPC bridge or + * Intel 82801DB/DBL (ICH4/ICH4-L) LPC Interface Bridge. They all work the same way! + */ +static int __init preconfigure_through_82801(struct pci_dev *dev, + struct smsc_ircc_subsystem_configuration *conf) +{ + unsigned short tmpword; + int ret; + + IRDA_MESSAGE("Setting up the SMSC device via the 82801 controller.\n"); + pci_write_config_byte(dev, COM_DEC, 0x10); + + /* Enable LPC */ + pci_read_config_word(dev, LPC_EN, &tmpword); /* LPC_EN register */ + tmpword &= 0xfffd; /* mask bit 1 */ + tmpword |= 0x0001; /* set bit 0 : COMA addr range enable */ + pci_write_config_word(dev, LPC_EN, tmpword); + + /* Setup DMA */ + pci_write_config_word(dev, PCI_DMA_C, 0xc0c0); /* LPC I/F DMA on, channel 3 -- rtm (?? PCI DMA ?) */ + pci_write_config_word(dev, GEN2_DEC, 0x131); /* LPC I/F 2nd decode range */ + + /* Pre-configure chip */ + ret = preconfigure_smsc_chip(conf); + + /* Disable LPC */ + pci_read_config_word(dev, LPC_EN, &tmpword); /* LPC_EN register */ + tmpword &= 0xfffc; /* mask bit 1 and bit 0, COMA addr range disable */ + pci_write_config_word(dev, LPC_EN, tmpword); + return ret; +} + +static int __init preconfigure_through_ali(struct pci_dev *dev, + struct smsc_ircc_subsystem_configuration *conf) +{ + /* TODO: put in ALi 1533 configuration here. */ + IRDA_MESSAGE("SORRY: %s has an unsupported bridge controller (ALi): not pre-configured.\n", conf->name); + return -ENODEV; +} + +static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg, + unsigned short ircc_fir, + unsigned short ircc_sir, + unsigned char ircc_dma, + unsigned char ircc_irq) +{ + struct pci_dev *dev = NULL; + unsigned short ss_vendor = 0x0000; + unsigned short ss_device = 0x0000; + int ret = 0; + + dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev); + + while (dev != NULL) { + struct smsc_ircc_subsystem_configuration *conf; + + /* + * Cache the subsystem vendor/device: some manufacturers fail to set + * this for all components, so we save it in case there is just + * 0x0000 0x0000 on the device we want to check. + */ + if (dev->subsystem_vendor != 0x0000U) { + ss_vendor = dev->subsystem_vendor; + ss_device = dev->subsystem_device; + } + conf = subsystem_configurations; + for( ; conf->subvendor; conf++) { + if(conf->vendor == dev->vendor && + conf->device == dev->device && + conf->subvendor == ss_vendor && /* Sometimes these are cached values */ + (conf->subdevice == ss_device || conf->subdevice == 0xffff)) { + struct smsc_ircc_subsystem_configuration tmpconf; + + memcpy(&tmpconf, conf, sizeof(struct smsc_ircc_subsystem_configuration)); + + /* Override the default values with anything passed in as parameter */ + if (ircc_cfg != 0) + tmpconf.cfg_base = ircc_cfg; + if (ircc_fir != 0) + tmpconf.fir_io = ircc_fir; + if (ircc_sir != 0) + tmpconf.sir_io = ircc_sir; + if (ircc_dma != 0xff) + tmpconf.fir_dma = ircc_dma; + if (ircc_irq != 0xff) + tmpconf.fir_irq = ircc_irq; + + IRDA_MESSAGE("Detected unconfigured %s SMSC IrDA chip, pre-configuring device.\n", conf->name); + if (conf->preconfigure) + ret = conf->preconfigure(dev, &tmpconf); + else + ret = -ENODEV; + } + } + dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev); + } + + return ret; +} +#endif // CONFIG_PCI + /************************************************ * * Transceivers specific functions