* Copyright (c) 2002 Daniele Peri
* All Rights Reserved.
* Copyright (c) 2002 Jean Tourrilhes
+ * Copyright (c) 2006 Linus Walleij
*
*
* Based on smc-ircc.c:
#include <linux/rtnetlink.h>
#include <linux/serial_reg.h>
#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <linux/spinlock.h>
#include <linux/pm.h>
+#ifdef CONFIG_PCI
+#include <linux/pci.h>
+#endif
#include <net/irda/wrapper.h>
#include <net/irda/irda.h>
/* 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);
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 */
/* Power Management */
-static int smsc_ircc_suspend(struct device *dev, pm_message_t state);
-static int smsc_ircc_resume(struct device *dev);
+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 */
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) {
}
if (ret)
- driver_unregister(&smsc_ircc_driver);
+ platform_driver_unregister(&smsc_ircc_driver);
return ret;
}
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++;
*/
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 */
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);
}
#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)
{
struct smsc_ircc_cb *self;
char hwname[16];
- unsigned long flags;
IRDA_DEBUG(1, "%s\n", __FUNCTION__);
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",
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 */
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)
+static int smsc_ircc_suspend(struct platform_device *dev, pm_message_t state)
{
- struct smsc_ircc_cb *self = dev_get_drvdata(dev);
-
- IRDA_MESSAGE("%s, Suspending\n", driver_name);
+ struct smsc_ircc_cb *self = platform_get_drvdata(dev);
if (!self->io.suspended) {
- smsc_ircc_net_close(self->netdev);
+ IRDA_DEBUG(1, "%s, Suspending\n", driver_name);
+
+ 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)
+static int smsc_ircc_resume(struct platform_device *dev)
{
- struct smsc_ircc_cb *self = dev_get_drvdata(dev);
+ struct smsc_ircc_cb *self = platform_get_drvdata(dev);
if (self->io.suspended) {
-
- smsc_ircc_net_open(self->netdev);
+ 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;
}
*/
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;);
/* 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__,
smsc_ircc_close(dev_self[i]);
}
- driver_unregister(&smsc_ircc_driver);
+ platform_driver_unregister(&smsc_ircc_driver);
}
/*
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