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

📄 ali-ircc.c

📁 《linux驱动程序设计从入门到精通》一书中所有的程序代码含驱动和相应的应用程序
💻 C
📖 第 1 页 / 共 4 页
字号:
/********************************************************************* *                 * Filename:      ali-ircc.h * Version:       0.5 * Description:   Driver for the ALI M1535D and M1543C FIR Controller * Status:        Experimental. * Author:        Benjamin Kong <benjamin_kong@ali.com.tw> * Created at:    2000/10/16 03:46PM * Modified at:   2001/1/3 02:55PM * Modified by:   Benjamin Kong <benjamin_kong@ali.com.tw> * Modified at:   2003/11/6 and support for ALi south-bridge chipsets M1563 * Modified by:   Clear Zhang <clear_zhang@ali.com.tw> *  *     Copyright (c) 2000 Benjamin Kong <benjamin_kong@ali.com.tw> *     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. *   ********************************************************************/#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 <linux/dma-mapping.h>#include <linux/platform_device.h>#include <asm/io.h>#include <asm/dma.h>#include <asm/byteorder.h>#include <net/irda/wrapper.h>#include <net/irda/irda.h>#include <net/irda/irda_device.h>#include "ali-ircc.h"#define CHIP_IO_EXTENT 8#define BROKEN_DONGLE_ID#define ALI_IRCC_DRIVER_NAME "ali-ircc"/* Power Management */static int ali_ircc_suspend(struct platform_device *dev, pm_message_t state);static int ali_ircc_resume(struct platform_device *dev);static struct platform_driver ali_ircc_driver = {	.suspend	= ali_ircc_suspend,	.resume		= ali_ircc_resume,	.driver		= {		.name	= ALI_IRCC_DRIVER_NAME,	},};/* Module parameters */static int qos_mtt_bits = 0x07;  /* 1 ms or more *//* Use BIOS settions by default, but user may supply module parameters */static unsigned int io[]  = { ~0, ~0, ~0, ~0 };static unsigned int irq[] = { 0, 0, 0, 0 };static unsigned int dma[] = { 0, 0, 0, 0 };static int  ali_ircc_probe_53(ali_chip_t *chip, chipio_t *info);static int  ali_ircc_init_43(ali_chip_t *chip, chipio_t *info);static int  ali_ircc_init_53(ali_chip_t *chip, chipio_t *info);/* These are the currently known ALi sourth-bridge chipsets, the only one difference * is that M1543C doesn't support HP HDSL-3600 */static ali_chip_t chips[] ={	{ "M1543", { 0x3f0, 0x370 }, 0x51, 0x23, 0x20, 0x43, ali_ircc_probe_53, ali_ircc_init_43 },	{ "M1535", { 0x3f0, 0x370 }, 0x51, 0x23, 0x20, 0x53, ali_ircc_probe_53, ali_ircc_init_53 },	{ "M1563", { 0x3f0, 0x370 }, 0x51, 0x23, 0x20, 0x63, ali_ircc_probe_53, ali_ircc_init_53 },	{ NULL }};/* Max 4 instances for now */static struct ali_ircc_cb *dev_self[] = { NULL, NULL, NULL, NULL };/* Dongle Types */static char *dongle_types[] = {	"TFDS6000",	"HP HSDL-3600",	"HP HSDL-1100",		"No dongle connected",};/* Some prototypes */static int  ali_ircc_open(int i, chipio_t *info);static int  ali_ircc_close(struct ali_ircc_cb *self);static int  ali_ircc_setup(chipio_t *info);static int  ali_ircc_is_receiving(struct ali_ircc_cb *self);static int  ali_ircc_net_open(struct net_device *dev);static int  ali_ircc_net_close(struct net_device *dev);static int  ali_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);static void ali_ircc_change_speed(struct ali_ircc_cb *self, __u32 baud);static struct net_device_stats *ali_ircc_net_get_stats(struct net_device *dev);/* SIR function */static int  ali_ircc_sir_hard_xmit(struct sk_buff *skb, struct net_device *dev);static irqreturn_t ali_ircc_sir_interrupt(struct ali_ircc_cb *self);static void ali_ircc_sir_receive(struct ali_ircc_cb *self);static void ali_ircc_sir_write_wakeup(struct ali_ircc_cb *self);static int  ali_ircc_sir_write(int iobase, int fifo_size, __u8 *buf, int len);static void ali_ircc_sir_change_speed(struct ali_ircc_cb *priv, __u32 speed);/* FIR function */static int  ali_ircc_fir_hard_xmit(struct sk_buff *skb, struct net_device *dev);static void ali_ircc_fir_change_speed(struct ali_ircc_cb *priv, __u32 speed);static irqreturn_t ali_ircc_fir_interrupt(struct ali_ircc_cb *self);static int  ali_ircc_dma_receive(struct ali_ircc_cb *self); static int  ali_ircc_dma_receive_complete(struct ali_ircc_cb *self);static int  ali_ircc_dma_xmit_complete(struct ali_ircc_cb *self);static void ali_ircc_dma_xmit(struct ali_ircc_cb *self);/* My Function */static int  ali_ircc_read_dongle_id (int i, chipio_t *info);static void ali_ircc_change_dongle_speed(struct ali_ircc_cb *priv, int speed);/* ALi chip function */static void SIR2FIR(int iobase);static void FIR2SIR(int iobase);static void SetCOMInterrupts(struct ali_ircc_cb *self , unsigned char enable);/* * Function ali_ircc_init () * *    Initialize chip. Find out whay kinds of chips we are dealing with *    and their configuation registers address */static int __init ali_ircc_init(void){	ali_chip_t *chip;	chipio_t info;	int ret;	int cfg, cfg_base;	int reg, revision;	int i = 0;		IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__);	ret = platform_driver_register(&ali_ircc_driver);        if (ret) {                IRDA_ERROR("%s, Can't register driver!\n",			   ALI_IRCC_DRIVER_NAME);                return ret;        }	ret = -ENODEV;		/* Probe for all the ALi chipsets we know about */	for (chip= chips; chip->name; chip++, i++) 	{		IRDA_DEBUG(2, "%s(), Probing for %s ...\n", __FUNCTION__, chip->name);						/* Try all config registers for this chip */		for (cfg=0; cfg<2; cfg++)		{			cfg_base = chip->cfg[cfg];			if (!cfg_base)				continue;							memset(&info, 0, sizeof(chipio_t));			info.cfg_base = cfg_base;			info.fir_base = io[i];			info.dma = dma[i];			info.irq = irq[i];									/* Enter Configuration */			outb(chip->entr1, cfg_base);			outb(chip->entr2, cfg_base);						/* Select Logical Device 5 Registers (UART2) */			outb(0x07, cfg_base);			outb(0x05, cfg_base+1);						/* Read Chip Identification Register */			outb(chip->cid_index, cfg_base);				reg = inb(cfg_base+1);								if (reg == chip->cid_value)			{				IRDA_DEBUG(2, "%s(), Chip found at 0x%03x\n", __FUNCTION__, cfg_base);					   				outb(0x1F, cfg_base);				revision = inb(cfg_base+1);				IRDA_DEBUG(2, "%s(), Found %s chip, revision=%d\n", __FUNCTION__,					   chip->name, revision);													/* 				 * If the user supplies the base address, then				 * we init the chip, if not we probe the values				 * set by the BIOS				 */								if (io[i] < 2000)				{					chip->init(chip, &info);				}				else				{					chip->probe(chip, &info);					}								if (ali_ircc_open(i, &info) == 0)					ret = 0;				i++;							}			else			{				IRDA_DEBUG(2, "%s(), No %s chip at 0x%03x\n", __FUNCTION__, chip->name, cfg_base);			}			/* Exit configuration */			outb(0xbb, cfg_base);		}	}					IRDA_DEBUG(2, "%s(), ----------------- End -----------------\n", __FUNCTION__);					   			if (ret)		platform_driver_unregister(&ali_ircc_driver);	return ret;}/* * Function ali_ircc_cleanup () * *    Close all configured chips * */static void __exit ali_ircc_cleanup(void){	int i;	IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__);		for (i=0; i < ARRAY_SIZE(dev_self); i++) {		if (dev_self[i])			ali_ircc_close(dev_self[i]);	}		platform_driver_unregister(&ali_ircc_driver);	IRDA_DEBUG(2, "%s(), ----------------- End -----------------\n", __FUNCTION__);}/* * Function ali_ircc_open (int i, chipio_t *inf) * *    Open driver instance * */static int ali_ircc_open(int i, chipio_t *info){	struct net_device *dev;	struct ali_ircc_cb *self;	int dongle_id;	int err;				IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__);		if (i >= ARRAY_SIZE(dev_self)) {		IRDA_ERROR("%s(), maximum number of supported chips reached!\n",			   __FUNCTION__);		return -ENOMEM;	}		/* Set FIR FIFO and DMA Threshold */	if ((ali_ircc_setup(info)) == -1)		return -1;			dev = alloc_irdadev(sizeof(*self));	if (dev == NULL) {		IRDA_ERROR("%s(), can't allocate memory for control block!\n",			   __FUNCTION__);		return -ENOMEM;	}	self = dev->priv;	self->netdev = dev;	spin_lock_init(&self->lock);   	/* Need to store self somewhere */	dev_self[i] = self;	self->index = i;	/* Initialize IO */	self->io.cfg_base  = info->cfg_base;	/* In ali_ircc_probe_53 assign 		*/	self->io.fir_base  = info->fir_base;	/* info->sir_base = info->fir_base 	*/	self->io.sir_base  = info->sir_base; 	/* ALi SIR and FIR use the same address */        self->io.irq       = info->irq;        self->io.fir_ext   = CHIP_IO_EXTENT;        self->io.dma       = info->dma;        self->io.fifo_size = 16;		/* SIR: 16, FIR: 32 Benjamin 2000/11/1 */		/* Reserve the ioports that we need */	if (!request_region(self->io.fir_base, self->io.fir_ext,			    ALI_IRCC_DRIVER_NAME)) {		IRDA_WARNING("%s(), can't get iobase of 0x%03x\n", __FUNCTION__,			self->io.fir_base);		err = -ENODEV;		goto err_out1;	}	/* Initialize QoS for this device */	irda_init_max_qos_capabilies(&self->qos);		/* The only value we must override it the baudrate */	self->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600|		IR_115200|IR_576000|IR_1152000|(IR_4000000 << 8); // benjamin 2000/11/8 05:27PM				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 = 14384;	/* 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_out2;	}	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_out3;	}	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;		/* Reset Tx queue info */	self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0;	self->tx_fifo.tail = self->tx_buff.head;		/* Keep track of module usage */	SET_MODULE_OWNER(dev);	/* Override the network functions we need to use */	dev->hard_start_xmit = ali_ircc_sir_hard_xmit;	dev->open            = ali_ircc_net_open;	dev->stop            = ali_ircc_net_close;	dev->do_ioctl        = ali_ircc_net_ioctl;	dev->get_stats	     = ali_ircc_net_get_stats;	err = register_netdev(dev);	if (err) {		IRDA_ERROR("%s(), register_netdev() failed!\n", __FUNCTION__);		goto err_out4;	}	IRDA_MESSAGE("IrDA: Registered device %s\n", dev->name);	/* Check dongle id */	dongle_id = ali_ircc_read_dongle_id(i, info);	IRDA_MESSAGE("%s(), %s, Found dongle: %s\n", __FUNCTION__,		     ALI_IRCC_DRIVER_NAME, dongle_types[dongle_id]);			self->io.dongle_id = dongle_id;	IRDA_DEBUG(2, "%s(), ----------------- End -----------------\n", __FUNCTION__);		return 0; err_out4:	dma_free_coherent(NULL, self->tx_buff.truesize,			  self->tx_buff.head, self->tx_buff_dma); err_out3:	dma_free_coherent(NULL, self->rx_buff.truesize,			  self->rx_buff.head, self->rx_buff_dma); err_out2:	release_region(self->io.fir_base, self->io.fir_ext); err_out1:	dev_self[i] = NULL;	free_netdev(dev);	return err;}/* * Function ali_ircc_close (self) * *    Close driver instance * */static int __exit ali_ircc_close(struct ali_ircc_cb *self){	int iobase;	IRDA_DEBUG(4, "%s(), ---------------- Start ----------------\n", __FUNCTION__);	IRDA_ASSERT(self != NULL, return -1;);        iobase = self->io.fir_base;	/* Remove netdevice */	unregister_netdev(self->netdev);	/* Release the PORT that this driver is using */	IRDA_DEBUG(4, "%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);	dev_self[self->index] = NULL;	free_netdev(self->netdev);		IRDA_DEBUG(2, "%s(), ----------------- End -----------------\n", __FUNCTION__);		return 0;}/* * Function ali_ircc_init_43 (chip, info) * *    Initialize the ALi M1543 chip.  */static int ali_ircc_init_43(ali_chip_t *chip, chipio_t *info) {	/* All controller information like I/O address, DMA channel, IRQ	 * are set by BIOS	 */		return 0;}/* * Function ali_ircc_init_53 (chip, info) * *    Initialize the ALi M1535 chip.  */static int ali_ircc_init_53(ali_chip_t *chip, chipio_t *info) {	/* All controller information like I/O address, DMA channel, IRQ	 * are set by BIOS	 */		return 0;}/* * Function ali_ircc_probe_53 (chip, info) *    	 *	Probes for the ALi M1535D or M1535 */static int ali_ircc_probe_53(ali_chip_t *chip, chipio_t *info){	int cfg_base = info->cfg_base;	int hi, low, reg;		IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__);		/* Enter Configuration */	outb(chip->entr1, cfg_base);	outb(chip->entr2, cfg_base);		/* Select Logical Device 5 Registers (UART2) */	outb(0x07, cfg_base);	outb(0x05, cfg_base+1);		/* Read address control register */	outb(0x60, cfg_base);	hi = inb(cfg_base+1);		outb(0x61, cfg_base);	low = inb(cfg_base+1);	info->fir_base = (hi<<8) + low;		info->sir_base = info->fir_base;		IRDA_DEBUG(2, "%s(), probing fir_base=0x%03x\n", __FUNCTION__, info->fir_base);			/* Read IRQ control register */	outb(0x70, cfg_base);	reg = inb(cfg_base+1);	info->irq = reg & 0x0f;	IRDA_DEBUG(2, "%s(), probing irq=%d\n", __FUNCTION__, info->irq);		/* Read DMA channel */	outb(0x74, cfg_base);	reg = inb(cfg_base+1);	info->dma = reg & 0x07;		if(info->dma == 0x04)		IRDA_WARNING("%s(), No DMA channel assigned !\n", __FUNCTION__);	else		IRDA_DEBUG(2, "%s(), probing dma=%d\n", __FUNCTION__, info->dma);		/* Read Enabled Status */	outb(0x30, cfg_base);	reg = inb(cfg_base+1);	info->enabled = (reg & 0x80) && (reg & 0x01);	IRDA_DEBUG(2, "%s(), probing enabled=%d\n", __FUNCTION__, info->enabled);		/* Read Power Status */	outb(0x22, cfg_base);	reg = inb(cfg_base+1);	info->suspended = (reg & 0x20);	IRDA_DEBUG(2, "%s(), probing suspended=%d\n", __FUNCTION__, info->suspended);		/* Exit configuration */	outb(0xbb, cfg_base);			IRDA_DEBUG(2, "%s(), ----------------- End -----------------\n", __FUNCTION__);			return 0;	}/* * Function ali_ircc_setup (info) * *    	Set FIR FIFO and DMA Threshold *	Returns non-negative on success. * */static int ali_ircc_setup(chipio_t *info){	unsigned char tmp;	int version;	int iobase = info->fir_base;		IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__);		/* Locking comments :	 * Most operations here need to be protected. We are called before	 * the device instance is created in ali_ircc_open(), therefore 	 * nobody can bother us - Jean II */	/* Switch to FIR space */	SIR2FIR(iobase);		/* Master Reset */	outb(0x40, iobase+FIR_MCR); // benjamin 2000/11/30 11:45AM		/* Read FIR ID Version Register */	switch_bank(iobase, BANK3);	version = inb(iobase+FIR_ID_VR);

⌨️ 快捷键说明

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