⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 smsc-ircc2.c

📁 《linux驱动程序设计从入门到精通》一书中所有的程序代码含驱动和相应的应用程序
💻 C
📖 第 1 页 / 共 5 页
字号:
	}	return actual;}/* * Function smsc_ircc_is_receiving (self) * *    Returns true is we are currently receiving data * */static int smsc_ircc_is_receiving(struct smsc_ircc_cb *self){	return (self->rx_buff.state != OUTSIDE_FRAME);}/* * Function smsc_ircc_probe_transceiver(self) * *    Tries to find the used Transceiver * */static void smsc_ircc_probe_transceiver(struct smsc_ircc_cb *self){	unsigned int	i;	IRDA_ASSERT(self != NULL, return;);	for (i = 0; smsc_transceivers[i].name != NULL; i++)		if (smsc_transceivers[i].probe(self->io.fir_base)) {			IRDA_MESSAGE(" %s transceiver found\n",				     smsc_transceivers[i].name);			self->transceiver= i + 1;			return;		}	IRDA_MESSAGE("No transceiver found. Defaulting to %s\n",		     smsc_transceivers[SMSC_IRCC2_C_DEFAULT_TRANSCEIVER].name);	self->transceiver = SMSC_IRCC2_C_DEFAULT_TRANSCEIVER;}/* * Function smsc_ircc_set_transceiver_for_speed(self, speed) * *    Set the transceiver according to the speed * */static void smsc_ircc_set_transceiver_for_speed(struct smsc_ircc_cb *self, u32 speed){	unsigned int trx;	trx = self->transceiver;	if (trx > 0)		smsc_transceivers[trx - 1].set_for_speed(self->io.fir_base, speed);}/* * Function smsc_ircc_wait_hw_transmitter_finish () * *    Wait for the real end of HW transmission * * The UART is a strict FIFO, and we get called only when we have finished * pushing data to the FIFO, so the maximum amount of time we must wait * is only for the FIFO to drain out. * * We use a simple calibrated loop. We may need to adjust the loop * delay (udelay) to balance I/O traffic and latency. And we also need to * adjust the maximum timeout. * It would probably be better to wait for the proper interrupt, * but it doesn't seem to be available. * * We can't use jiffies or kernel timers because : * 1) We are called from the interrupt handler, which disable softirqs, * so jiffies won't be increased * 2) Jiffies granularity is usually very coarse (10ms), and we don't * want to wait that long to detect stuck hardware. * Jean II */static void smsc_ircc_sir_wait_hw_transmitter_finish(struct smsc_ircc_cb *self){	int iobase = self->io.sir_base;	int count = SMSC_IRCC2_HW_TRANSMITTER_TIMEOUT_US;	/* Calibrated busy loop */	while (count-- > 0 && !(inb(iobase + UART_LSR) & UART_LSR_TEMT))		udelay(1);	if (count == 0)		IRDA_DEBUG(0, "%s(): stuck transmitter\n", __FUNCTION__);}/* PROBING * * REVISIT we can be told about the device by PNP, and should use that info * instead of probing hardware and creating a platform_device ... */static int __init smsc_ircc_look_for_chips(void){	struct smsc_chip_address *address;	char *type;	unsigned int cfg_base, found;	found = 0;	address = possible_addresses;	while (address->cfg_base) {		cfg_base = address->cfg_base;		/*printk(KERN_WARNING "%s(): probing: 0x%02x for: 0x%02x\n", __FUNCTION__, cfg_base, address->type);*/		if (address->type & SMSCSIO_TYPE_FDC) {			type = "FDC";			if (address->type & SMSCSIO_TYPE_FLAT)				if (!smsc_superio_flat(fdc_chips_flat, cfg_base, type))					found++;			if (address->type & SMSCSIO_TYPE_PAGED)				if (!smsc_superio_paged(fdc_chips_paged, cfg_base, type))					found++;		}		if (address->type & SMSCSIO_TYPE_LPC) {			type = "LPC";			if (address->type & SMSCSIO_TYPE_FLAT)				if (!smsc_superio_flat(lpc_chips_flat, cfg_base, type))					found++;			if (address->type & SMSCSIO_TYPE_PAGED)				if (!smsc_superio_paged(lpc_chips_paged, cfg_base, type))					found++;		}		address++;	}	return found;}/* * Function smsc_superio_flat (chip, base, type) * *    Try to get configuration of a smc SuperIO chip with flat register model * */static int __init smsc_superio_flat(const struct smsc_chip *chips, unsigned short cfgbase, char *type){	unsigned short firbase, sirbase;	u8 mode, dma, irq;	int ret = -ENODEV;	IRDA_DEBUG(1, "%s\n", __FUNCTION__);	if (smsc_ircc_probe(cfgbase, SMSCSIOFLAT_DEVICEID_REG, chips, type) == NULL)		return ret;	outb(SMSCSIOFLAT_UARTMODE0C_REG, cfgbase);	mode = inb(cfgbase + 1);	/*printk(KERN_WARNING "%s(): mode: 0x%02x\n", __FUNCTION__, mode);*/	if (!(mode & SMSCSIOFLAT_UART2MODE_VAL_IRDA))		IRDA_WARNING("%s(): IrDA not enabled\n", __FUNCTION__);	outb(SMSCSIOFLAT_UART2BASEADDR_REG, cfgbase);	sirbase = inb(cfgbase + 1) << 2;	/* FIR iobase */	outb(SMSCSIOFLAT_FIRBASEADDR_REG, cfgbase);	firbase = inb(cfgbase + 1) << 3;	/* DMA */	outb(SMSCSIOFLAT_FIRDMASELECT_REG, cfgbase);	dma = inb(cfgbase + 1) & SMSCSIOFLAT_FIRDMASELECT_MASK;	/* IRQ */	outb(SMSCSIOFLAT_UARTIRQSELECT_REG, cfgbase);	irq = inb(cfgbase + 1) & SMSCSIOFLAT_UART2IRQSELECT_MASK;	IRDA_MESSAGE("%s(): fir: 0x%02x, sir: 0x%02x, dma: %02d, irq: %d, mode: 0x%02x\n", __FUNCTION__, firbase, sirbase, dma, irq, mode);	if (firbase && smsc_ircc_open(firbase, sirbase, dma, irq) == 0)		ret = 0;	/* Exit configuration */	outb(SMSCSIO_CFGEXITKEY, cfgbase);	return ret;}/* * Function smsc_superio_paged (chip, base, type) * *    Try  to get configuration of a smc SuperIO chip with paged register model * */static int __init smsc_superio_paged(const struct smsc_chip *chips, unsigned short cfg_base, char *type){	unsigned short fir_io, sir_io;	int ret = -ENODEV;	IRDA_DEBUG(1, "%s\n", __FUNCTION__);	if (smsc_ircc_probe(cfg_base, 0x20, chips, type) == NULL)		return ret;	/* Select logical device (UART2) */	outb(0x07, cfg_base);	outb(0x05, cfg_base + 1);	/* SIR iobase */	outb(0x60, cfg_base);	sir_io = inb(cfg_base + 1) << 8;	outb(0x61, cfg_base);	sir_io |= inb(cfg_base + 1);	/* Read FIR base */	outb(0x62, cfg_base);	fir_io = inb(cfg_base + 1) << 8;	outb(0x63, cfg_base);	fir_io |= inb(cfg_base + 1);	outb(0x2b, cfg_base); /* ??? */	if (fir_io && smsc_ircc_open(fir_io, sir_io, ircc_dma, ircc_irq) == 0)		ret = 0;	/* Exit configuration */	outb(SMSCSIO_CFGEXITKEY, cfg_base);	return ret;}static int __init smsc_access(unsigned short cfg_base, unsigned char reg){	IRDA_DEBUG(1, "%s\n", __FUNCTION__);	outb(reg, cfg_base);	return inb(cfg_base) != reg ? -1 : 0;}static const struct smsc_chip * __init smsc_ircc_probe(unsigned short cfg_base, u8 reg, const struct smsc_chip *chip, char *type){	u8 devid, xdevid, rev;	IRDA_DEBUG(1, "%s\n", __FUNCTION__);	/* Leave configuration */	outb(SMSCSIO_CFGEXITKEY, cfg_base);	if (inb(cfg_base) == SMSCSIO_CFGEXITKEY)	/* not a smc superio chip */		return NULL;	outb(reg, cfg_base);	xdevid = inb(cfg_base + 1);	/* Enter configuration */	outb(SMSCSIO_CFGACCESSKEY, cfg_base);	#if 0	if (smsc_access(cfg_base,0x55))	/* send second key and check */		return NULL;	#endif	/* probe device ID */	if (smsc_access(cfg_base, reg))		return NULL;	devid = inb(cfg_base + 1);	if (devid == 0 || devid == 0xff)	/* typical values for unused port */		return NULL;	/* probe revision ID */	if (smsc_access(cfg_base, reg + 1))		return NULL;	rev = inb(cfg_base + 1);	if (rev >= 128)			/* i think this will make no sense */		return NULL;	if (devid == xdevid)		/* protection against false positives */		return NULL;	/* Check for expected device ID; are there others? */	while (chip->devid != devid) {		chip++;		if (chip->name == NULL)			return NULL;	}	IRDA_MESSAGE("found SMC SuperIO Chip (devid=0x%02x rev=%02X base=0x%04x): %s%s\n",		     devid, rev, cfg_base, type, chip->name);	if (chip->rev > rev) {		IRDA_MESSAGE("Revision higher than expected\n");		return NULL;	}	if (chip->flags & NoIRDA)		IRDA_MESSAGE("chipset does not support IRDA\n");	return chip;}static int __init smsc_superio_fdc(unsigned short cfg_base){	int ret = -1;	if (!request_region(cfg_base, 2, driver_name)) {		IRDA_WARNING("%s: can't get cfg_base of 0x%03x\n",			     __FUNCTION__, cfg_base);	} else {		if (!smsc_superio_flat(fdc_chips_flat, cfg_base, "FDC") ||		    !smsc_superio_paged(fdc_chips_paged, cfg_base, "FDC"))			ret =  0;		release_region(cfg_base, 2);	}	return ret;}static int __init smsc_superio_lpc(unsigned short cfg_base){	int ret = -1;	if (!request_region(cfg_base, 2, driver_name)) {		IRDA_WARNING("%s: can't get cfg_base of 0x%03x\n",			     __FUNCTION__, cfg_base);	} else {		if (!smsc_superio_flat(lpc_chips_flat, cfg_base, "LPC") ||		    !smsc_superio_paged(lpc_chips_paged, cfg_base, "LPC"))			ret = 0;		release_region(cfg_base, 2);	}	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 (Low Pin Count) controller which * handles the communication with the SMSC device. After the LPC * controller is initialized through PCI, the SMSC device is initialized * through a dedicated port in the ISA port-mapped I/O area, this latter * area is used to configure the SMSC device with default * SIR and FIR I/O ports, DMA and IRQ. Different vendors have * used different sets of parameters and different control port * addresses making a subsystem device table necessary. */#ifdef CONFIG_PCI#define PCIID_VENDOR_INTEL 0x8086#define PCIID_VENDOR_ALI 0x10b9static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __initdata = {	/*	 * Subsystems needing entries:	 * 0x10b9:0x1533 0x103c:0x0850 HP nx9010 family	 * 0x10b9:0x1533 0x0e11:0x005a Compaq nc4000 family	 * 0x8086:0x24cc 0x0e11:0x002a HP nx9000 family	 */	{		/* Guessed entry */		.vendor = PCIID_VENDOR_INTEL, /* Intel 82801DBM LPC bridge */		.device = 0x24cc,		.subvendor = 0x103c,		.subdevice = 0x08bc,		.sir_io = 0x02f8,		.fir_io = 0x0130,		.fir_irq = 0x05,		.fir_dma = 0x03,		.cfg_base = 0x004e,		.preconfigure = preconfigure_through_82801,		.name = "HP nx5000 family",	},	{		.vendor = PCIID_VENDOR_INTEL, /* Intel 82801DBM LPC bridge */		.device = 0x24cc,		.subvendor = 0x103c,		.subdevice = 0x088c,		/* Quite certain these are the same for nc8000 as for nc6000 */		.sir_io = 0x02f8,		.fir_io = 0x0130,		.fir_irq = 0x05,		.fir_dma = 0x03,		.cfg_base = 0x004e,		.preconfigure = preconfigure_through_82801,		.name = "HP nc8000 family",	},	{		.vendor = PCIID_VENDOR_INTEL, /* Intel 82801DBM LPC bridge */		.device = 0x24cc,		.subvendor = 0x103c,		.subdevice = 0x0890,		.sir_io = 0x02f8,		.fir_io = 0x0130,		.fir_irq = 0x05,		.fir_dma = 0x03,		.cfg_base = 0x004e,		.preconfigure = preconfigure_through_82801,		.name = "HP nc6000 family",	},	{		.vendor = PCIID_VENDOR_INTEL, /* Intel 82801DBM LPC bridge */		.device = 0x24cc,		.subvendor = 0x0e11,		.subdevice = 0x0860,		/* I assume these are the same for x1000 as for the others */		.sir_io = 0x02e8,		.fir_io = 0x02f8,		.fir_irq = 0x07,		.fir_dma = 0x03,		.cfg_base = 0x002e,		.preconfigure = preconfigure_through_82801,		.name = "Compaq x1000 family",	},	{		/* Intel 82801DB/DBL (ICH4/ICH4-L) LPC Interface Bridge */		.vendor = PCIID_VENDOR_INTEL,		.device = 0x24c0,		.subvendor = 0x1179,		.subdevice = 0xffff, /* 0xffff is "any" */		.sir_io = 0x03f8,		.fir_io = 0x0130,		.fir_irq = 0x07,		.fir_dma = 0x01,		.cfg_base = 0x002e,		.preconfigure = preconfigure_through_82801,		.name = "Toshiba laptop with Intel 82801DB/DBL LPC bridge",	},	{		.vendor = PCIID_VENDOR_INTEL, /* Intel 82801CAM ISA bridge */		.device = 0x248c,		.subvendor = 0x1179,		.subdevice = 0xffff, /* 0xffff is "any" */		.sir_io = 0x03f8,		.fir_io = 0x0130,		.fir_irq = 0x03,		.fir_dma = 0x03,		.cfg_base = 0x002e,		.preconfigure = preconfigure_through_82801,		.name = "Toshiba laptop with Intel 82801CAM ISA bridge",	},	{		/* 82801DBM (ICH4-M) LPC Interface Bridge */		.vendor = PCIID_VENDOR_INTEL,		.device = 0x24cc,		.subvendor = 0x1179,		.subdevice = 0xffff, /* 0xffff is "any" */		.sir_io = 0x03f8,		.fir_io = 0x0130,		.fir_irq = 0x03,		.fir_dma = 0x03,		.cfg_base = 0x002e,		.preconfigure = preconfigure_through_82801,		.name = "Toshiba laptop with Intel 8281DBM LPC bridge",	},	{		/* ALi M1533/M1535 PCI to ISA Bridge [Aladdin IV/V/V+] */		.vendor = PCIID_VENDOR_ALI,		.device = 0x1533,		.subvendor = 0x1179,		.subdevice = 0xffff, /* 0xffff is "any" */		.sir_io = 0x02e8,		.fir_io = 0x02f8,		.fir_irq = 0x07,		.fir_dma = 0x03,		.cfg_base = 0x002e,		.preconfigure = preconfigure_through_ali,		.name = "Toshiba laptop with ALi ISA bridge",	},	{ } // 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_configura

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -