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

📄 lanai.c

📁 linux和2410结合开发 用他可以生成2410所需的zImage文件
💻 C
📖 第 1 页 / 共 5 页
字号:
static inline void intr_enable(const struct lanai_dev *lanai, u32 i){	reg_write(lanai, i, IntControlEna_Reg);}static inline void intr_disable(const struct lanai_dev *lanai, u32 i){	reg_write(lanai, i, IntControlDis_Reg);}/* -------------------- CARD/PCI STATUS: */static void status_message(int itf, const char *name, int status){	static const char *onoff[2] = { "off to on", "on to off" };	printk(KERN_INFO DEV_LABEL "(itf %d): %s changed from %s\n",	    itf, name, onoff[!status]);}static void lanai_check_status(struct lanai_dev *lanai){	u32 new = reg_read(lanai, Status_Reg);	u32 changes = new ^ lanai->status;	lanai->status = new;#define e(flag, name) \		if (changes & flag) \			status_message(lanai->number, name, new & flag)	e(STATUS_SOOL, "SOOL");	e(STATUS_LOCD, "LOCD");	e(STATUS_LED, "LED");	e(STATUS_GPIN, "GPIN");#undef e}static void pcistatus_got(int itf, const char *name){	printk(KERN_INFO DEV_LABEL "(itf %d): PCI got %s error\n", itf, name);}static void pcistatus_check(struct lanai_dev *lanai, int clearonly){	u16 s;	int result;	result = pci_read_config_word(lanai->pci, PCI_STATUS, &s);	if (result != PCIBIOS_SUCCESSFUL) {		printk(KERN_ERR DEV_LABEL "(itf %d): can't read PCI_STATUS: "		    "%d\n", lanai->number, result);		return;	}	s &= PCI_STATUS_DETECTED_PARITY | PCI_STATUS_SIG_SYSTEM_ERROR |	    PCI_STATUS_REC_MASTER_ABORT | PCI_STATUS_REC_TARGET_ABORT |	    PCI_STATUS_SIG_TARGET_ABORT | PCI_STATUS_PARITY;	if (s == 0)		return;	result = pci_write_config_word(lanai->pci, PCI_STATUS, s);	if (result != PCIBIOS_SUCCESSFUL)		printk(KERN_ERR DEV_LABEL "(itf %d): can't write PCI_STATUS: "		    "%d\n", lanai->number, result);	if (clearonly)		return;#define e(flag, name, stat) \		if (s & flag) { \			pcistatus_got(lanai->number, name); \			++lanai->stats.pcierr_##stat; \		}	e(PCI_STATUS_DETECTED_PARITY, "parity", parity_detect);	e(PCI_STATUS_SIG_SYSTEM_ERROR, "signalled system", serr_set);	e(PCI_STATUS_REC_MASTER_ABORT, "master", master_abort);	e(PCI_STATUS_REC_TARGET_ABORT, "master target", m_target_abort);	e(PCI_STATUS_SIG_TARGET_ABORT, "slave", s_target_abort);	e(PCI_STATUS_PARITY, "master parity", master_parity);#undef e}/* -------------------- VCC TX BUFFER UTILITIES: *//* space left in tx buffer in bytes */static inline int vcc_tx_space(const struct lanai_vcc *lvcc, int endptr){	int r;	r = endptr * 16;	r -= ((unsigned long) lvcc->tx.buf.ptr) -	    ((unsigned long) lvcc->tx.buf.start);	r -= 16;	/* Leave "bubble" - if start==end it looks empty */	if (r < 0)		r += lanai_buf_size(&lvcc->tx.buf);	return r;}/* Bit fields in the segmentation buffer descriptor */#define DESCRIPTOR_MAGIC	(0xD0000000)#define DESCRIPTOR_AAL5		(0x00008000)#define DESCRIPTOR_AAL5_STREAM	(0x00004000)#define DESCRIPTOR_CLP		(0x00002000)/* Add 32-bit descriptor with it's padding */static inline void vcc_tx_add_aal5_descriptor(struct lanai_vcc *lvcc,	u32 flags, int len){	int pos;	APRINTK((((unsigned long) lvcc->tx.buf.ptr) & 15) == 0,	    "vcc_tx_add_aal5_descriptor: bad ptr=%p\n", lvcc->tx.buf.ptr);	lvcc->tx.buf.ptr += 4;	/* Hope the values REALLY don't matter */	pos = ((unsigned char *) lvcc->tx.buf.ptr) -	    (unsigned char *) lvcc->tx.buf.start;	APRINTK((pos & ~0x0001FFF0) == 0,	    "vcc_tx_add_aal5_descriptor: bad pos (%d) before, vci=%d, "	    "start,ptr,end=%p,%p,%p\n", pos, lvcc->vci,	    lvcc->tx.buf.start, lvcc->tx.buf.ptr, lvcc->tx.buf.end);	pos = (pos + len) & (lanai_buf_size(&lvcc->tx.buf) - 1);	APRINTK((pos & ~0x0001FFF0) == 0,	    "vcc_tx_add_aal5_descriptor: bad pos (%d) after, vci=%d, "	    "start,ptr,end=%p,%p,%p\n", pos, lvcc->vci,	    lvcc->tx.buf.start, lvcc->tx.buf.ptr, lvcc->tx.buf.end);	lvcc->tx.buf.ptr[-1] =	    cpu_to_le32(DESCRIPTOR_MAGIC | DESCRIPTOR_AAL5 |	    ((lvcc->tx.atmvcc->atm_options & ATM_ATMOPT_CLP) ?	    DESCRIPTOR_CLP : 0) | flags | pos >> 4);	if (lvcc->tx.buf.ptr >= lvcc->tx.buf.end)		lvcc->tx.buf.ptr = lvcc->tx.buf.start;}/* Add 32-bit AAL5 trailer and leave room for its CRC */static inline void vcc_tx_add_aal5trailer(struct lanai_vcc *lvcc,	int len, int cpi, int uu){	APRINTK((((unsigned long) lvcc->tx.buf.ptr) & 15) == 8,	    "vcc_tx_add_aal5_descriptor: bad ptr=%p\n", lvcc->tx.buf.ptr);	lvcc->tx.buf.ptr += 2;	lvcc->tx.buf.ptr[-2] = cpu_to_be32((uu << 24) | (cpi << 16) | len);	if (lvcc->tx.buf.ptr >= lvcc->tx.buf.end)		lvcc->tx.buf.ptr = lvcc->tx.buf.start;}static inline void vcc_tx_memcpy(struct lanai_vcc *lvcc,	const unsigned char *src, int n){	unsigned char *e;	int m;	e = ((unsigned char *) lvcc->tx.buf.ptr) + n;	m = e - (unsigned char *) lvcc->tx.buf.end;	if (m < 0)		m = 0;	memcpy(lvcc->tx.buf.ptr, src, n - m);	if (m != 0) {		memcpy(lvcc->tx.buf.start, src + n - m, m);		e = ((unsigned char *) lvcc->tx.buf.start) + m;	}	lvcc->tx.buf.ptr = (u32 *) e;}static inline void vcc_tx_memzero(struct lanai_vcc *lvcc, int n){	unsigned char *e;	int m;	if (n == 0)		return;	e = ((unsigned char *) lvcc->tx.buf.ptr) + n;	m = e - (unsigned char *) lvcc->tx.buf.end;	if (m < 0)		m = 0;	memset(lvcc->tx.buf.ptr, 0, n - m);	if (m != 0) {		memset(lvcc->tx.buf.start, 0, m);		e = ((unsigned char *) lvcc->tx.buf.start) + m;	}	lvcc->tx.buf.ptr = (u32 *) e;}/* Update "butt" register to specify new WritePtr */static inline void lanai_endtx(const struct lanai_dev *lanai,	const struct lanai_vcc *lvcc){	int i, ptr = ((unsigned char *) lvcc->tx.buf.ptr) -	    (unsigned char *) lvcc->tx.buf.start;	APRINTK((ptr & ~0x0001FFF0) == 0,	    "lanai_endtx: bad ptr (%d), vci=%d, start,ptr,end=%p,%p,%p\n",	    ptr, lvcc->vci, lvcc->tx.buf.start, lvcc->tx.buf.ptr,	    lvcc->tx.buf.end);	/*	 * We need to check if the "butt busy" bit is set before	 * updating the butt register.  In theory this should	 * never happen because the ATM card is plenty fast at	 * updating the register.  Still, we should make sure	 */	for (i = 0; reg_read(lanai, Status_Reg) & STATUS_BUTTBUSY; i++) {		if (i > 50) {			printk(KERN_ERR DEV_LABEL "(itf %d): butt register "			    "always busy!\n", lanai->number);			break;		}		udelay(5);	}	reg_write(lanai, (ptr << 12) | lvcc->vci, Butt_Reg);}/* Try to fill the buffer - don't call unless there is backlog */static void vcc_tx_unqueue_aal5(struct lanai_dev *lanai,	struct lanai_vcc *lvcc, int endptr){	int pad, n;	struct sk_buff *skb;	int space = vcc_tx_space(lvcc, endptr);	APRINTK(vcc_is_backlogged(lvcc),	    "vcc_tx_unqueue() called with empty backlog (vci=%d)\n",	    lvcc->vci);	if (space < 64)		return;		/* No space for even 1 cell+descriptor */	if (lvcc->tx.inprogress != NULL) {		APRINTK((lvcc->tx.inprogleft % 48) == 0,		    "vcc_tx_unqueue_aal5: bad progleft=%d\n",		    lvcc->tx.inprogleft);		if (lvcc->tx.inprogleft + 16 > space) {	/* Can't send all? */			n = aal5_spacefor(space - 16);	/* Bytes to send */			vcc_tx_add_aal5_descriptor(lvcc,			    DESCRIPTOR_AAL5_STREAM, n);			pad = lvcc->tx.pptr + n - lvcc->tx.inprogress->tail;			if (pad < 0)				pad = 0;			vcc_tx_memcpy(lvcc, lvcc->tx.pptr, n - pad);			vcc_tx_memzero(lvcc, pad);			lvcc->tx.pptr += n;			lvcc->tx.inprogleft -= n;			goto end;		/* Buffer is now full */		}		/* OK, there's at least space for all of "inprogress" skb */		vcc_tx_add_aal5_descriptor(lvcc, 0,		    lvcc->tx.inprogleft);		pad = lvcc->tx.pptr + lvcc->tx.inprogleft -		    lvcc->tx.inprogress->tail;		if (pad >= lvcc->tx.inprogleft) { /* Nothing but pad left */			APRINTK(lvcc->tx.inprogleft == 48,			    "vcc_tx_unqueue_aal5: bad pure-pad=%d\n",			    lvcc->tx.inprogleft);			pad = 48;		} else			vcc_tx_memcpy(lvcc, lvcc->tx.pptr,			    lvcc->tx.inprogleft - pad);		vcc_tx_memzero(lvcc, pad - 8);		vcc_tx_add_aal5trailer(lvcc, lvcc->tx.inprogress->len, 0, 0);		lanai_free_skb(lvcc->tx.atmvcc, lvcc->tx.inprogress);		lvcc->tx.inprogress = NULL;		space -= lvcc->tx.inprogleft + 16;		atomic_inc(&lvcc->tx.atmvcc->stats->tx);	}	while (space >= 64) {		if ((skb = skb_dequeue(&lvcc->tx.backlog)) == NULL)			break;		n = aal5_size(skb->len);		if (n + 16 > space) {	/* Can only send part */			int m = aal5_spacefor(space - 16); /* Bytes to send */			vcc_tx_add_aal5_descriptor(lvcc,			    DESCRIPTOR_AAL5_STREAM, m);			lvcc->tx.pptr = skb->data + m;			pad = lvcc->tx.pptr - skb->tail;			if (pad < 0)				pad = 0;			vcc_tx_memcpy(lvcc, skb->data, m - pad);			vcc_tx_memzero(lvcc, pad);			lvcc->tx.inprogleft = n - m;			lvcc->tx.inprogress = skb;			goto end;		}		vcc_tx_add_aal5_descriptor(lvcc, 0, n);		pad = n - skb->len - 8;		vcc_tx_memcpy(lvcc, skb->data, skb->len);		vcc_tx_memzero(lvcc, pad);		lanai_free_skb(lvcc->tx.atmvcc, skb);		vcc_tx_add_aal5trailer(lvcc, skb->len, 0, 0);		space -= n + 16;		atomic_inc(&lvcc->tx.atmvcc->stats->tx);	}	if (skb_queue_empty(&lvcc->tx.backlog))		vcc_unmark_backlogged(lanai, lvcc);    end:	lanai_endtx(lanai, lvcc);}/* Given an skb that we want to transmit either send it now or queue */static void vcc_tx_aal5(struct lanai_dev *lanai, struct lanai_vcc *lvcc,	struct sk_buff *skb){	int space, n, pad;	if (vcc_is_backlogged(lvcc))		/* Already backlogged */		goto queue_it;	space = vcc_tx_space(lvcc, TXREADPTR_GET_PTR(cardvcc_read(lvcc,	    vcc_txreadptr)));	if (space < 64) {		vcc_mark_backlogged(lanai, lvcc);	/* No space */		goto queue_it;	}	if (space >= 16 + (n = aal5_size(skb->len))) {		/* We can send the whole thing now */		vcc_tx_add_aal5_descriptor(lvcc, 0, n);		pad = n - skb->len;		vcc_tx_memcpy(lvcc, skb->data, skb->len);		vcc_tx_memzero(lvcc, pad - 8);		vcc_tx_add_aal5trailer(lvcc, skb->len, 0, 0);		lanai_free_skb(lvcc->tx.atmvcc, skb);		atomic_inc(&lvcc->tx.atmvcc->stats->tx);	} else {	/* Space for only part of skb */		int bytes = aal5_spacefor(space - 16);	/* Bytes to send */		vcc_tx_add_aal5_descriptor(lvcc,			DESCRIPTOR_AAL5_STREAM, bytes);		pad = bytes - skb->len;		if (pad < 0)			pad = 0;		vcc_tx_memcpy(lvcc, skb->data, bytes - pad);		vcc_tx_memzero(lvcc, pad);		lvcc->tx.inprogress = skb;		lvcc->tx.inprogleft = n - bytes;		lvcc->tx.pptr = skb->data + bytes;		vcc_mark_backlogged(lanai, lvcc);	}	lanai_endtx(lanai, lvcc);	return;    queue_it:	skb_queue_tail(&lvcc->tx.backlog, skb);}static void vcc_tx_unqueue_aal0(struct lanai_dev *lanai,	struct lanai_vcc *lvcc, int endptr){	printk(KERN_INFO DEV_LABEL	    ": vcc_tx_unqueue_aal0: not implemented\n");}static void vcc_tx_aal0(struct lanai_dev *lanai, struct lanai_vcc *lvcc,	struct sk_buff *skb){	printk(KERN_INFO DEV_LABEL ": vcc_tx_aal0: not implemented\n");	/* Remember to increment lvcc->tx.atmvcc->stats->tx */	lanai_free_skb(lvcc->tx.atmvcc, skb);}/* Try to undequeue 1 backlogged vcc */static void iter_dequeue(struct lanai_dev *lanai, vci_t vci){	struct lanai_vcc *lvcc = lanai->vccs[vci];	int endptr;	if (lvcc == NULL || !vcc_is_backlogged(lvcc)) {		vci_bitfield_clear(&lanai->backlog_vccs, vci);		return;	}	endptr = TXREADPTR_GET_PTR(cardvcc_read(lvcc, vcc_txreadptr));	lvcc->tx.unqueue(lanai, lvcc, endptr);}/* Try a dequeue on all backlogged connections */static inline void vcc_tx_dequeue_all(struct lanai_dev *lanai){	unsigned long flags;	spin_lock_irqsave(&lanai->txlock, flags);	vci_bitfield_iterate(lanai, &lanai->backlog_vccs, iter_dequeue);	spin_unlock_irqrestore(&lanai->txlock, flags);}/* -------------------- VCC RX BUFFER UTILITIES: *//* unlike the _tx_ cousins, this doesn't update ptr */static inline void vcc_rx_memcpy(unsigned char *dest,	const struct lanai_vcc *lvcc, int n){	int m = ((const unsigned char *) lvcc->rx.buf.ptr) + n -	    ((const unsigned char *) (lvcc->rx.buf.end));	if (m < 0)		m = 0;	memcpy(dest, lvcc->rx.buf.ptr, n - m);	memcpy(dest + n - m, lvcc->rx.buf.start, m);}/* Receive AAL5 data on a VCC with a particular endptr */static void vcc_rx_aal5(struct lanai_vcc *lvcc, int endptr){	int size;	struct sk_buff *skb;	/*const*/ u32 *x, *end = &lvcc->rx.buf.start[endptr * 4];	int n = ((unsigned long) end) - ((unsigned long) lvcc->rx.buf.ptr);	if (n < 0)		n += lanai_buf_size(&lvcc->rx.buf);	APRINTK(n >= 0 && n < lanai_buf_size(&lvcc->rx.buf) && !(n & 15),	    "vcc_rx_aal5: n out of range (%d/%d)\n",	    n, lanai_buf_size(&lvcc->rx.buf));	/* Recover the second-to-last word to get true pdu length */	if ((x = &end[-2]) < lvcc->rx.buf.start)		x = &lvcc->rx.buf.end[-2];	size = be32_to_cpup(x) & 0xffff;	if (n != aal5_size(size)) {	/* Make sure size matches padding */		printk(KERN_INFO DEV_LABEL "(itf %d): Got bad AAL5 length "		    "on vci=%d - size=%d n=%d\n",		    lvcc->rx.atmvcc->dev->number, lvcc->vci, size, n);		lvcc->stats.x.aal5.rx_badlen++;		goto out;	}	skb = atm_alloc_charge(lvcc->rx.atmvcc, size, GFP_ATOMIC);	if (skb == NULL) {		lvcc->stats.rx_nomem++;		goto out;	}	skb_put(skb, size);	ATM_SKB(skb)->vcc = lvcc->rx.atmvcc;

⌨️ 快捷键说明

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