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

📄 b1dma.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/* $Id: b1dma.c,v 1.1.2.3 2004/02/10 01:07:12 keil Exp $ *  * Common module for AVM B1 cards that support dma with AMCC *  * Copyright 2000 by Carsten Paeth <calle@calle.de> *  * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. * */#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/skbuff.h>#include <linux/delay.h>#include <linux/mm.h>#include <linux/interrupt.h>#include <linux/ioport.h>#include <linux/capi.h>#include <linux/kernelcapi.h>#include <asm/io.h>#include <linux/init.h>#include <asm/uaccess.h>#include <linux/netdevice.h>#include <linux/isdn/capilli.h>#include "avmcard.h"#include <linux/isdn/capicmd.h>#include <linux/isdn/capiutil.h>static char *revision = "$Revision: 1.1.2.3 $";#undef CONFIG_B1DMA_DEBUG/* ------------------------------------------------------------- */MODULE_DESCRIPTION("CAPI4Linux: DMA support for active AVM cards");MODULE_AUTHOR("Carsten Paeth");MODULE_LICENSE("GPL");static int suppress_pollack = 0;MODULE_PARM(suppress_pollack, "0-1i");/* ------------------------------------------------------------- */static void b1dma_dispatch_tx(avmcard *card);/* ------------------------------------------------------------- *//* S5933 */#define	AMCC_RXPTR	0x24#define	AMCC_RXLEN	0x28#define	AMCC_TXPTR	0x2c#define	AMCC_TXLEN	0x30#define	AMCC_INTCSR	0x38#	define EN_READ_TC_INT		0x00008000L#	define EN_WRITE_TC_INT		0x00004000L#	define EN_TX_TC_INT		EN_READ_TC_INT#	define EN_RX_TC_INT		EN_WRITE_TC_INT#	define AVM_FLAG			0x30000000L#	define ANY_S5933_INT		0x00800000L#	define READ_TC_INT		0x00080000L#	define WRITE_TC_INT		0x00040000L#	define	TX_TC_INT		READ_TC_INT#	define	RX_TC_INT		WRITE_TC_INT#	define MASTER_ABORT_INT		0x00100000L#	define TARGET_ABORT_INT		0x00200000L#	define BUS_MASTER_INT		0x00200000L#	define ALL_INT			0x000C0000L#define	AMCC_MCSR	0x3c#	define A2P_HI_PRIORITY		0x00000100L#	define EN_A2P_TRANSFERS		0x00000400L#	define P2A_HI_PRIORITY		0x00001000L#	define EN_P2A_TRANSFERS		0x00004000L#	define RESET_A2P_FLAGS		0x04000000L#	define RESET_P2A_FLAGS		0x02000000L/* ------------------------------------------------------------- */static inline void b1dma_writel(avmcard *card, u32 value, int off){	writel(value, card->mbase + off);}static inline u32 b1dma_readl(avmcard *card, int off){	return readl(card->mbase + off);}/* ------------------------------------------------------------- */static inline int b1dma_tx_empty(unsigned int port){	return inb(port + 0x03) & 0x1;}static inline int b1dma_rx_full(unsigned int port){	return inb(port + 0x02) & 0x1;}static int b1dma_tolink(avmcard *card, void *buf, unsigned int len){	unsigned long stop = jiffies + 1 * HZ;	/* maximum wait time 1 sec */	unsigned char *s = (unsigned char *)buf;	while (len--) {		while (   !b1dma_tx_empty(card->port)		       && time_before(jiffies, stop));		if (!b1dma_tx_empty(card->port)) 			return -1;	        t1outp(card->port, 0x01, *s++);	}	return 0;}static int b1dma_fromlink(avmcard *card, void *buf, unsigned int len){	unsigned long stop = jiffies + 1 * HZ;	/* maximum wait time 1 sec */	unsigned char *s = (unsigned char *)buf;	while (len--) {		while (   !b1dma_rx_full(card->port)		       && time_before(jiffies, stop));		if (!b1dma_rx_full(card->port)) 			return -1;	        *s++ = t1inp(card->port, 0x00);	}	return 0;}static int WriteReg(avmcard *card, u32 reg, u8 val){	u8 cmd = 0x00;	if (   b1dma_tolink(card, &cmd, 1) == 0	    && b1dma_tolink(card, &reg, 4) == 0) {		u32 tmp = val;		return b1dma_tolink(card, &tmp, 4);	}	return -1;}static u8 ReadReg(avmcard *card, u32 reg){	u8 cmd = 0x01;	if (   b1dma_tolink(card, &cmd, 1) == 0	    && b1dma_tolink(card, &reg, 4) == 0) {		u32 tmp;		if (b1dma_fromlink(card, &tmp, 4) == 0)			return (u8)tmp;	}	return 0xff;}/* ------------------------------------------------------------- */static inline void _put_byte(void **pp, u8 val){	u8 *s = *pp;	*s++ = val;	*pp = s;}static inline void _put_word(void **pp, u32 val){	u8 *s = *pp;	*s++ = val & 0xff;	*s++ = (val >> 8) & 0xff;	*s++ = (val >> 16) & 0xff;	*s++ = (val >> 24) & 0xff;	*pp = s;}static inline void _put_slice(void **pp, unsigned char *dp, unsigned int len){	unsigned i = len;	_put_word(pp, i);	while (i-- > 0)		_put_byte(pp, *dp++);}static inline u8 _get_byte(void **pp){	u8 *s = *pp;	u8 val;	val = *s++;	*pp = s;	return val;}static inline u32 _get_word(void **pp){	u8 *s = *pp;	u32 val;	val = *s++;	val |= (*s++ << 8);	val |= (*s++ << 16);	val |= (*s++ << 24);	*pp = s;	return val;}static inline u32 _get_slice(void **pp, unsigned char *dp){	unsigned int len, i;	len = i = _get_word(pp);	while (i-- > 0) *dp++ = _get_byte(pp);	return len;}/* ------------------------------------------------------------- */void b1dma_reset(avmcard *card){	card->csr = 0x0;	b1dma_writel(card, card->csr, AMCC_INTCSR);	b1dma_writel(card, 0, AMCC_MCSR);	b1dma_writel(card, 0, AMCC_RXLEN);	b1dma_writel(card, 0, AMCC_TXLEN);	t1outp(card->port, 0x10, 0x00);	t1outp(card->port, 0x07, 0x00);	b1dma_writel(card, 0, AMCC_MCSR);	mdelay(10);	b1dma_writel(card, 0x0f000000, AMCC_MCSR); /* reset all */	mdelay(10);	b1dma_writel(card, 0, AMCC_MCSR);	if (card->cardtype == avm_t1pci)		mdelay(42);	else		mdelay(10);}/* ------------------------------------------------------------- */static int b1dma_detect(avmcard *card){	b1dma_writel(card, 0, AMCC_MCSR);	mdelay(10);	b1dma_writel(card, 0x0f000000, AMCC_MCSR); /* reset all */	mdelay(10);	b1dma_writel(card, 0, AMCC_MCSR);	mdelay(42);	b1dma_writel(card, 0, AMCC_RXLEN);	b1dma_writel(card, 0, AMCC_TXLEN);	card->csr = 0x0;	b1dma_writel(card, card->csr, AMCC_INTCSR);	if (b1dma_readl(card, AMCC_MCSR) != 0x000000E6)		return 1;	b1dma_writel(card, 0xffffffff, AMCC_RXPTR);	b1dma_writel(card, 0xffffffff, AMCC_TXPTR);	if (   b1dma_readl(card, AMCC_RXPTR) != 0xfffffffc	    || b1dma_readl(card, AMCC_TXPTR) != 0xfffffffc)		return 2;	b1dma_writel(card, 0x0, AMCC_RXPTR);	b1dma_writel(card, 0x0, AMCC_TXPTR);	if (   b1dma_readl(card, AMCC_RXPTR) != 0x0	    || b1dma_readl(card, AMCC_TXPTR) != 0x0)		return 3;	t1outp(card->port, 0x10, 0x00);	t1outp(card->port, 0x07, 0x00);		t1outp(card->port, 0x02, 0x02);	t1outp(card->port, 0x03, 0x02);	if (   (t1inp(card->port, 0x02) & 0xFE) != 0x02	    || t1inp(card->port, 0x3) != 0x03)		return 4;	t1outp(card->port, 0x02, 0x00);	t1outp(card->port, 0x03, 0x00);	if (   (t1inp(card->port, 0x02) & 0xFE) != 0x00	    || t1inp(card->port, 0x3) != 0x01)		return 5;	return 0;}int t1pci_detect(avmcard *card){	int ret;	if ((ret = b1dma_detect(card)) != 0)		return ret;		/* Transputer test */		if (   WriteReg(card, 0x80001000, 0x11) != 0	    || WriteReg(card, 0x80101000, 0x22) != 0	    || WriteReg(card, 0x80201000, 0x33) != 0	    || WriteReg(card, 0x80301000, 0x44) != 0)		return 6;	if (   ReadReg(card, 0x80001000) != 0x11	    || ReadReg(card, 0x80101000) != 0x22	    || ReadReg(card, 0x80201000) != 0x33	    || ReadReg(card, 0x80301000) != 0x44)		return 7;	if (   WriteReg(card, 0x80001000, 0x55) != 0	    || WriteReg(card, 0x80101000, 0x66) != 0	    || WriteReg(card, 0x80201000, 0x77) != 0	    || WriteReg(card, 0x80301000, 0x88) != 0)		return 8;	if (   ReadReg(card, 0x80001000) != 0x55	    || ReadReg(card, 0x80101000) != 0x66	    || ReadReg(card, 0x80201000) != 0x77	    || ReadReg(card, 0x80301000) != 0x88)		return 9;	return 0;}int b1pciv4_detect(avmcard *card){	int ret, i;	if ((ret = b1dma_detect(card)) != 0)		return ret;		for (i=0; i < 5 ; i++) {		if (WriteReg(card, 0x80A00000, 0x21) != 0)			return 6;		if ((ReadReg(card, 0x80A00000) & 0x01) != 0x01)			return 7;	}	for (i=0; i < 5 ; i++) {		if (WriteReg(card, 0x80A00000, 0x20) != 0)			return 8;		if ((ReadReg(card, 0x80A00000) & 0x01) != 0x00)			return 9;	}		return 0;}static void b1dma_queue_tx(avmcard *card, struct sk_buff *skb){	unsigned long flags;	spin_lock_irqsave(&card->lock, flags);	skb_queue_tail(&card->dma->send_queue, skb);	if (!(card->csr & EN_TX_TC_INT)) {		b1dma_dispatch_tx(card);		b1dma_writel(card, card->csr, AMCC_INTCSR);	}	spin_unlock_irqrestore(&card->lock, flags);}/* ------------------------------------------------------------- */static void b1dma_dispatch_tx(avmcard *card){	avmcard_dmainfo *dma = card->dma;	struct sk_buff *skb;	u8 cmd, subcmd;	u16 len;	u32 txlen;	void *p;		skb = skb_dequeue(&dma->send_queue);	len = CAPIMSG_LEN(skb->data);	if (len) {		cmd = CAPIMSG_COMMAND(skb->data);		subcmd = CAPIMSG_SUBCOMMAND(skb->data);		p = dma->sendbuf.dmabuf;		if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) {			u16 dlen = CAPIMSG_DATALEN(skb->data);			_put_byte(&p, SEND_DATA_B3_REQ);			_put_slice(&p, skb->data, len);			_put_slice(&p, skb->data + len, dlen);		} else {			_put_byte(&p, SEND_MESSAGE);			_put_slice(&p, skb->data, len);		}		txlen = (u8 *)p - (u8 *)dma->sendbuf.dmabuf;#ifdef CONFIG_B1DMA_DEBUG		printk(KERN_DEBUG "tx: put msg len=%d\n", txlen);#endif	} else {		txlen = skb->len-2;#ifdef CONFIG_B1DMA_POLLDEBUG		if (skb->data[2] == SEND_POLLACK)			printk(KERN_INFO "%s: send ack\n", card->name);#endif#ifdef CONFIG_B1DMA_DEBUG		printk(KERN_DEBUG "tx: put 0x%x len=%d\n", 		       skb->data[2], txlen);#endif		memcpy(dma->sendbuf.dmabuf, skb->data+2, skb->len-2);	}	txlen = (txlen + 3) & ~3;	b1dma_writel(card, dma->sendbuf.dmaaddr, AMCC_TXPTR);	b1dma_writel(card, txlen, AMCC_TXLEN);	card->csr |= EN_TX_TC_INT;	dev_kfree_skb_any(skb);}/* ------------------------------------------------------------- */static void queue_pollack(avmcard *card){	struct sk_buff *skb;	void *p;	skb = alloc_skb(3, GFP_ATOMIC);	if (!skb) {		printk(KERN_CRIT "%s: no memory, lost poll ack\n",					card->name);		return;	}	p = skb->data;	_put_byte(&p, 0);	_put_byte(&p, 0);	_put_byte(&p, SEND_POLLACK);	skb_put(skb, (u8 *)p - (u8 *)skb->data);	b1dma_queue_tx(card, skb);}/* ------------------------------------------------------------- */static void b1dma_handle_rx(avmcard *card){	avmctrl_info *cinfo = &card->ctrlinfo[0];	avmcard_dmainfo *dma = card->dma;	struct capi_ctr *ctrl = &cinfo->capi_ctrl;	struct sk_buff *skb;	void *p = dma->recvbuf.dmabuf+4;	u32 ApplId, MsgLen, DataB3Len, NCCI, WindowSize;	u8 b1cmd =  _get_byte(&p);#ifdef CONFIG_B1DMA_DEBUG	printk(KERN_DEBUG "rx: 0x%x %lu\n", b1cmd, (unsigned long)dma->recvlen);#endif		switch (b1cmd) {	case RECEIVE_DATA_B3_IND:		ApplId = (unsigned) _get_word(&p);		MsgLen = _get_slice(&p, card->msgbuf);		DataB3Len = _get_slice(&p, card->databuf);		if (MsgLen < 30) { /* not CAPI 64Bit */			memset(card->msgbuf+MsgLen, 0, 30-MsgLen);			MsgLen = 30;			CAPIMSG_SETLEN(card->msgbuf, 30);		}		if (!(skb = alloc_skb(DataB3Len+MsgLen, GFP_ATOMIC))) {			printk(KERN_ERR "%s: incoming packet dropped\n",					card->name);		} else {			memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);			memcpy(skb_put(skb, DataB3Len), card->databuf, DataB3Len);			capi_ctr_handle_message(ctrl, ApplId, skb);		}		break;	case RECEIVE_MESSAGE:		ApplId = (unsigned) _get_word(&p);		MsgLen = _get_slice(&p, card->msgbuf);		if (!(skb = alloc_skb(MsgLen, GFP_ATOMIC))) {			printk(KERN_ERR "%s: incoming packet dropped\n",					card->name);		} else {			memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);			if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_CONF)				capilib_data_b3_conf(&cinfo->ncci_head, ApplId,						     CAPIMSG_NCCI(skb->data),

⌨️ 快捷键说明

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