nsc-ircc.c
来自「linux 内核源代码」· C语言 代码 · 共 2,406 行 · 第 1/4 页
C
2,406 行
case 1: info->fir_base = 0x2e8; break; case 2: info->fir_base = 0x3f8; break; case 3: info->fir_base = 0x2f8; break; } info->sir_base = info->fir_base; IRDA_DEBUG(2, "%s(), probing fir_base=0x%03x\n", __FUNCTION__, info->fir_base); /* Read control signals routing register (CSRT) */ outb(CFG_108_CSRT, cfg_base); reg = inb(cfg_base+1); switch (reg & 0x07) { case 0: info->irq = -1; break; case 1: info->irq = 3; break; case 2: info->irq = 4; break; case 3: info->irq = 5; break; case 4: info->irq = 7; break; case 5: info->irq = 9; break; case 6: info->irq = 11; break; case 7: info->irq = 15; break; } IRDA_DEBUG(2, "%s(), probing irq=%d\n", __FUNCTION__, info->irq); /* Currently we only read Rx DMA but it will also be used for Tx */ switch ((reg >> 3) & 0x03) { case 0: info->dma = -1; break; case 1: info->dma = 0; break; case 2: info->dma = 1; break; case 3: info->dma = 3; break; } IRDA_DEBUG(2, "%s(), probing dma=%d\n", __FUNCTION__, info->dma); /* Read mode control register (MCTL) */ outb(CFG_108_MCTL, cfg_base); reg = inb(cfg_base+1); info->enabled = reg & 0x01; info->suspended = !((reg >> 1) & 0x01); return 0;}/* * Function nsc_ircc_init_338 (chip, info) * * Initialize the NSC '338 chip. Remember that the 87338 needs two * consecutive writes to the data registers while CPU interrupts are * disabled. The 97338 does not require this, but shouldn't be any * harm if we do it anyway. */static int nsc_ircc_init_338(nsc_chip_t *chip, chipio_t *info) { /* No init yet */ return 0;}/* * Function nsc_ircc_probe_338 (chip, info) * * * */static int nsc_ircc_probe_338(nsc_chip_t *chip, chipio_t *info) { int cfg_base = info->cfg_base; int reg, com = 0; int pnp; /* Read funtion enable register (FER) */ outb(CFG_338_FER, cfg_base); reg = inb(cfg_base+1); info->enabled = (reg >> 2) & 0x01; /* Check if we are in Legacy or PnP mode */ outb(CFG_338_PNP0, cfg_base); reg = inb(cfg_base+1); pnp = (reg >> 3) & 0x01; if (pnp) { IRDA_DEBUG(2, "(), Chip is in PnP mode\n"); outb(0x46, cfg_base); reg = (inb(cfg_base+1) & 0xfe) << 2; outb(0x47, cfg_base); reg |= ((inb(cfg_base+1) & 0xfc) << 8); info->fir_base = reg; } else { /* Read function address register (FAR) */ outb(CFG_338_FAR, cfg_base); reg = inb(cfg_base+1); switch ((reg >> 4) & 0x03) { case 0: info->fir_base = 0x3f8; break; case 1: info->fir_base = 0x2f8; break; case 2: com = 3; break; case 3: com = 4; break; } if (com) { switch ((reg >> 6) & 0x03) { case 0: if (com == 3) info->fir_base = 0x3e8; else info->fir_base = 0x2e8; break; case 1: if (com == 3) info->fir_base = 0x338; else info->fir_base = 0x238; break; case 2: if (com == 3) info->fir_base = 0x2e8; else info->fir_base = 0x2e0; break; case 3: if (com == 3) info->fir_base = 0x220; else info->fir_base = 0x228; break; } } } info->sir_base = info->fir_base; /* Read PnP register 1 (PNP1) */ outb(CFG_338_PNP1, cfg_base); reg = inb(cfg_base+1); info->irq = reg >> 4; /* Read PnP register 3 (PNP3) */ outb(CFG_338_PNP3, cfg_base); reg = inb(cfg_base+1); info->dma = (reg & 0x07) - 1; /* Read power and test register (PTR) */ outb(CFG_338_PTR, cfg_base); reg = inb(cfg_base+1); info->suspended = reg & 0x01; return 0;}/* * Function nsc_ircc_init_39x (chip, info) * * Now that we know it's a '39x (see probe below), we need to * configure it so we can use it. * * The NSC '338 chip is a Super I/O chip with a "bank" architecture, * the configuration of the different functionality (serial, parallel, * floppy...) are each in a different bank (Logical Device Number). * The base address, irq and dma configuration registers are common * to all functionalities (index 0x30 to 0x7F). * There is only one configuration register specific to the * serial port, CFG_39X_SPC. * JeanII * * Note : this code was written by Jan Frey <janfrey@web.de> */static int nsc_ircc_init_39x(nsc_chip_t *chip, chipio_t *info) { int cfg_base = info->cfg_base; int enabled; /* User is sure about his config... accept it. */ IRDA_DEBUG(2, "%s(): nsc_ircc_init_39x (user settings): " "io=0x%04x, irq=%d, dma=%d\n", __FUNCTION__, info->fir_base, info->irq, info->dma); /* Access bank for SP2 */ outb(CFG_39X_LDN, cfg_base); outb(0x02, cfg_base+1); /* Configure SP2 */ /* We want to enable the device if not enabled */ outb(CFG_39X_ACT, cfg_base); enabled = inb(cfg_base+1) & 0x01; if (!enabled) { /* Enable the device */ outb(CFG_39X_SIOCF1, cfg_base); outb(0x01, cfg_base+1); /* May want to update info->enabled. Jean II */ } /* Enable UART bank switching (bit 7) ; Sets the chip to normal * power mode (wake up from sleep mode) (bit 1) */ outb(CFG_39X_SPC, cfg_base); outb(0x82, cfg_base+1); return 0;}/* * Function nsc_ircc_probe_39x (chip, info) * * Test if we really have a '39x chip at the given address * * Note : this code was written by Jan Frey <janfrey@web.de> */static int nsc_ircc_probe_39x(nsc_chip_t *chip, chipio_t *info) { int cfg_base = info->cfg_base; int reg1, reg2, irq, irqt, dma1, dma2; int enabled, susp; IRDA_DEBUG(2, "%s(), nsc_ircc_probe_39x, base=%d\n", __FUNCTION__, cfg_base); /* This function should be executed with irq off to avoid * another driver messing with the Super I/O bank - Jean II */ /* Access bank for SP2 */ outb(CFG_39X_LDN, cfg_base); outb(0x02, cfg_base+1); /* Read infos about SP2 ; store in info struct */ outb(CFG_39X_BASEH, cfg_base); reg1 = inb(cfg_base+1); outb(CFG_39X_BASEL, cfg_base); reg2 = inb(cfg_base+1); info->fir_base = (reg1 << 8) | reg2; outb(CFG_39X_IRQNUM, cfg_base); irq = inb(cfg_base+1); outb(CFG_39X_IRQSEL, cfg_base); irqt = inb(cfg_base+1); info->irq = irq; outb(CFG_39X_DMA0, cfg_base); dma1 = inb(cfg_base+1); outb(CFG_39X_DMA1, cfg_base); dma2 = inb(cfg_base+1); info->dma = dma1 -1; outb(CFG_39X_ACT, cfg_base); info->enabled = enabled = inb(cfg_base+1) & 0x01; outb(CFG_39X_SPC, cfg_base); susp = 1 - ((inb(cfg_base+1) & 0x02) >> 1); IRDA_DEBUG(2, "%s(): io=0x%02x%02x, irq=%d (type %d), rxdma=%d, txdma=%d, enabled=%d (suspended=%d)\n", __FUNCTION__, reg1,reg2,irq,irqt,dma1,dma2,enabled,susp); /* Configure SP2 */ /* We want to enable the device if not enabled */ outb(CFG_39X_ACT, cfg_base); enabled = inb(cfg_base+1) & 0x01; if (!enabled) { /* Enable the device */ outb(CFG_39X_SIOCF1, cfg_base); outb(0x01, cfg_base+1); /* May want to update info->enabled. Jean II */ } /* Enable UART bank switching (bit 7) ; Sets the chip to normal * power mode (wake up from sleep mode) (bit 1) */ outb(CFG_39X_SPC, cfg_base); outb(0x82, cfg_base+1); return 0;}/* PNP probing */static int nsc_ircc_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *id){ memset(&pnp_info, 0, sizeof(chipio_t)); pnp_info.irq = -1; pnp_info.dma = -1; pnp_succeeded = 1; /* There don't seem to be any way to get the cfg_base. * On my box, cfg_base is in the PnP descriptor of the * motherboard. Oh well... Jean II */ if (pnp_port_valid(dev, 0) && !(pnp_port_flags(dev, 0) & IORESOURCE_DISABLED)) pnp_info.fir_base = pnp_port_start(dev, 0); if (pnp_irq_valid(dev, 0) && !(pnp_irq_flags(dev, 0) & IORESOURCE_DISABLED)) pnp_info.irq = pnp_irq(dev, 0); if (pnp_dma_valid(dev, 0) && !(pnp_dma_flags(dev, 0) & IORESOURCE_DISABLED)) pnp_info.dma = pnp_dma(dev, 0); IRDA_DEBUG(0, "%s() : From PnP, found firbase 0x%03X ; irq %d ; dma %d.\n", __FUNCTION__, pnp_info.fir_base, pnp_info.irq, pnp_info.dma); if((pnp_info.fir_base == 0) || (pnp_info.irq == -1) || (pnp_info.dma == -1)) { /* Returning an error will disable the device. Yuck ! */ //return -EINVAL; pnp_succeeded = 0; } return 0;}/* * Function nsc_ircc_setup (info) * * Returns non-negative on success. * */static int nsc_ircc_setup(chipio_t *info){ int version; int iobase = info->fir_base; /* Read the Module ID */ switch_bank(iobase, BANK3); version = inb(iobase+MID); IRDA_DEBUG(2, "%s() Driver %s Found chip version %02x\n", __FUNCTION__, driver_name, version); /* Should be 0x2? */ if (0x20 != (version & 0xf0)) { IRDA_ERROR("%s, Wrong chip version %02x\n", driver_name, version); return -1; } /* Switch to advanced mode */ switch_bank(iobase, BANK2); outb(ECR1_EXT_SL, iobase+ECR1); switch_bank(iobase, BANK0); /* Set FIFO threshold to TX17, RX16, reset and enable FIFO's */ switch_bank(iobase, BANK0); outb(FCR_RXTH|FCR_TXTH|FCR_TXSR|FCR_RXSR|FCR_FIFO_EN, iobase+FCR); outb(0x03, iobase+LCR); /* 8 bit word length */ outb(MCR_SIR, iobase+MCR); /* Start at SIR-mode, also clears LSR*/ /* Set FIFO size to 32 */ switch_bank(iobase, BANK2); outb(EXCR2_RFSIZ|EXCR2_TFSIZ, iobase+EXCR2); /* IRCR2: FEND_MD is not set */ switch_bank(iobase, BANK5); outb(0x02, iobase+4); /* Make sure that some defaults are OK */ switch_bank(iobase, BANK6); outb(0x20, iobase+0); /* Set 32 bits FIR CRC */ outb(0x0a, iobase+1); /* Set MIR pulse width */ outb(0x0d, iobase+2); /* Set SIR pulse width to 1.6us */ outb(0x2a, iobase+4); /* Set beginning frag, and preamble length */ /* Enable receive interrupts */ switch_bank(iobase, BANK0); outb(IER_RXHDL_IE, iobase+IER); return 0;}/* * Function nsc_ircc_read_dongle_id (void) * * Try to read dongle indentification. This procedure needs to be executed * once after power-on/reset. It also needs to be used whenever you suspect * that the user may have plugged/unplugged the IrDA Dongle. */static int nsc_ircc_read_dongle_id (int iobase){ int dongle_id; __u8 bank; bank = inb(iobase+BSR); /* Select Bank 7 */ switch_bank(iobase, BANK7); /* IRCFG4: IRSL0_DS and IRSL21_DS are cleared */ outb(0x00, iobase+7); /* ID0, 1, and 2 are pulled up/down very slowly */ udelay(50); /* IRCFG1: read the ID bits */ dongle_id = inb(iobase+4) & 0x0f;#ifdef BROKEN_DONGLE_ID if (dongle_id == 0x0a) dongle_id = 0x09;#endif /* Go back to bank 0 before returning */ switch_bank(iobase, BANK0); outb(bank, iobase+BSR); return dongle_id;}/* * Function nsc_ircc_init_dongle_interface (iobase, dongle_id) * * This function initializes the dongle for the transceiver that is * used. This procedure needs to be executed once after * power-on/reset. It also needs to be used whenever you suspect that * the dongle is changed. */static void nsc_ircc_init_dongle_interface (int iobase, int dongle_id){ int bank; /* Save current bank */ bank = inb(iobase+BSR); /* Select Bank 7 */ switch_bank(iobase, BANK7); /* IRCFG4: set according to dongle_id */ switch (dongle_id) { case 0x00: /* same as */ case 0x01: /* Differential serial interface */ IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n", __FUNCTION__, dongle_types[dongle_id]); break; case 0x02: /* same as */ case 0x03: /* Reserved */ IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n", __FUNCTION__, dongle_types[dongle_id]); break; case 0x04: /* Sharp RY5HD01 */ break; case 0x05: /* Reserved, but this is what the Thinkpad reports */ IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n", __FUNCTION__, dongle_types[dongle_id]); break; case 0x06: /* Single-ended serial interface */ IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n", __FUNCTION__, dongle_types[dongle_id]); break; case 0x07: /* Consumer-IR only */ IRDA_DEBUG(0, "%s(), %s is not for IrDA mode\n", __FUNCTION__, dongle_types[dongle_id]); break; case 0x08: /* HP HSDL-2300, HP HSDL-3600/HSDL-3610 */ IRDA_DEBUG(0, "%s(), %s\n", __FUNCTION__, dongle_types[dongle_id]); break; case 0x09: /* IBM31T1100 or Temic TFDS6000/TFDS6500 */ outb(0x28, iobase+7); /* Set irsl[0-2] as output */ break; case 0x0A: /* same as */ case 0x0B: /* Reserved */ IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n", __FUNCTION__, dongle_types[dongle_id]); break; case 0x0C: /* same as */ case 0x0D: /* HP HSDL-1100/HSDL-2100 */ /* * Set irsl0 as input, irsl[1-2] as output, and separate * inputs are used for SIR and MIR/FIR */ outb(0x48, iobase+7); break; case 0x0E: /* Supports SIR Mode only */ outb(0x28, iobase+7); /* Set irsl[0-2] as output */ break; case 0x0F: /* No dongle connected */ IRDA_DEBUG(0, "%s(), %s\n", __FUNCTION__, dongle_types[dongle_id]); switch_bank(iobase, BANK0); outb(0x62, iobase+MCR); break; default: IRDA_DEBUG(0, "%s(), invalid dongle_id %#x", __FUNCTION__, dongle_id); } /* IRCFG1: IRSL1 and 2 are set to IrDA mode */ outb(0x00, iobase+4); /* Restore bank register */ outb(bank, iobase+BSR); } /* set_up_dongle_interface *//* * Function nsc_ircc_change_dongle_speed (iobase, speed, dongle_id) * * Change speed of the attach dongle * */static void nsc_ircc_change_dongle_speed(int iobase, int speed, int dongle_id){ __u8 bank; /* Save current bank */ bank = inb(iobase+BSR); /* Select Bank 7 */ switch_bank(iobase, BANK7); /* IRCFG1: set according to dongle_id */ switch (dongle_id) { case 0x00: /* same as */ case 0x01: /* Differential serial interface */ IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n", __FUNCTION__, dongle_types[dongle_id]); break; case 0x02: /* same as */ case 0x03: /* Reserved */ IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n", __FUNCTION__, dongle_types[dongle_id]); break; case 0x04: /* Sharp RY5HD01 */ break; case 0x05: /* Reserved */ IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n", __FUNCTION__, dongle_types[dongle_id]); break; case 0x06: /* Single-ended serial interface */ IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n", __FUNCTION__, dongle_types[dongle_id]); break; case 0x07: /* Consumer-IR only */ IRDA_DEBUG(0, "%s(), %s is not for IrDA mode\n", __FUNCTION__, dongle_types[dongle_id]); break; case 0x08: /* HP HSDL-2300, HP HSDL-3600/HSDL-3610 */ IRDA_DEBUG(0, "%s(), %s\n", __FUNCTION__, dongle_types[dongle_id]); outb(0x00, iobase+4); if (speed > 115200) outb(0x01, iobase+4); break; case 0x09: /* IBM31T1100 or Temic TFDS6000/TFDS6500 */ outb(0x01, iobase+4); if (speed == 4000000) { /* There was a cli() there, but we now are already * under spin_lock_irqsave() - JeanII */ outb(0x81, iobase+4); outb(0x80, iobase+4); } else outb(0x00, iobase+4); break; case 0x0A: /* same as */ case 0x0B: /* Reserved */ IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n", __FUNCTION__, dongle_types[dongle_id]); break;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?