hisax_fcclassic.c

来自「是关于linux2.5.1的完全源码」· C语言 代码 · 共 385 行

C
385
字号
/* * Driver for AVM Fritz!classic (ISA) ISDN card * * Author       Kai Germaschewski * Copyright    2001 by Kai Germaschewski  <kai.germaschewski@gmx.de> *              2001 by Karsten Keil       <keil@isdn4linux.de> *  * based upon Karsten Keil's original avm_a1.c driver * * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. * */#include <linux/version.h>#include <linux/module.h>#include <linux/init.h>#include <linux/pci.h>#include <linux/isapnp.h>#include <linux/kmod.h>#include <linux/slab.h>#include <linux/skbuff.h>#include <linux/netdevice.h>#include "hisax_fcclassic.h"// debugging cruft#define __debug_variable debug#include "hisax_debug.h"#ifdef CONFIG_HISAX_DEBUGstatic int debug = 0;MODULE_PARM(debug, "i");#endifMODULE_AUTHOR("Kai Germaschewski <kai.germaschewski@gmx.de>/Karsten Keil <kkeil@suse.de>");MODULE_DESCRIPTION("AVM Fritz!Card classic ISDN driver");static int protocol = 2;       /* EURO-ISDN Default */MODULE_PARM(protocol, "i");// ----------------------------------------------------------------------#define	 AVM_A1_STAT_ISAC	0x01#define	 AVM_A1_STAT_HSCX	0x02#define	 AVM_A1_STAT_TIMER	0x04// ----------------------------------------------------------------------static unsigned charfcclassic_read_isac(struct isac *isac, unsigned char offset){	struct fritz_adapter *adapter = isac->priv;	unsigned char val;	val = inb(adapter->isac_base + offset);	DBG(0x1000, " port %#x, value %#x",	    offset, val);	return val;}static voidfcclassic_write_isac(struct isac *isac, unsigned char offset,		     unsigned char value){	struct fritz_adapter *adapter = isac->priv;	DBG(0x1000, " port %#x, value %#x",	    offset, value);	outb(value, adapter->isac_base + offset);}static voidfcclassic_read_isac_fifo(struct isac *isac, unsigned char * data, int size){	struct fritz_adapter *adapter = isac->priv;	insb(adapter->isac_fifo, data, size);}static voidfcclassic_write_isac_fifo(struct isac *isac, unsigned char * data, int size){	struct fritz_adapter *adapter = isac->priv;	outsb(adapter->isac_fifo, data, size);}static u_charfcclassic_read_hscx(struct hscx *hscx, u_char offset){	struct fritz_adapter *adapter = hscx->priv;	return inb(adapter->hscx_base[hscx->channel] + offset);}static voidfcclassic_write_hscx(struct hscx *hscx, u_char offset, u_char value){	struct fritz_adapter *adapter = hscx->priv;	outb(value, adapter->hscx_base[hscx->channel] + offset);}static voidfcclassic_read_hscx_fifo(struct hscx *hscx, unsigned char * data, int size){	struct fritz_adapter *adapter = hscx->priv;	insb(adapter->hscx_fifo[hscx->channel], data, size);}static voidfcclassic_write_hscx_fifo(struct hscx *hscx, unsigned char * data, int size){	struct fritz_adapter *adapter = hscx->priv;	outsb(adapter->hscx_fifo[hscx->channel], data, size);}// ----------------------------------------------------------------------static voidfcclassic_irq(int intno, void *dev, struct pt_regs *regs){	struct fritz_adapter *adapter = dev;	unsigned char sval;	DBG(2, "");	while ((sval = inb(adapter->cfg_reg) & 0xf) != 0x7) {		DBG(2, "sval %#x", sval);		if (!(sval & AVM_A1_STAT_TIMER)) {			outb(0x1e, adapter->cfg_reg);		}		if (!(sval & AVM_A1_STAT_HSCX)) {			hscx_irq(adapter->hscx);		}		if (!(sval & AVM_A1_STAT_ISAC)) {			isac_irq(&adapter->isac);		}	}}// ----------------------------------------------------------------------static int __initfcclassic_setup(struct fritz_adapter *adapter){	u32 val = 0;	int i;	int retval;	DBG(1,"");	isac_init(&adapter->isac); // FIXME is this okay now	adapter->cfg_reg      = adapter->io + 0x1800;	adapter->isac_base    = adapter->io + 0x1400 - 0x20;	adapter->isac_fifo    = adapter->io + 0x1000;	adapter->hscx_base[0] = adapter->io + 0x0400 - 0x20;	adapter->hscx_fifo[0] = adapter->io;	adapter->hscx_base[1] = adapter->io + 0x0c00 - 0x20;	adapter->hscx_fifo[1] = adapter->io + 0x0800;	retval = -EBUSY;	if (!request_region(adapter->cfg_reg            ,  8,			    "fcclassic cfg"))		goto err;	if (!request_region(adapter->isac_base + 0x20   , 32,			    "fcclassic isac"))		goto err_cfg_reg;	if (!request_region(adapter->isac_fifo          ,  1,			    "fcclassic isac fifo"))		goto err_isac_base;	if (!request_region(adapter->hscx_base[0] + 0x20, 32,			    "fcclassic hscx"))		goto err_isac_fifo;	if (!request_region(adapter->hscx_fifo[0]       ,  1,			    "fcclassic hscx fifo"))		goto err_hscx_base_0;	if (!request_region(adapter->hscx_base[1] + 0x20, 32,			    "fcclassic hscx"))		goto err_hscx_fifo_0;	if (!request_region(adapter->hscx_fifo[1]       ,  1,			    "fcclassic hscx fifo"))		goto err_hscx_base_1;	retval = request_irq(adapter->irq, fcclassic_irq,  0,			     "fcclassic", adapter);	if (retval)		goto err_hscx_fifo_1;	// Reset	outb(0x00, adapter->cfg_reg);	set_current_state(TASK_UNINTERRUPTIBLE);	schedule_timeout(200 * HZ / 1000); // 200 msec	outb(0x01, adapter->cfg_reg);	set_current_state(TASK_UNINTERRUPTIBLE);	schedule_timeout(200 * HZ / 1000); // 200 msec	outb(0x00, adapter->cfg_reg);	set_current_state(TASK_UNINTERRUPTIBLE);	schedule_timeout(200 * HZ / 1000); // 200 msec	val = adapter->irq;	if (val == 9)		val = 2;	outb(val, adapter->cfg_reg + 1);	set_current_state(TASK_UNINTERRUPTIBLE);	schedule_timeout(200 * HZ / 1000); // 200 msec	outb(0x00, adapter->cfg_reg);	set_current_state(TASK_UNINTERRUPTIBLE);	schedule_timeout(200 * HZ / 1000); // 200 msec	val = inb(adapter->cfg_reg);	printk(KERN_INFO "AVM A1: Byte at %x is %x\n",	       adapter->cfg_reg, val);	val = inb(adapter->cfg_reg + 3);	printk(KERN_INFO "AVM A1: Byte at %x is %x\n",	       adapter->cfg_reg + 3, val);	val = inb(adapter->cfg_reg + 2);	printk(KERN_INFO "AVM A1: Byte at %x is %x\n",	       adapter->cfg_reg + 2, val);	val = inb(adapter->cfg_reg);	printk(KERN_INFO "AVM A1: Byte at %x is %x\n",	       adapter->cfg_reg, val);	outb(0x16, adapter->cfg_reg);	outb(0x1e, adapter->cfg_reg);	adapter->isac.priv            = adapter;	adapter->isac.read_isac       = &fcclassic_read_isac;	adapter->isac.write_isac      = &fcclassic_write_isac;	adapter->isac.read_isac_fifo  = &fcclassic_read_isac_fifo;	adapter->isac.write_isac_fifo = &fcclassic_write_isac_fifo;	isac_setup(&adapter->isac);	for (i = 0; i < 2; i++) {		hscx_init(&adapter->hscx[i]);		adapter->hscx[i].priv            = adapter;		adapter->hscx[i].read_hscx       = &fcclassic_read_hscx;		adapter->hscx[i].write_hscx      = &fcclassic_write_hscx;		adapter->hscx[i].read_hscx_fifo  = &fcclassic_read_hscx_fifo;		adapter->hscx[i].write_hscx_fifo = &fcclassic_write_hscx_fifo;		hscx_setup(&adapter->hscx[i]);	}	return 0; err_hscx_fifo_1:	release_region(adapter->hscx_fifo[1]       ,  1); err_hscx_base_1:	release_region(adapter->hscx_base[1] + 0x20, 32); err_hscx_fifo_0:	release_region(adapter->hscx_fifo[0]       ,  1); err_hscx_base_0:	release_region(adapter->hscx_base[0] + 0x20, 32); err_isac_fifo:	release_region(adapter->isac_fifo          ,  1); err_isac_base:	release_region(adapter->isac_base    + 0x20, 32); err_cfg_reg:	release_region(adapter->cfg_reg            ,  8); err:	return retval;}static void __exit fcclassic_release(struct fritz_adapter *adapter){	DBG(1,"");//	outb(0, adapter->io + AVM_STATUS0);	free_irq(adapter->irq, adapter);	release_region(adapter->hscx_fifo[1]       ,  1);	release_region(adapter->hscx_base[1] + 0x20, 32);	release_region(adapter->hscx_fifo[0]       ,  1);	release_region(adapter->hscx_base[0] + 0x20, 32);	release_region(adapter->isac_fifo          ,  1);	release_region(adapter->isac_base    + 0x20, 32);	release_region(adapter->cfg_reg            ,  8);}// ----------------------------------------------------------------------static struct fritz_adapter * __init new_adapter(struct pci_dev *pdev){	struct fritz_adapter *adapter;	struct hisax_b_if *b_if[2];	int i;	adapter = kmalloc(sizeof(struct fritz_adapter), GFP_KERNEL);	if (!adapter)		return NULL;	memset(adapter, 0, sizeof(struct fritz_adapter));	SET_MODULE_OWNER(&adapter->isac.hisax_d_if);	adapter->isac.hisax_d_if.ifc.priv = &adapter->isac;	adapter->isac.hisax_d_if.ifc.l2l1 = isac_d_l2l1;	for (i = 0; i < 2; i++) {	  //		adapter->hscx[i].adapter = adapter;		adapter->hscx[i].channel = i;		adapter->hscx[i].b_if.ifc.priv = &adapter->hscx[i];		adapter->hscx[i].b_if.ifc.l2l1 = hscx_b_l2l1;	}	pci_set_drvdata(pdev, adapter);	for (i = 0; i < 2; i++)		b_if[i] = &adapter->hscx[i].b_if;	hisax_register(&adapter->isac.hisax_d_if, b_if, "fcclassic", protocol);	return adapter;}static voiddelete_adapter(struct fritz_adapter *adapter){	hisax_unregister(&adapter->isac.hisax_d_if);	kfree(adapter);}static int __initfcclassic_probe(struct pci_dev *pdev, const struct isapnp_device_id *ent){	struct fritz_adapter *adapter;	int retval;	retval = -ENOMEM;	adapter = new_adapter(pdev);	if (!adapter)		goto err;	adapter->io = pdev->resource[0].start;	adapter->irq = pdev->irq_resource[0].start;	printk(KERN_INFO "hisax_fcclassic: found Fritz!Card classic at IO %#x irq %d\n",	       adapter->io, adapter->irq);	retval = fcclassic_setup(adapter);	if (retval)		goto err_free;	return 0;	 err_free:	delete_adapter(adapter); err:	return retval;}static int __exit fcclassic_remove(struct pci_dev *pdev){	struct fritz_adapter *adapter = pci_get_drvdata(pdev);	fcclassic_release(adapter);	delete_adapter(adapter);	return 0;}static struct pci_dev isa_dev[4];static int __inithisax_fcclassic_init(void){	printk(KERN_INFO "hisax_fcclassic: Fritz!Card classic ISDN driver v0.0.1\n");	isa_dev[0].resource[0].start = 0x300;	isa_dev[0].irq_resource[0].start = 7;	fcclassic_probe(isa_dev, NULL);	return 0;}static void __exithisax_fcclassic_exit(void){	fcclassic_remove(isa_dev);}module_init(hisax_fcclassic_init);module_exit(hisax_fcclassic_exit);

⌨️ 快捷键说明

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