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

📄 smc-ircc.c

📁 上传linux-jx2410的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/********************************************************************* *                 * Filename:      smc-ircc.c * Version:       0.4 * Description:   Driver for the SMC Infrared Communications Controller * Status:        Experimental. * Author:        Thomas Davis (tadavis@jps.net) * Created at:     * Modified at:   Tue Feb 22 10:05:06 2000 * Modified by:   Dag Brattli <dag@brattli.net> * Modified at:   Tue Jun 26 2001 * Modified by:   Stefani Seibold <stefani@seibold.net> *  *     Copyright (c) 2001      Stefani Seibold *     Copyright (c) 1999-2001 Dag Brattli *     Copyright (c) 1998-1999 Thomas Davis,  *     All Rights Reserved. *       *     This program is free software; you can redistribute it and/or  *     modify it under the terms of the GNU General Public License as  *     published by the Free Software Foundation; either version 2 of  *     the License, or (at your option) any later version. *  *     This program is distributed in the hope that it will be useful, *     but WITHOUT ANY WARRANTY; without even the implied warranty of *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *     GNU General Public License for more details. *  *     You should have received a copy of the GNU General Public License  *     along with this program; if not, write to the Free Software  *     Foundation, Inc., 59 Temple Place, Suite 330, Boston,  *     MA 02111-1307 USA * *     SIO's: all SIO documentet by SMC (June, 2001) *     Applicable Models :	Fujitsu Lifebook 635t, Sony PCG-505TX, *     				Dell Inspiron 8000 * ********************************************************************/#include <linux/module.h>#include <linux/kernel.h>#include <linux/types.h>#include <linux/skbuff.h>#include <linux/netdevice.h>#include <linux/ioport.h>#include <linux/delay.h>#include <linux/slab.h>#include <linux/init.h>#include <linux/rtnetlink.h>#include <linux/serial_reg.h>#include <asm/io.h>#include <asm/dma.h>#include <asm/byteorder.h>#include <linux/pm.h>#include <net/irda/wrapper.h>#include <net/irda/irda.h>#include <net/irda/irmod.h>#include <net/irda/irlap_frame.h>#include <net/irda/irda_device.h>#include <net/irda/smc-ircc.h>#include <net/irda/irport.h>struct smc_chip {	char *name;	u16 flags;	u8 devid;	u8 rev;};typedef struct smc_chip smc_chip_t;static const char *driver_name = "smc-ircc";#define	DIM(x)	(sizeof(x)/(sizeof(*(x))))#define CHIP_IO_EXTENT 8static struct ircc_cb *dev_self[] = { NULL, NULL};/* Some prototypes */static int  ircc_open(unsigned int iobase, unsigned int board_addr);static int  ircc_dma_receive(struct ircc_cb *self, int iobase); static void ircc_dma_receive_complete(struct ircc_cb *self, int iobase);static int  ircc_hard_xmit(struct sk_buff *skb, struct net_device *dev);static void ircc_dma_xmit(struct ircc_cb *self, int iobase, int bofs);static void ircc_change_speed(void *priv, u32 speed);static void ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs);static int  ircc_net_open(struct net_device *dev);static int  ircc_net_close(struct net_device *dev);static int  ircc_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data);#define	KEY55_1	0	/* SuperIO Configuration mode with Key <0x55> */#define	KEY55_2	1	/* SuperIO Configuration mode with Key <0x55,0x55> */#define	NoIRDA	2	/* SuperIO Chip has no IRDA Port */#define	SIR	0	/* SuperIO Chip has only slow IRDA */#define	FIR	4	/* SuperIO Chip has fast IRDA */#define	SERx4	8	/* SuperIO Chip supports 115,2 KBaud * 4=460,8 KBaud *//* These are the currently known SMC SuperIO chipsets */static smc_chip_t __initdata fdc_chips_flat[]={	/* Base address 0x3f0 or 0x370 */	{ "37C44",	KEY55_1|NoIRDA,		0x00, 0x00 }, /* This chip can not detected */	{ "37C665GT",	KEY55_2|NoIRDA,		0x65, 0x01 },	{ "37C665GT",	KEY55_2|NoIRDA,		0x66, 0x01 },	{ "37C669",	KEY55_2|SIR|SERx4,	0x03, 0x02 },	{ "37C669",	KEY55_2|SIR|SERx4,	0x04, 0x02 }, /* ID? */	{ "37C78",	KEY55_2|NoIRDA,		0x78, 0x00 },	{ "37N769",	KEY55_1|FIR|SERx4,	0x28, 0x00 },	{ "37N869",	KEY55_1|FIR|SERx4,	0x29, 0x00 },	{ NULL }};static smc_chip_t __initdata fdc_chips_paged[]={	/* Base address 0x3f0 or 0x370 */	{ "37B72X",	KEY55_1|SIR|SERx4,	0x4c, 0x00 },	{ "37B77X",	KEY55_1|SIR|SERx4,	0x43, 0x00 },	{ "37B78X",	KEY55_1|SIR|SERx4,	0x44, 0x00 },	{ "37B80X",	KEY55_1|SIR|SERx4,	0x42, 0x00 },	{ "37C67X",	KEY55_1|FIR|SERx4,	0x40, 0x00 },	{ "37C93X",	KEY55_2|SIR|SERx4,	0x02, 0x01 },	{ "37C93XAPM",	KEY55_1|SIR|SERx4,	0x30, 0x01 },	{ "37C93XFR",	KEY55_2|FIR|SERx4,	0x03, 0x01 },	{ "37M707",	KEY55_1|SIR|SERx4,	0x42, 0x00 },	{ "37M81X",	KEY55_1|SIR|SERx4,	0x4d, 0x00 },	{ "37N958FR",	KEY55_1|FIR|SERx4,	0x09, 0x04 },	{ "37N971",	KEY55_1|FIR|SERx4,	0x0a, 0x00 },	{ "37N972",	KEY55_1|FIR|SERx4,	0x0b, 0x00 },	{ NULL }};static smc_chip_t __initdata lpc_chips_flat[]={	/* Base address 0x2E or 0x4E */	{ "47N227",	KEY55_1|FIR|SERx4,	0x5a, 0x00 },	{ "47N267",	KEY55_1|FIR|SERx4,	0x5e, 0x00 },	{ NULL }};static smc_chip_t __initdata lpc_chips_paged[]={	/* Base address 0x2E or 0x4E */	{ "47B27X",	KEY55_1|SIR|SERx4,	0x51, 0x00 },	{ "47B37X",	KEY55_1|SIR|SERx4,	0x52, 0x00 },	{ "47M10X",	KEY55_1|SIR|SERx4,	0x59, 0x00 },	{ "47M120",	KEY55_1|NoIRDA|SERx4,	0x5c, 0x00 },	{ "47M13X",	KEY55_1|SIR|SERx4,	0x59, 0x00 },	{ "47M14X",	KEY55_1|SIR|SERx4,	0x5f, 0x00 },	{ "47N252",	KEY55_1|FIR|SERx4,	0x0e, 0x00 },	{ "47S42X",	KEY55_1|SIR|SERx4,	0x57, 0x00 },	{ NULL }};static int ircc_irq=255;static int ircc_dma=255;static int ircc_fir=0;static int ircc_sir=0;static int ircc_cfg=0;static unsigned short	dev_count=0;static inline void register_bank(int iobase, int bank){        outb(((inb(iobase+IRCC_MASTER) & 0xf0) | (bank & 0x07)),               iobase+IRCC_MASTER);}static int __init smc_access(unsigned short cfg_base,unsigned char reg){	IRDA_DEBUG(0, __FUNCTION__ "()\n");	outb(reg, cfg_base);	if (inb(cfg_base)!=reg)		return -1;	return 0;}static const smc_chip_t * __init smc_probe(unsigned short cfg_base,u8 reg,const smc_chip_t *chip,char *type){	u8 devid,xdevid,rev; 	IRDA_DEBUG(0, __FUNCTION__ "()\n");	/* Leave configuration */	outb(0xaa, cfg_base);	if (inb(cfg_base)==0xaa)	/* not a smc superio chip */		return NULL;	outb(reg, cfg_base);	xdevid=inb(cfg_base+1);	/* Enter configuration */	outb(0x55, cfg_base);	if (smc_access(cfg_base,0x55))	/* send second key and check */		return NULL;	/* probe device ID */	if (smc_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 (smc_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;	}	if (chip->rev>rev)		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->flags&NoIRDA)		MESSAGE("chipset does not support IRDA\n");	return chip;}/* * Function smc_superio_flat (chip, base, type) * *    Try get configuration of a smc SuperIO chip with flat register model * */static int __init smc_superio_flat(const smc_chip_t *chips, unsigned short cfg_base, char *type){	unsigned short fir_io;	unsigned short sir_io;	u8 mode;	int ret = -ENODEV;	IRDA_DEBUG(0, __FUNCTION__ "()\n");	if (smc_probe(cfg_base,0xD,chips,type)==NULL)		return ret;	outb(0x0c, cfg_base);	mode = inb(cfg_base+1);	mode = (mode & 0x38) >> 3;			/* Value for IR port */	if (mode && mode < 4) {		/* SIR iobase */		outb(0x25, cfg_base);		sir_io = inb(cfg_base+1) << 2;	       	/* FIR iobase */		outb(0x2b, cfg_base);		fir_io = inb(cfg_base+1) << 3;		if (fir_io) {			if (ircc_open(fir_io, sir_io) == 0)				ret=0; 		}	}		/* Exit configuration */	outb(0xaa, cfg_base);	return ret;}/* * Function smc_superio_paged (chip, base, type) * *    Try  get configuration of a smc SuperIO chip with paged register model * */static int __init smc_superio_paged(const smc_chip_t *chips, unsigned short cfg_base, char *type){	unsigned short fir_io;	unsigned short sir_io;	int ret = -ENODEV;		IRDA_DEBUG(0, __FUNCTION__ "()\n");	if (smc_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 (ircc_open(fir_io, sir_io) == 0)			ret=0; 	}		/* Exit configuration */	outb(0xaa, cfg_base);	return ret;}static int __init smc_superio_fdc(unsigned short cfg_base){	if (check_region(cfg_base, 2) < 0) {		IRDA_DEBUG(0, __FUNCTION__ ": can't get cfg_base of 0x%03x\n",			   cfg_base);		return -1;	}	if (!smc_superio_flat(fdc_chips_flat,cfg_base,"FDC")||!smc_superio_paged(fdc_chips_paged,cfg_base,"FDC"))		return 0;	return -1;}static int __init smc_superio_lpc(unsigned short cfg_base){#if 0	if (check_region(cfg_base, 2) < 0) {		IRDA_DEBUG(0, __FUNCTION__ ": can't get cfg_base of 0x%03x\n",			   cfg_base);		return -1;	}#endif	if (!smc_superio_flat(lpc_chips_flat,cfg_base,"LPC")||!smc_superio_paged(lpc_chips_paged,cfg_base,"LPC"))		return 0;	return -1;}/* * Function ircc_init () * *    Initialize chip. Just try to find out how many chips we are dealing with *    and where they are */int __init ircc_init(void){	int ret=-ENODEV;	IRDA_DEBUG(0, __FUNCTION__ "\n");	dev_count=0;	if ((ircc_fir>0)&&(ircc_sir>0)) {	        MESSAGE(" Overriding FIR address 0x%04x\n", ircc_fir);		MESSAGE(" Overriding SIR address 0x%04x\n", ircc_sir);		if (ircc_open(ircc_fir, ircc_sir) == 0)			return 0;		return -ENODEV;	}	/* try user provided configuration register base address */	if (ircc_cfg>0) {	        MESSAGE(" Overriding configuration address 0x%04x\n", ircc_cfg);		if (!smc_superio_fdc(ircc_cfg))			ret=0;	}	/* Trys to open for all the SMC chipsets we know about */	IRDA_DEBUG(0, __FUNCTION__ 	" Try to open all known SMC chipsets\n");	if (!smc_superio_fdc(0x3f0))		ret=0;	if (!smc_superio_fdc(0x370))		ret=0;	if (!smc_superio_fdc(0xe0))		ret=0;	if (!smc_superio_lpc(0x2e))		ret=0;	if (!smc_superio_lpc(0x4e))		ret=0;	return ret;}/* * Function ircc_open (iobase, irq) * *    Try to open driver instance * */static int __init ircc_open(unsigned int fir_base, unsigned int sir_base){	struct ircc_cb *self;        struct irport_cb *irport;	unsigned char low, high, chip, config, dma, irq, version;	IRDA_DEBUG(0, __FUNCTION__ "\n");	if (check_region(fir_base, CHIP_IO_EXTENT) < 0) {		IRDA_DEBUG(0, __FUNCTION__ ": can't get fir_base of 0x%03x\n",			   fir_base);		return -ENODEV;	}#if POSSIBLE_USED_BY_SERIAL_DRIVER	if (check_region(sir_base, CHIP_IO_EXTENT) < 0) {		IRDA_DEBUG(0, __FUNCTION__ ": can't get sir_base of 0x%03x\n",			   sir_base);		return -ENODEV;	}#endif	register_bank(fir_base, 3);	high    = inb(fir_base+IRCC_ID_HIGH);	low     = inb(fir_base+IRCC_ID_LOW);	chip    = inb(fir_base+IRCC_CHIP_ID);	version = inb(fir_base+IRCC_VERSION);	config  = inb(fir_base+IRCC_INTERFACE);	irq     = config >> 4 & 0x0f;	dma     = config & 0x0f;        if (high != 0x10 || low != 0xb8 || (chip != 0xf1 && chip != 0xf2)) { 	        IRDA_DEBUG(0, __FUNCTION__ 			   "(), addr 0x%04x - no device found!\n", fir_base);		return -ENODEV;	}	MESSAGE("SMC IrDA Controller found\n IrCC version %d.%d, "		"firport 0x%03x, sirport 0x%03x dma=%d, irq=%d\n",		chip & 0x0f, version, fir_base, sir_base, dma, irq);	if (dev_count>DIM(dev_self)) {	        IRDA_DEBUG(0, __FUNCTION__ 			   "(), to many devices!\n");		return -ENOMEM;	}	/*	 *  Allocate new instance of the driver	 */	self = kmalloc(sizeof(struct ircc_cb), GFP_KERNEL);	if (self == NULL) {		ERROR("%s, Can't allocate memory for control block!\n",                      driver_name);		return -ENOMEM;	}	memset(self, 0, sizeof(struct ircc_cb));	spin_lock_init(&self->lock);	/* Max DMA buffer size needed = (data_size + 6) * (window_size) + 6; */	self->rx_buff.truesize = 4000; 	self->tx_buff.truesize = 4000;	self->rx_buff.head = (u8 *) kmalloc(self->rx_buff.truesize,					      GFP_KERNEL|GFP_DMA);	if (self->rx_buff.head == NULL) {		ERROR("%s, Can't allocate memory for receive buffer!\n",                      driver_name);		kfree(self);		return -ENOMEM;	}	self->tx_buff.head = (u8 *) kmalloc(self->tx_buff.truesize, 					      GFP_KERNEL|GFP_DMA);	if (self->tx_buff.head == NULL) {		ERROR("%s, Can't allocate memory for transmit buffer!\n",                      driver_name);		kfree(self->rx_buff.head);		kfree(self);		return -ENOMEM;	}	irport = irport_open(dev_count, sir_base, irq);	if (!irport) {		kfree(self->tx_buff.head);		kfree(self->rx_buff.head);		kfree(self);		return -ENODEV;	}	memset(self->rx_buff.head, 0, self->rx_buff.truesize);	memset(self->tx_buff.head, 0, self->tx_buff.truesize);   	/* Need to store self somewhere */	dev_self[dev_count++] = self;	/* Steal the network device from irport */	self->netdev = irport->netdev;	self->irport = irport;	irport->priv = self;	/* Initialize IO */	self->io           = &irport->io;	self->io->fir_base  = fir_base;        self->io->sir_base  = sir_base;	/* Used by irport */        self->io->fir_ext   = CHIP_IO_EXTENT;        self->io->sir_ext   = 8;		/* Used by irport */	if (ircc_irq < 255) {		if (ircc_irq!=irq)			MESSAGE("%s, Overriding IRQ - chip says %d, using %d\n",				driver_name, self->io->irq, ircc_irq);		self->io->irq = ircc_irq;	}	else		self->io->irq = irq;	if (ircc_dma < 255) {		if (ircc_dma!=dma)			MESSAGE("%s, Overriding DMA - chip says %d, using %d\n",				driver_name, self->io->dma, ircc_dma);		self->io->dma = ircc_dma;	}	else		self->io->dma = dma;	request_region(fir_base, CHIP_IO_EXTENT, driver_name);	/* Initialize QoS for this device */	irda_init_max_qos_capabilies(&irport->qos);		/* The only value we must override it the baudrate */	irport->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600|		IR_115200|IR_576000|IR_1152000|(IR_4000000 << 8);	irport->qos.min_turn_time.bits = 0x07;	irport->qos.window_size.bits = 0x01;	irda_qos_bits_to_value(&irport->qos);	irport->flags = IFF_FIR|IFF_MIR|IFF_SIR|IFF_DMA|IFF_PIO;		self->rx_buff.in_frame = FALSE;	self->rx_buff.state = OUTSIDE_FRAME;	self->tx_buff.data = self->tx_buff.head;	self->rx_buff.data = self->rx_buff.head;		/* Override the speed change function, since we must control it now */	irport->change_speed = &ircc_change_speed;	irport->interrupt    = &ircc_interrupt;	self->netdev->open   = &ircc_net_open;	self->netdev->stop   = &ircc_net_close;	irport_start(self->irport);        self->pmdev = pm_register(PM_SYS_DEV, PM_SYS_IRDA, ircc_pmproc);        if (self->pmdev)                self->pmdev->data = self;	/* Power on device */	outb(0x00, fir_base+IRCC_MASTER);	return 0;}/* * Function ircc_change_speed (self, baud) * *    Change the speed of the device * */static void ircc_change_speed(void *priv, u32 speed){	int iobase, ir_mode, ctrl, fast; 	struct ircc_cb *self = (struct ircc_cb *) priv;	struct net_device *dev;	IRDA_DEBUG(0, __FUNCTION__ "\n");	ASSERT(self != NULL, return;);	dev = self->netdev;	iobase = self->io->fir_base;	/* Update accounting for new speed */	self->io->speed = speed;	outb(IRCC_MASTER_RESET, iobase+IRCC_MASTER);	outb(0x00, iobase+IRCC_MASTER);	switch (speed) {	default:		IRDA_DEBUG(0, __FUNCTION__ "(), unknown baud rate of %d\n", 

⌨️ 快捷键说明

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