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

📄 pt.c

📁 powerpc内核mpc8241linux系统下net驱动程序
💻 C
📖 第 1 页 / 共 4 页
字号:
#undef PT_DEBUG 1/* * pt.c: Linux device driver for the Gracilis PackeTwin. * Copyright (c) 1995 Craig Small VK2XLZ (vk2xlz@vk2xlz.ampr.org.) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 675 Mass Ave, Cambridge MA 02139, USA. * * This driver is largely based upon the PI driver by David Perry. * * Revision History * 23/02/95 cs  Started again on driver, last one scrapped * 27/02/95 cs  Program works, we have chan A only.  Tx stays on * 28/02/95 cs  Fix Tx problem (& TxUIE instead of | ) *		Fix Chan B Tx timer problem, used TMR2 instead of TMR1 * 03/03/95 cs  Painfully found out (after 3 days) SERIAL_CFG is write only *              created image of it and DMA_CFG * 21/06/95 cs  Upgraded to suit PI driver 0.8 ALPHA * 22/08/95 cs	Changed it all around to make it like pi driver * 23/08/95 cs  It now works, got caught again by TMR2 and we must have *				auto-enables for daughter boards. * 07/10/95 cs  Fixed for 1.3.30 (hopefully) * 26/11/95 cs  Fixed for 1.3.43, ala 29/10 for pi2.c by ac * 21/12/95 cs  Got rid of those nasty warnings when compiling, for 1.3.48 * 08/08/96 jsn Convert to use as a module. Removed send_kiss, empty_scc and *		pt_loopback functions - they were unused. * 13/12/96 jsn Fixed to match Linux networking changes. *//* * default configuration of the PackeTwin, * ie What Craig uses his PT for. */#define PT_DMA 3#define DEF_A_SPEED	4800		/* 4800 baud */#define DEF_A_TXDELAY	350		/* 350 mS */#define DEF_A_PERSIST	64		/* 25% persistence */#define DEF_A_SLOTIME	10		/* 10 mS */#define DEF_A_SQUELDELAY 30		/* 30 mS */#define DEF_A_CLOCKMODE	0		/* Normal clock mode */#define DEF_A_NRZI		1		/* NRZI mode */#define DEF_B_SPEED	0		/* 0 means external clock */#define DEF_B_TXDELAY	250		/* 250 mS */#define DEF_B_PERSIST	64		/* 25% */#define DEF_B_SLOTIME	10		/* 10 mS */#define DEF_B_SQUELDELAY 30		/* 30 mS */#define DEF_B_CLOCKMODE 0 		/* Normal clock mode ?!? */#define DEF_B_NRZI		1		/* NRZI mode */#define	PARAM_TXDELAY	1#define	PARAM_PERSIST	2#define	PARAM_SLOTTIME	3#define	PARAM_FULLDUP	5#define	PARAM_HARDWARE	6#define	PARAM_RETURN	255#include <linux/config.h>#include <linux/kernel.h>#include <linux/module.h>#include <linux/sched.h>#include <linux/types.h>#include <linux/fcntl.h>#include <linux/interrupt.h>#include <linux/ptrace.h>#include <linux/ioport.h>#include <linux/in.h>#include <linux/malloc.h>#include <linux/string.h>#include <linux/errno.h>#include <asm/system.h>#include <asm/bitops.h>#include <asm/io.h>#include <asm/dma.h>#include <asm/uaccess.h>#include <linux/inet.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/skbuff.h>#include <linux/timer.h>#include <linux/if_arp.h>#include <linux/pt.h>#include <linux/init.h>#include "z8530.h"#include <net/ax25.h>struct mbuf {    struct mbuf *next;    int cnt;    char data[0];};/* * The actual PT devices we will use */static int pt0_preprobe(struct device *dev) {return 0;} /* Dummy probe function */static struct device pt0a = { "pt0a", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, pt0_preprobe };static struct device pt0b = { "pt0b", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, pt0_preprobe };/* Ok, they shouldn't be here, but both channels share them *//* The Images of the Serial and DMA config registers */static unsigned char pt_sercfg = 0;static unsigned char pt_dmacfg = 0;/* The number of IO ports used by the card */#define PT_TOTAL_SIZE   16/* Index to functions, as function prototypes. */static int pt_probe(struct device *dev);static int pt_open(struct device *dev);static int pt_send_packet(struct sk_buff *skb, struct device *dev);static void pt_interrupt(int irq, void *dev_id, struct pt_regs *regs);static int pt_close(struct device *dev);static int pt_ioctl(struct device *dev, struct ifreq *ifr, int cmd);static struct net_device_stats *pt_get_stats(struct device *dev);static void pt_rts(struct pt_local *lp, int x);static void pt_rxisr(struct device *dev);static void pt_txisr(struct pt_local *lp);static void pt_exisr(struct pt_local *lp);static void pt_tmrisr(struct pt_local *lp);static char *get_dma_buffer(unsigned long *mem_ptr);static int valid_dma_page(unsigned long addr, unsigned long dev_buffsize);static int hw_probe(int ioaddr);static void tdelay(struct pt_local *lp, int time);static void chipset_init(struct device *dev);static char ax25_bcast[7] ={'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, '0' << 1};static char ax25_test[7] ={'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1, '1' << 1};static int ext2_secrm_seed = 152;static inline unsigned char random(void){    return (unsigned char) (ext2_secrm_seed = ext2_secrm_seed * 60691 + 1);}static inline void wrtscc(int cbase, int ctl, int sccreg, unsigned char val){    outb_p(sccreg, ctl);        /* Select register */    outb_p(val, ctl);           /* Output value */}static inline unsigned char rdscc(int cbase, int ctl, int sccreg){    unsigned char retval;    outb_p(sccreg, ctl);        /* Select register */    retval = inb_p(ctl);    return retval;}static void switchbuffers(struct pt_local *lp){    if (lp->rcvbuf == lp->rxdmabuf1)	lp->rcvbuf = lp->rxdmabuf2;    else	lp->rcvbuf = lp->rxdmabuf1;}static void hardware_send_packet(struct pt_local *lp, struct sk_buff *skb){	char kickflag;	unsigned long flags;	char *ptr;	struct device *dev;	/* First, let's see if this packet is actually a KISS packet */	ptr = skb->data;	if (ptr[0] != 0 && skb->len >= 2)	{#ifdef PT_DEBUG		printk(KERN_DEBUG "PT: Rx KISS... Control = %d, value = %d.\n", ptr[0], (skb->len > 1? ptr[1] : -1));#endif		/* Kludge to get device */		if ((struct pt_local*)(&pt0b.priv) == lp)			dev = &pt0b;		else			dev = &pt0a;		switch(ptr[0])		{			case PARAM_TXDELAY:				/*TxDelay is in 10mS increments */				lp->txdelay = ptr[1] * 10;				break;			case PARAM_PERSIST:				lp->persist = ptr[1];				break;			case PARAM_SLOTTIME:				lp->slotime = ptr[1];				break;			case PARAM_FULLDUP:				/* Yeah right, you wish!  Fullduplex is a little while to				 * go folks, but this is how you fire it up				 */				break;			/* Perhaps we should have txtail here?? */		} /*switch */		return;	}	lp->stats.tx_packets++;	lp->stats.tx_bytes+=skb->len;	save_flags(flags);	cli();	kickflag = (skb_peek(&lp->sndq) == NULL) && (lp->sndbuf == NULL);	restore_flags(flags);#ifdef PT_DEBUG	printk(KERN_DEBUG "PT: hardware_send_packet(): kickflag = %d (%d).\n", kickflag, lp->base & CHANA);#endif	skb_queue_tail(&lp->sndq, skb);	if (kickflag) 	{        /* Simulate interrupt to transmit */        	if (lp->dmachan)			pt_txisr(lp);		else 		{            		save_flags(flags);	           	cli();            		if (lp->tstate == IDLE)                		pt_txisr(lp);            		restore_flags(flags);		}	}} /* hardware_send_packet() */static void setup_rx_dma(struct pt_local *lp){	unsigned long flags;	int cmd;	unsigned long dma_abs;	unsigned char dmachan;	save_flags(flags);	cli();	dma_abs = (unsigned long) (lp->rcvbuf->data);	dmachan = lp->dmachan;	cmd = lp->base + CTL;	if(!valid_dma_page(dma_abs, DMA_BUFF_SIZE + sizeof(struct mbuf)))		panic("PI: RX buffer violates DMA boundary!");	/* Get ready for RX DMA */	wrtscc(lp->cardbase, cmd, R1, WT_FN_RDYFN | WT_RDY_RT | INT_ERR_Rx | EXT_INT_ENAB);	disable_dma(dmachan);	clear_dma_ff(dmachan);	/*	 *	Set DMA mode register to single transfers, incrementing address,	 *	auto init, writes	 */	set_dma_mode(dmachan, DMA_MODE_READ | 0x10);	set_dma_addr(dmachan, dma_abs);	set_dma_count(dmachan, lp->bufsiz);	enable_dma(dmachan);	/*	 *	If a packet is already coming in, this line is supposed to	 *	avoid receiving a partial packet.	 */	wrtscc(lp->cardbase, cmd, R0, RES_Rx_CRC);	/* Enable RX dma */	wrtscc(lp->cardbase, cmd, R1,		WT_RDY_ENAB | WT_FN_RDYFN | WT_RDY_RT | INT_ERR_Rx | EXT_INT_ENAB);	restore_flags(flags);}static void setup_tx_dma(struct pt_local *lp, int length){    unsigned long dma_abs;    unsigned long flags;    unsigned long dmachan;    save_flags(flags);    cli();    dmachan = lp->dmachan;    dma_abs = (unsigned long) (lp->txdmabuf);    if(!valid_dma_page(dma_abs, DMA_BUFF_SIZE + sizeof(struct mbuf)))	panic("PT: TX buffer violates DMA boundary!");    disable_dma(dmachan);    /* Set DMA mode register to single transfers, incrementing address,     *  no auto init, reads     */    set_dma_mode(dmachan, DMA_MODE_WRITE);    clear_dma_ff(dmachan);    set_dma_addr(dmachan, dma_abs);    /* output byte count */    set_dma_count(dmachan, length);    restore_flags(flags);}/* * This sets up all the registers in the SCC for the given channel * based upon tsync_hwint() */static void scc_init(struct device *dev){	unsigned long flags;	struct pt_local *lp = (struct pt_local*) dev->priv;	register int cmd = lp->base + CTL;	int tc, br;#ifdef PT_DEBUG	printk(KERN_DEBUG "PT: scc_init(): (%d).\n", lp->base & CHANA);#endif	save_flags(flags);	cli();	/* We may put something here to enable_escc */	if (cmd & CHANA)	{	        wrtscc(lp->cardbase, cmd, R9, CHRA);	/* Reset channel A */	        wrtscc(lp->cardbase, cmd, R2, 0xff);	/* Initialise interrupt vector */	}	else	    	wrtscc(lp->cardbase, cmd, R9, CHRB);	/* Reset channel B */	/* Deselect all Rx and Tx interrupts */	wrtscc(lp->cardbase, cmd, R1, 0);	/* Turn off external interrupts (like CTS/CD) */	wrtscc(lp->cardbase, cmd, R15, 0);	/* X1 clock, SDLC mode */	wrtscc(lp->cardbase, cmd, R4, SDLC | X1CLK);	/* Preset CRC and set mode */	if (lp->nrzi)	    	/* Preset Tx CRC, put into NRZI mode */		wrtscc(lp->cardbase, cmd, R10, CRCPS | NRZI);	else		/* Preset Tx CRC, put into NRZ mode */		wrtscc(lp->cardbase, cmd, R10, CRCPS);	/* Tx/Rx parameters */	if (lp->speed)		/* Use internal clocking */	       /* Tx Clk from BRG. Rx Clk form DPLL, TRxC pin outputs DPLL */	       wrtscc(lp->cardbase, cmd, R11, TCBR | RCDPLL | TRxCDP | TRxCOI);	else	/* Use external clocking */	{		/* Tx Clk from TRxCL. Rx Clk from RTxCL, TRxC pin if input */		wrtscc(lp->cardbase, cmd, R11, TCTRxCP | RCRTxCP | TRxCBR);        	wrtscc(lp->cardbase,cmd, R14, 0);	/* wiz1 */	}	/* Null out SDLC start address */	wrtscc(lp->cardbase, cmd, R6, 0);	/* SDLC flag */	wrtscc(lp->cardbase, cmd, R7, FLAG);	/* Setup Tx but don't enable it */	wrtscc(lp->cardbase, cmd, R5, Tx8 | DTR);	/* Setup Rx */	wrtscc(lp->cardbase, cmd, R3, AUTO_ENAB | Rx8);	/* Setup the BRG, turn it off first */	wrtscc(lp->cardbase, cmd, R14, BRSRC);	/* set the 32x time constant for the BRG in Rx mode */	if (lp->speed)	{		br = lp->speed;		tc = ((lp->xtal / 32) / (br * 2)) - 2;		wrtscc(lp->cardbase, cmd, R12, tc & 0xff);		/* lower byte */   		wrtscc(lp->cardbase, cmd, R13, (tc >> 8) & 0xff);	/* upper byte */	}	/* Turn transmitter off, to setup stuff */   	pt_rts(lp, OFF);	/* External clocking */	if (lp->speed)	{		/* DPLL frm BRG, BRG src PCLK */		wrtscc(lp->cardbase, cmd, R14, BRSRC | SSBR);		wrtscc(lp->cardbase, cmd, R14, BRSRC | SEARCH);	/* SEARCH mode, keep BRG src */		wrtscc(lp->cardbase, cmd, R14, BRSRC | BRENABL);	/* Enable the BRG */	    /* Turn off external clock port */		if (lp->base & CHANA)			outb_p( (pt_sercfg &= ~PT_EXTCLKA), (lp->cardbase + SERIAL_CFG) );		else			outb_p( (pt_sercfg &= ~PT_EXTCLKB), (lp->cardbase + SERIAL_CFG) );	}	else	{		/* DPLL frm rtxc,BRG src PCLK */		/* Turn on external clock port */		if (lp->base & CHANA)			outb_p( (pt_sercfg |= PT_EXTCLKA), (lp->cardbase + SERIAL_CFG) );		else			outb_p( (pt_sercfg |= PT_EXTCLKB), (lp->cardbase + SERIAL_CFG) );	}	if (!lp->dmachan)		wrtscc(lp->cardbase, cmd, R1, (INT_ALL_Rx | EXT_INT_ENAB));	wrtscc(lp->cardbase, cmd, R15, BRKIE);	/* ABORT int */	/* Turn on the DTR to tell modem we're alive */	if (lp->base & CHANA)		outb_p( (pt_sercfg |= PT_DTRA_ON), (lp->cardbase + SERIAL_CFG) );	else	    	outb_p( (pt_sercfg |= PT_DTRB_ON), (lp->cardbase + SERIAL_CFG) );	/* Now, turn on the receiver and hunt for a flag */	wrtscc(lp->cardbase, cmd, R3, RxENABLE | RxCRC_ENAB | AUTO_ENAB | Rx8 );	restore_flags(flags);} /* scc_init() *//* Resets the given channel and whole SCC if both channels off */

⌨️ 快捷键说明

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