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 + -
显示快捷键?