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

📄 smsc-ircc2.c

📁 h内核
💻 C
📖 第 1 页 / 共 4 页
字号:
	IRDA_DEBUG(3, "%s\n", __FUNCTION__);	iobase = self->io.sir_base;	/* Reset UART */	outb(0, iobase+UART_MCR);		/* Turn off interrupts */	outb(0, iobase+UART_IER);}#endif/* * Function smsc_sir_write_wakeup (self) * *    Called by the SIR interrupt handler when there's room for more data. *    If we have more packets to send, we send them here. * */static void smsc_ircc_sir_write_wakeup(struct smsc_ircc_cb *self){	int actual = 0;	int iobase;	int fcr;	ASSERT(self != NULL, return;);	IRDA_DEBUG(4, "%s\n", __FUNCTION__);	iobase = self->io.sir_base;	/* Finished with frame?  */	if (self->tx_buff.len > 0)  {		/* Write data left in transmit buffer */		actual = smsc_ircc_sir_write(iobase, self->io.fifo_size, 				      self->tx_buff.data, self->tx_buff.len);		self->tx_buff.data += actual;		self->tx_buff.len  -= actual;	} else {		/*if (self->tx_buff.len ==0)  {*/				/* 		 *  Now serial buffer is almost free & we can start 		 *  transmission of another packet. But first we must check		 *  if we need to change the speed of the hardware		 */		if (self->new_speed) {			IRDA_DEBUG(5, "%s(), Changing speed to %d.\n",				   __FUNCTION__, self->new_speed);			smsc_ircc_sir_wait_hw_transmitter_finish(self);			smsc_ircc_change_speed(self, self->new_speed);			self->new_speed = 0;		} else {			/* Tell network layer that we want more frames */			netif_wake_queue(self->netdev);		}		self->stats.tx_packets++;		if(self->io.speed <= 115200) {		/* 		 * Reset Rx FIFO to make sure that all reflected transmit data		 * is discarded. This is needed for half duplex operation		 */		fcr = UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR;		if (self->io.speed < 38400)			fcr |= UART_FCR_TRIGGER_1;		else 			fcr |= UART_FCR_TRIGGER_14;		outb(fcr, iobase+UART_FCR);		/* Turn on receive interrupts */		outb(UART_IER_RDI, iobase+UART_IER);		}	}}/* * Function smsc_ircc_sir_write (iobase, fifo_size, buf, len) * *    Fill Tx FIFO with transmit data * */static int smsc_ircc_sir_write(int iobase, int fifo_size, __u8 *buf, int len){	int actual = 0;		/* Tx FIFO should be empty! */	if (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) {		WARNING("%s(), failed, fifo not empty!\n", __FUNCTION__);		return 0;	}        	/* Fill FIFO with current frame */	while ((fifo_size-- > 0) && (actual < len)) {		/* Transmit next byte */		outb(buf[actual], iobase+UART_TX);		actual++;	}	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;		ASSERT(self != NULL, return;);		for(i=0; smsc_transceivers[i].name!=NULL; i++) 		if((*smsc_transceivers[i].probe)(self->io.fir_base)) {			MESSAGE(" %s transceiver found\n", smsc_transceivers[i].name);			self->transceiver= i+1;			return;		}	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;	int count = SMSC_IRCC2_HW_TRANSMITTER_TIMEOUT_US;		iobase = self->io.sir_base;		/* 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 * * */static int __init smsc_ircc_look_for_chips(void){	smsc_chip_address_t *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,"LPC")) 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 smsc_chip_t *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))		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;	MESSAGE("%s(): fir: 0x%02x, sir: 0x%02x, dma: %02d, irq: %d, mode: 0x%02x\n", __FUNCTION__, firbase, sirbase, dma, irq, mode);	if (firbase) {		if (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 smsc_chip_t *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) {		if (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);	if (inb(cfg_base)!=reg)		return -1;	return 0;}static const smsc_chip_t * __init smsc_ircc_probe(unsigned short cfg_base,u8 reg,const smsc_chip_t *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)			/* typical value for unused port */		return NULL;	if (devid==0xff)		/* typical value 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;	}	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){		MESSAGE("Revision higher than expected\n");			return NULL;	}		if (chip->flags&NoIRDA)		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)) {		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)) {		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;}/************************************************ * * Transceivers specific functions * ************************************************//* * Function smsc_ircc_set_transceiver_smsc_ircc_atc(fir_base, speed) * *    Program transceiver through smsc-ircc ATC circuitry * */static void smsc_ircc_set_transceiver_smsc_ircc_atc(int fir_base, u32 speed){	unsigned long jiffies_now, jiffies_timeout;	u8	val;		jiffies_now= jiffies;	jiffies_timeout= jiffies+SMSC_IRCC2_ATC_PROGRAMMING_TIMEOUT_JIFFIES;		/* ATC */	register_bank(fir_base, 4);	outb((inb(fir_base+IRCC_ATC) & IRCC_ATC_MASK) |IRCC_ATC_nPROGREADY|IRCC_ATC_ENABLE, fir_base+IRCC_ATC);	while((val=(inb(fir_base+IRCC_ATC) & IRCC_ATC_nPROGREADY)) && !time_after(jiffies, jiffies_timeout));	if(val)		WARNING("%s(): ATC: 0x%02x\n", __FUNCTION__,			inb(fir_base+IRCC_ATC));}/* * Function smsc_ircc_probe_transceiver_smsc_ircc_atc(fir_base) * *    Probe transceiver smsc-ircc ATC circuitry * */static int smsc_ircc_probe_transceiver_smsc_ircc_atc(int fir_base){	return 0;}/* * Function smsc_ircc_set_transceiver_smsc_ircc_fast_pin_select(self, speed) * *    Set transceiver  * */static void smsc_ircc_set_transceiver_smsc_ircc_fast_pin_select(int fir_base, u32 speed){	u8	fast_mode;		switch(speed)	{		default:		case 576000 :		fast_mode = 0; 		break;		case 1152000 :		case 4000000 :		fast_mode = IRCC_LCR_A_FAST;		break;			}	register_bank(fir_base, 0);	outb((inb(fir_base+IRCC_LCR_A) &  0xbf) | fast_mode, fir_base+IRCC_LCR_A);}/* * Function smsc_ircc_probe_transceiver_smsc_ircc_fast_pin_select(fir_base) * *    Probe transceiver  * */static int smsc_ircc_probe_transceiver_smsc_ircc_fast_pin_select(int fir_base){	return 0;}/* * Function smsc_ircc_set_transceiver_toshiba_sat1800(fir_base, speed) * *    Set transceiver  * */static void smsc_ircc_set_transceiver_toshiba_sat1800(int fir_base, u32 speed){	u8	fast_mode;		switch(speed)	{		default:		case 576000 :		fast_mode = 0; 		break;		case 1152000 :		case 4000000 :		fast_mode = /*IRCC_LCR_A_FAST |*/ IRCC_LCR_A_GP_DATA;		break;			}	/* This causes an interrupt */	register_bank(fir_base, 0);	outb((inb(fir_base+IRCC_LCR_A) &  0xbf) | fast_mode, fir_base+IRCC_LCR_A);}/* * Function smsc_ircc_probe_transceiver_toshiba_sat1800(fir_base) * *    Probe transceiver  * */static int smsc_ircc_probe_transceiver_toshiba_sat1800(int fir_base){	return 0;}module_init(smsc_ircc_init);module_exit(smsc_ircc_cleanup);MODULE_AUTHOR("Daniele Peri <peri@csai.unipa.it>");MODULE_DESCRIPTION("SMC IrCC SIR/FIR controller driver");MODULE_LICENSE("GPL");module_param(ircc_dma, int, 0);MODULE_PARM_DESC(ircc_dma, "DMA channel");module_param(ircc_irq, int, 0);MODULE_PARM_DESC(ircc_irq, "IRQ line");module_param(ircc_fir, int, 0);MODULE_PARM_DESC(ircc_fir, "FIR Base Address");module_param(ircc_sir, int, 0);MODULE_PARM_DESC(ircc_sir, "SIR Base Address");module_param(ircc_cfg, int, 0);MODULE_PARM_DESC(ircc_cfg, "Configuration register base address");module_param(ircc_transceiver, int, 0);MODULE_PARM_DESC(ircc_transceiver, "Transceiver type");

⌨️ 快捷键说明

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