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

📄 w83977af_ir.c

📁 《linux驱动程序设计从入门到精通》一书中所有的程序代码含驱动和相应的应用程序
💻 C
📖 第 1 页 / 共 3 页
字号:
/********************************************************************* *                 * Filename:      w83977af_ir.c * Version:       1.0 * Description:   FIR driver for the Winbond W83977AF Super I/O chip * Status:        Experimental. * Author:        Paul VanderSpek * Created at:    Wed Nov  4 11:46:16 1998 * Modified at:   Fri Jan 28 12:10:59 2000 * Modified by:   Dag Brattli <dagb@cs.uit.no> *  *     Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no> *     Copyright (c) 1998-1999 Rebel.com *       *     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. *   *     Neither Paul VanderSpek nor Rebel.com admit liability nor provide *     warranty for any of this software. This material is provided "AS-IS" *     and at no charge. *      *     If you find bugs in this file, its very likely that the same bug *     will also be in pc87108.c since the implementations are quite *     similar. * *     Notice that all functions that needs to access the chip in _any_ *     way, must save BSR register on entry, and restore it on exit.  *     It is _very_ important to follow this policy! * *         __u8 bank; *      *         bank = inb( iobase+BSR); *   *         do_your_stuff_here(); * *         outb( bank, iobase+BSR); * ********************************************************************/#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/dma-mapping.h>#include <asm/io.h>#include <asm/dma.h>#include <asm/byteorder.h>#include <net/irda/irda.h>#include <net/irda/wrapper.h>#include <net/irda/irda_device.h>#include "w83977af.h"#include "w83977af_ir.h"#ifdef  CONFIG_ARCH_NETWINDER            /* Adjust to NetWinder differences */#undef  CONFIG_NETWINDER_TX_DMA_PROBLEMS /* Not needed */#define CONFIG_NETWINDER_RX_DMA_PROBLEMS /* Must have this one! */#endif#undef  CONFIG_USE_INTERNAL_TIMER  /* Just cannot make that timer work */#define CONFIG_USE_W977_PNP        /* Currently needed */#define PIO_MAX_SPEED       115200 static char *driver_name = "w83977af_ir";static int  qos_mtt_bits = 0x07;   /* 1 ms or more */#define CHIP_IO_EXTENT 8static unsigned int io[] = { 0x180, ~0, ~0, ~0 };#ifdef CONFIG_ARCH_NETWINDER             /* Adjust to NetWinder differences */static unsigned int irq[] = { 6, 0, 0, 0 };#elsestatic unsigned int irq[] = { 11, 0, 0, 0 };#endifstatic unsigned int dma[] = { 1, 0, 0, 0 };static unsigned int efbase[] = { W977_EFIO_BASE, W977_EFIO2_BASE };static unsigned int efio = W977_EFIO_BASE;static struct w83977af_ir *dev_self[] = { NULL, NULL, NULL, NULL};/* Some prototypes */static int  w83977af_open(int i, unsigned int iobase, unsigned int irq,                           unsigned int dma);static int  w83977af_close(struct w83977af_ir *self);static int  w83977af_probe(int iobase, int irq, int dma);static int  w83977af_dma_receive(struct w83977af_ir *self); static int  w83977af_dma_receive_complete(struct w83977af_ir *self);static int  w83977af_hard_xmit(struct sk_buff *skb, struct net_device *dev);static int  w83977af_pio_write(int iobase, __u8 *buf, int len, int fifo_size);static void w83977af_dma_write(struct w83977af_ir *self, int iobase);static void w83977af_change_speed(struct w83977af_ir *self, __u32 speed);static int  w83977af_is_receiving(struct w83977af_ir *self);static int  w83977af_net_open(struct net_device *dev);static int  w83977af_net_close(struct net_device *dev);static int  w83977af_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);static struct net_device_stats *w83977af_net_get_stats(struct net_device *dev);/* * Function w83977af_init () * *    Initialize chip. Just try to find out how many chips we are dealing with *    and where they are */static int __init w83977af_init(void){        int i;	IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );	for (i=0; (io[i] < 2000) && (i < ARRAY_SIZE(dev_self)); i++) {		if (w83977af_open(i, io[i], irq[i], dma[i]) == 0)			return 0;	}	return -ENODEV;}/* * Function w83977af_cleanup () * *    Close all configured chips * */static void __exit w83977af_cleanup(void){	int i;        IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );	for (i=0; i < ARRAY_SIZE(dev_self); i++) {		if (dev_self[i])			w83977af_close(dev_self[i]);	}}/* * Function w83977af_open (iobase, irq) * *    Open driver instance * */int w83977af_open(int i, unsigned int iobase, unsigned int irq, 		  unsigned int dma){	struct net_device *dev;        struct w83977af_ir *self;	int err;	IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );	/* Lock the port that we need */	if (!request_region(iobase, CHIP_IO_EXTENT, driver_name)) {		IRDA_DEBUG(0, "%s(), can't get iobase of 0x%03x\n",		      __FUNCTION__ , iobase);		return -ENODEV;	}	if (w83977af_probe(iobase, irq, dma) == -1) {		err = -1;		goto err_out;	}	/*	 *  Allocate new instance of the driver	 */	dev = alloc_irdadev(sizeof(struct w83977af_ir));	if (dev == NULL) {		printk( KERN_ERR "IrDA: Can't allocate memory for "			"IrDA control block!\n");		err = -ENOMEM;		goto err_out;	}	self = dev->priv;	spin_lock_init(&self->lock);   	/* Initialize IO */	self->io.fir_base   = iobase;        self->io.irq       = irq;        self->io.fir_ext   = CHIP_IO_EXTENT;        self->io.dma       = dma;        self->io.fifo_size = 32;	/* Initialize QoS for this device */	irda_init_max_qos_capabilies(&self->qos);		/* The only value we must override it the baudrate */	/* FIXME: The HP HDLS-1100 does not support 1152000! */	self->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600|		IR_115200|IR_576000|IR_1152000|(IR_4000000 << 8);	/* The HP HDLS-1100 needs 1 ms according to the specs */	self->qos.min_turn_time.bits = qos_mtt_bits;	irda_qos_bits_to_value(&self->qos);		/* Max DMA buffer size needed = (data_size + 6) * (window_size) + 6; */	self->rx_buff.truesize = 14384; 	self->tx_buff.truesize = 4000;		/* Allocate memory if needed */	self->rx_buff.head =		dma_alloc_coherent(NULL, self->rx_buff.truesize,				   &self->rx_buff_dma, GFP_KERNEL);	if (self->rx_buff.head == NULL) {		err = -ENOMEM;		goto err_out1;	}	memset(self->rx_buff.head, 0, self->rx_buff.truesize);		self->tx_buff.head =		dma_alloc_coherent(NULL, self->tx_buff.truesize,				   &self->tx_buff_dma, GFP_KERNEL);	if (self->tx_buff.head == NULL) {		err = -ENOMEM;		goto err_out2;	}	memset(self->tx_buff.head, 0, self->tx_buff.truesize);	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;	self->netdev = dev;	/* Keep track of module usage */	SET_MODULE_OWNER(dev);	/* Override the network functions we need to use */	dev->hard_start_xmit = w83977af_hard_xmit;	dev->open            = w83977af_net_open;	dev->stop            = w83977af_net_close;	dev->do_ioctl        = w83977af_net_ioctl;	dev->get_stats	     = w83977af_net_get_stats;	err = register_netdev(dev);	if (err) {		IRDA_ERROR("%s(), register_netdevice() failed!\n", __FUNCTION__);		goto err_out3;	}	IRDA_MESSAGE("IrDA: Registered device %s\n", dev->name);	/* Need to store self somewhere */	dev_self[i] = self;		return 0;err_out3:	dma_free_coherent(NULL, self->tx_buff.truesize,			  self->tx_buff.head, self->tx_buff_dma);err_out2:		dma_free_coherent(NULL, self->rx_buff.truesize,			  self->rx_buff.head, self->rx_buff_dma);err_out1:	free_netdev(dev);err_out:	release_region(iobase, CHIP_IO_EXTENT);	return err;}/* * Function w83977af_close (self) * *    Close driver instance * */static int w83977af_close(struct w83977af_ir *self){	int iobase;	IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );        iobase = self->io.fir_base;#ifdef CONFIG_USE_W977_PNP	/* enter PnP configuration mode */	w977_efm_enter(efio);	w977_select_device(W977_DEVICE_IR, efio);	/* Deactivate device */	w977_write_reg(0x30, 0x00, efio);	w977_efm_exit(efio);#endif /* CONFIG_USE_W977_PNP */	/* Remove netdevice */	unregister_netdev(self->netdev);	/* Release the PORT that this driver is using */	IRDA_DEBUG(0 , "%s(), Releasing Region %03x\n", 	      __FUNCTION__ , self->io.fir_base);	release_region(self->io.fir_base, self->io.fir_ext);	if (self->tx_buff.head)		dma_free_coherent(NULL, self->tx_buff.truesize,				  self->tx_buff.head, self->tx_buff_dma);		if (self->rx_buff.head)		dma_free_coherent(NULL, self->rx_buff.truesize,				  self->rx_buff.head, self->rx_buff_dma);	free_netdev(self->netdev);	return 0;}int w83977af_probe( int iobase, int irq, int dma){  	int version;	int i;  	 	for (i=0; i < 2; i++) { 		IRDA_DEBUG( 0, "%s()\n", __FUNCTION__ );#ifdef CONFIG_USE_W977_PNP 		/* Enter PnP configuration mode */		w977_efm_enter(efbase[i]);   		w977_select_device(W977_DEVICE_IR, efbase[i]);   		/* Configure PnP port, IRQ, and DMA channel */ 		w977_write_reg(0x60, (iobase >> 8) & 0xff, efbase[i]); 		w977_write_reg(0x61, (iobase) & 0xff, efbase[i]);   		w977_write_reg(0x70, irq, efbase[i]);#ifdef CONFIG_ARCH_NETWINDER		/* Netwinder uses 1 higher than Linux */ 		w977_write_reg(0x74, dma+1, efbase[i]);#else 		w977_write_reg(0x74, dma, efbase[i]);   #endif /*CONFIG_ARCH_NETWINDER */ 		w977_write_reg(0x75, 0x04, efbase[i]);  /* Disable Tx DMA */  	 		/* Set append hardware CRC, enable IR bank selection */	 		w977_write_reg(0xf0, APEDCRC|ENBNKSEL, efbase[i]);   		/* Activate device */ 		w977_write_reg(0x30, 0x01, efbase[i]);   		w977_efm_exit(efbase[i]);#endif /* CONFIG_USE_W977_PNP */  		/* Disable Advanced mode */  		switch_bank(iobase, SET2);  		outb(iobase+2, 0x00);    		/* Turn on UART (global) interrupts */ 		switch_bank(iobase, SET0);  		outb(HCR_EN_IRQ, iobase+HCR);  	  		/* Switch to advanced mode */  		switch_bank(iobase, SET2);  		outb(inb(iobase+ADCR1) | ADCR1_ADV_SL, iobase+ADCR1);    		/* Set default IR-mode */  		switch_bank(iobase, SET0);  		outb(HCR_SIR, iobase+HCR);    		/* Read the Advanced IR ID */  		switch_bank(iobase, SET3);  		version = inb(iobase+AUID);  	  		/* Should be 0x1? */  		if (0x10 == (version & 0xf0)) { 			efio = efbase[i];  			/* Set FIFO size to 32 */ 			switch_bank(iobase, SET2); 			outb(ADCR2_RXFS32|ADCR2_TXFS32, iobase+ADCR2);	 	 			/* Set FIFO threshold to TX17, RX16 */ 			switch_bank(iobase, SET0);	 			outb(UFR_RXTL|UFR_TXTL|UFR_TXF_RST|UFR_RXF_RST|			     UFR_EN_FIFO,iobase+UFR);  			/* Receiver frame length */ 			switch_bank(iobase, SET4);			outb(2048 & 0xff, iobase+6);			outb((2048 >> 8) & 0x1f, iobase+7);			/* 			 * Init HP HSDL-1100 transceiver. 			 * 			 * Set IRX_MSL since we have 2 * receive paths IRRX, 			 * and IRRXH. Clear IRSL0D since we want IRSL0 * to 			 * be a input pin used for IRRXH 			 *			 *   IRRX  pin 37 connected to receiver 			 *   IRTX  pin 38 connected to transmitter			 *   FIRRX pin 39 connected to receiver      (IRSL0) 			 *   CIRRX pin 40 connected to pin 37			 */			switch_bank(iobase, SET7);			outb(0x40, iobase+7);						IRDA_MESSAGE("W83977AF (IR) driver loaded. "				     "Version: 0x%02x\n", version);						return 0;		} else {			/* Try next extented function register address */			IRDA_DEBUG( 0, "%s(), Wrong chip version", __FUNCTION__ );		}  	}   		return -1;}void w83977af_change_speed(struct w83977af_ir *self, __u32 speed){	int ir_mode = HCR_SIR;	int iobase; 	__u8 set;	iobase = self->io.fir_base;	/* Update accounting for new speed */	self->io.speed = speed;	/* Save current bank */	set = inb(iobase+SSR);	/* Disable interrupts */	switch_bank(iobase, SET0);	outb(0, iobase+ICR);	/* Select Set 2 */	switch_bank(iobase, SET2);	outb(0x00, iobase+ABHL);	switch (speed) {	case 9600:   outb(0x0c, iobase+ABLL); break;	case 19200:  outb(0x06, iobase+ABLL); break;	case 38400:  outb(0x03, iobase+ABLL); break;	case 57600:  outb(0x02, iobase+ABLL); break;	case 115200: outb(0x01, iobase+ABLL); break;	case 576000:		ir_mode = HCR_MIR_576;		IRDA_DEBUG(0, "%s(), handling baud of 576000\n", __FUNCTION__ );		break;	case 1152000:		ir_mode = HCR_MIR_1152;		IRDA_DEBUG(0, "%s(), handling baud of 1152000\n", __FUNCTION__ );		break;	case 4000000:		ir_mode = HCR_FIR;		IRDA_DEBUG(0, "%s(), handling baud of 4000000\n", __FUNCTION__ );		break;	default:		ir_mode = HCR_FIR;		IRDA_DEBUG(0, "%s(), unknown baud rate of %d\n", __FUNCTION__ , speed);		break;

⌨️ 快捷键说明

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