📄 ibmtr.c
字号:
/* ibmtr.c: A shared-memory IBM Token Ring 16/4 driver for linux * * Written 1993 by Mark Swanson and Peter De Schrijver. * This software may be used and distributed according to the terms * of the GNU Public License, incorporated herein by reference. * * This device driver should work with Any IBM Token Ring Card that does * not use DMA. * * I used Donald Becker's (becker@cesdis.gsfc.nasa.gov) device driver work * as a base for most of my initial work. * * Changes by Peter De Schrijver (Peter.Deschrijver@linux.cc.kuleuven.ac.be) : * * + changed name to ibmtr.c in anticipation of other tr boards. * + changed reset code and adapter open code. * + added SAP open code. * + a first attempt to write interrupt, transmit and receive routines. * * Changes by David W. Morris (dwm@shell.portal.com) : * 941003 dwm: - Restructure tok_probe for multiple adapters, devices. * + Add comments, misc reorg for clarity. * + Flatten interrupt handler levels. * * Changes by Farzad Farid (farzy@zen.via.ecp.fr) * and Pascal Andre (andre@chimay.via.ecp.fr) (March 9 1995) : * + multi ring support clean up. * + RFC1042 compliance enhanced. * * Changes by Pascal Andre (andre@chimay.via.ecp.fr) (September 7 1995) : * + bug correction in tr_tx * + removed redundant information display * + some code reworking * * Changes by Michel Lespinasse (walken@via.ecp.fr), * Yann Doussot (doussot@via.ecp.fr) and Pascal Andre (andre@via.ecp.fr) * (February 18, 1996) : * + modified shared memory and mmio access port the driver to * alpha platform (structure access -> readb/writeb) * * Changes by Steve Kipisz (bungy@ibm.net or kipisz@vnet.ibm.com) * (January 18 1996): * + swapped WWOR and WWCR in ibmtr.h * + moved some init code from tok_probe into trdev_init. The * PCMCIA code can call trdev_init to complete initializing * the driver. * + added -DPCMCIA to support PCMCIA * + detecting PCMCIA Card Removal in interrupt handler. If * ISRP is FF, then a PCMCIA card has been removed * * Changes by Paul Norton (pnorton@cts.com) : * + restructured the READ.LOG logic to prevent the transmit SRB * from being rudely overwritten before the transmit cycle is * complete. (August 15 1996) * + completed multiple adapter support. (November 20 1996) * + implemented csum_partial_copy in tr_rx and increased receive * buffer size and count. Minor fixes. (March 15, 1997) * * Changes by Christopher Turcksin <wabbit@rtfc.demon.co.uk> * + Now compiles ok as a module again. * * Changes by Paul Norton (pnorton@ieee.org) : * + moved the header manipulation code in tr_tx and tr_rx to * net/802/tr.c. (July 12 1997) * + add retry and timeout on open if cable disconnected. (May 5 1998) * + lifted 2000 byte mtu limit. now depends on shared-RAM size. * May 25 1998) * + can't allocate 2k recv buff at 8k shared-RAM. (20 October 1998) * * Changes by Joel Sloan (jjs@c-me.com) : * + disable verbose debug messages by default - to enable verbose * debugging, edit the IBMTR_DEBUG_MESSAGES define below * * Changes by Tim Hockin (thockin@isunix.it.ilstu.edu) : * + added spinlocks for SMP sanity (10 March 1999) *//* change the define of IBMTR_DEBUG_MESSAGES to a nonzero value in the event that chatty debug messages are desired - jjs 12/30/98 */#define IBMTR_DEBUG_MESSAGES 0#ifdef PCMCIA#define MODULE#endif#include <linux/module.h>#ifdef PCMCIA#undef MODULE#endif#define NO_AUTODETECT 1#undef NO_AUTODETECT#undef ENABLE_PAGING#define FALSE 0#define TRUE (!FALSE)/* changes the output format of driver initialisation */#define TR_NEWFORMAT 1#define TR_VERBOSE 0/* some 95 OS send many non UI frame; this allow removing the warning */#define TR_FILTERNONUI 1/* version and credits */static char *version ="ibmtr.c: v1.3.57 8/ 7/94 Peter De Schrijver and Mark Swanson\n"" v2.1.125 10/20/98 Paul Norton <pnorton@ieee.org>\n"" v2.2.0 12/30/98 Joel Sloan <jjs@c-me.com>\n";static char pcchannelid[] = { 0x05, 0x00, 0x04, 0x09, 0x04, 0x03, 0x04, 0x0f, 0x03, 0x06, 0x03, 0x01, 0x03, 0x01, 0x03, 0x00, 0x03, 0x09, 0x03, 0x09, 0x03, 0x00, 0x02, 0x00};static char mcchannelid[] = { 0x04, 0x0d, 0x04, 0x01, 0x05, 0x02, 0x05, 0x03, 0x03, 0x06, 0x03, 0x03, 0x05, 0x08, 0x03, 0x04, 0x03, 0x05, 0x03, 0x01, 0x03, 0x08, 0x02, 0x00};#include <linux/kernel.h>#include <linux/sched.h>#include <linux/errno.h>#include <linux/sched.h>#include <linux/timer.h>#include <linux/in.h>#include <linux/ioport.h>#include <linux/errno.h>#include <linux/string.h>#include <linux/skbuff.h>#include <linux/interrupt.h>#include <linux/delay.h>#include <linux/netdevice.h>#include <linux/trdevice.h>#include <linux/stddef.h>#include <linux/init.h>#include <net/checksum.h>#include <asm/io.h>#include <asm/spinlock.h>#include <asm/system.h>#include <asm/bitops.h>#include "ibmtr.h"#define DPRINTK(format, args...) printk("%s: " format, dev->name , ## args)#define DPRINTD(format, args...) DummyCall("%s: " format, dev->name , ## args)#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))#define MAX(X, Y) ((X) > (Y) ? (X) : (Y))#if TR_NEWFORMAT/* this allows displaying full adapter information */const char *channel_def[] __initdata = { "ISA", "MCA", "ISA P&P" };__initfunc(char *adapter_def(char type)){ switch (type) { case 0xF : return "PC Adapter | PC Adapter II | Adapter/A"; case 0xE : return "16/4 Adapter | 16/4 Adapter/A (long)"; case 0xD : return "16/4 Adapter/A (short) | 16/4 ISA-16 Adapter"; case 0xC : return "Auto 16/4 Adapter"; default : return "adapter (unknown type)"; };};#endif#if !TR_NEWFORMATunsigned char ibmtr_debug_trace=1; /* Patch or otherwise alter to control tokenring tracing. */#elseunsigned char ibmtr_debug_trace=0;#endif#define TRC_INIT 0x01 /* Trace initialization & PROBEs */#define TRC_INITV 0x02 /* verbose init trace points */int ibmtr_probe(struct device *dev);static int ibmtr_probe1(struct device *dev, int ioaddr);static unsigned char get_sram_size(struct tok_info *adapt_info);static int tok_init_card(struct device *dev);void tok_interrupt(int irq, void *dev_id, struct pt_regs *regs);static int trdev_init(struct device *dev);static void initial_tok_int(struct device *dev);static void open_sap(unsigned char type,struct device *dev);void tok_open_adapter(unsigned long dev_addr);static void tr_rx(struct device *dev);static void tr_tx(struct device *dev);static int tok_open(struct device *dev);static int tok_close(struct device *dev);static int tok_send_packet(struct sk_buff *skb, struct device *dev);static struct net_device_stats * tok_get_stats(struct device *dev);void ibmtr_readlog(struct device *dev);void ibmtr_reset_timer(struct timer_list *tmr, struct device *dev);int ibmtr_change_mtu(struct device *dev, int mtu);static unsigned int ibmtr_portlist[] __initdata = { 0xa20, 0xa24, 0};static __u32 ibmtr_mem_base = 0xd0000;__initfunc(static void PrtChanID(char *pcid, short stride) ){ short i, j; for (i=0, j=0; i<24; i++, j+=stride) printk("%1x", ((int) pcid[j]) & 0x0f); printk("\n");}__initfunc(static void HWPrtChanID (__u32 pcid, short stride)){ short i, j; for (i=0, j=0; i<24; i++, j+=stride) printk("%1x", ((int)readb(pcid + j)) & 0x0f); printk("\n");}/* * ibmtr_probe(): Routine specified in the network device structure * to probe for an IBM Token Ring Adapter. Routine outline: * I. Interrogate hardware to determine if an adapter exists * and what the speeds and feeds are * II. Setup data structures to control execution based upon * adapter characteristics. * III. Initialize adapter operation * * We expect ibmtr_probe to be called once for each device entry * which references it. */ __initfunc(int ibmtr_probe(struct device *dev)){ int i; int base_addr = dev ? dev->base_addr : 0; if (base_addr > 0x1ff) { /* * Check a single specified location. */ if (ibmtr_probe1(dev, base_addr)) {#ifndef MODULE tr_freedev(dev);#endif return -ENODEV; } else return 0; } else if (base_addr != 0) /* Don't probe at all. */ return -ENXIO; for (i = 0; ibmtr_portlist[i]; i++) { int ioaddr = ibmtr_portlist[i]; if (check_region(ioaddr, IBMTR_IO_EXTENT)) continue; if (ibmtr_probe1(dev, ioaddr)) {#ifndef MODULE tr_freedev(dev);#endif } else return 0; } return -ENODEV;}__initfunc(static int ibmtr_probe1(struct device *dev, int PIOaddr)){ unsigned char segment=0, intr=0, irq=0, i=0, j=0, cardpresent=NOTOK,temp=0; __u32 t_mmio=0; struct tok_info *ti=0; __u32 cd_chanid; unsigned char *tchanid, ctemp; unsigned long timeout;#ifndef MODULE dev = init_trdev(dev,0);#endif /* Query the adapter PIO base port which will return * indication of where MMIO was placed. We also have a * coded interrupt number. */ segment = inb(PIOaddr); /* * Out of range values so we'll assume non-existent IO device */ if (segment < 0x40 || segment > 0xe0) return -ENODEV; /* * Compute the linear base address of the MMIO area * as LINUX doesn't care about segments */ t_mmio=(((__u32)(segment & 0xfc) << 11) + 0x80000); intr = segment & 0x03; /* low bits is coded interrupt # */ if (ibmtr_debug_trace & TRC_INIT) DPRINTK("PIOaddr: %4hx seg/intr: %2x mmio base: %08X intr: %d\n", PIOaddr, (int)segment, t_mmio, (int)intr); /* * Now we will compare expected 'channelid' strings with * what we is there to learn of ISA/MCA or not TR card */ cd_chanid = (CHANNEL_ID + t_mmio); /* for efficiency */ tchanid=pcchannelid; cardpresent=TR_ISA; /* try ISA */ /* * Suboptimize knowing first byte different */ ctemp = readb(cd_chanid) & 0x0f; if (ctemp != *tchanid) { /* NOT ISA card, try MCA */ tchanid=mcchannelid; cardpresent=TR_MCA; if (ctemp != *tchanid) /* Neither ISA nor MCA */ cardpresent=NOTOK; } if (cardpresent != NOTOK) { /* * Know presumed type, try rest of ID */ for (i=2,j=1; i<=46; i=i+2,j++) { if ((readb(cd_chanid+i) & 0x0f) != tchanid[j]) { cardpresent=NOTOK; /* match failed, not TR card */ break; } } } /* * If we have an ISA board check for the ISA P&P version, * as it has different IRQ settings */ if (cardpresent == TR_ISA && (readb(AIPFID + t_mmio)==0x0e)) cardpresent=TR_ISAPNP; if (cardpresent == NOTOK) { /* "channel_id" did not match, report */ if (ibmtr_debug_trace & TRC_INIT) { DPRINTK("Channel ID string not found for PIOaddr: %4hx\n", PIOaddr); DPRINTK("Expected for ISA: "); PrtChanID(pcchannelid,1); DPRINTK(" found: "); HWPrtChanID(cd_chanid,2); DPRINTK("Expected for MCA: "); PrtChanID(mcchannelid,1); } return -ENODEV; } /* Now, allocate some of the pl0 buffers for this driver.. */ ti = (struct tok_info *)kmalloc(sizeof(struct tok_info), GFP_KERNEL); if (ti == NULL) return -ENOMEM; memset(ti, 0, sizeof(struct tok_info)); ti->mmio= t_mmio; ti->readlog_pending = 0; dev->priv = ti; /* this seems like the logical use of the field ... let's try some empirical tests using the token-info structure -- that should fit with out future hope of multiple adapter support as well /dwm */ switch (cardpresent) { case TR_ISA: if (intr==0) irq=9; /* irq2 really is irq9 */ if (intr==1) irq=3; if (intr==2) irq=6; if (intr==3) irq=7; ti->global_int_enable=GLOBAL_INT_ENABLE+((irq==9) ? 2 : irq); ti->adapter_int_enable=PIOaddr+ADAPTINTREL; ti->sram=0;#if !TR_NEWFORMAT DPRINTK("ti->global_int_enable: %04X\n",ti->global_int_enable);#endif break; case TR_MCA: if (intr==0) irq=9; if (intr==1) irq=3; if (intr==2) irq=10; if (intr==3) irq=11; ti->global_int_enable=0; ti->adapter_int_enable=0; ti->sram=((__u32)(inb(PIOaddr+ADAPTRESETREL) & 0xfe) << 12); break; case TR_ISAPNP: if (intr==0) irq=9; if (intr==1) irq=3; if (intr==2) irq=10; if (intr==3) irq=11; timeout = jiffies + TR_SPIN_INTERVAL; while(!readb(ti->mmio + ACA_OFFSET + ACA_RW + RRR_EVEN))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -