/**************************************************************** * This driver can only be compiled as a module and it * can only be loaded ONCE per system. There is no * support yet for multiple cards with one driver. To * load more than one card, try creating multiple copies * of rlmod.o, naming the copies uniquely, and loading * one copy per card. * * This driver does not support probing. To change irq * or io port at runtime enter the following: * insmod rl2mod irq=x io=y * * *****************************************************************/ #include #include /* #include */ #include #include #include #include #include #include #include #include #include #include #include /* #include */ #include #include #include #include #include /* #include */ #include #include #include #include #include #include #include "proxim_lld.h" #include "proxim_ioctl.h" #include "proxim_cs.h" static const char *version = "proxim_cs.o: v1.4.2_POD, , Dave Koberstein\n"; #ifdef PCMCIA_DEBUG static int pc_debug = PCMCIA_DEBUG; MODULE_PARM(pc_debug, "i"); #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_NOTICE args); static char *version = "proxim_cs.c 1.40 1997/12/29 17:01:08 (nobody)"; #else #define DEBUG(n, args...) #endif static void proxim_config(dev_link_t *link); static void proxim_release(u_long arg); static int proxim_event(event_t event, int priority, event_callback_args_t *args); static void proxim_interrupt IRQ(int irq, void *dev_id, struct pt_regs *regs); static dev_link_t *proxim_attach(void); static void proxim_detach(dev_link_t *); /* Used to match up with cards */ static dev_info_t dev_info = "proxim_cs"; static dev_link_t *dev_list = NULL; typedef struct local_info_t { dev_node_t node; } local_info_t; /**************************************************************** * LLS Routines Required by the LLD * * *****************************************************************/ void LLSReceiveLookAhead (unsigned_8 *Buffer, unsigned_16 Length, unsigned_16 Status, unsigned_16 RSSI) { struct sk_buff *skb; printk(KERN_NOTICE "LLSReceiveLookAhead\n"); #if 0 int i; if(Buffer[0] != 0xff) { printk(KERN_NOTICE "%d to:",Length); for(i=0; i< 6;i++) printk(KERN_NOTICE "%2.2x",Buffer[i]); printk(KERN_NOTICE " from:"); for(i=0;i <6; i++) printk(KERN_NOTICE "%2.2x",Buffer[i + 6]); printk(KERN_NOTICE "\n"); } #endif /*allocate the skb*/ skb=alloc_skb(Length, GFP_ATOMIC); /*prepare a 1 item fragment list for LLD*/ rxDesc.LLDRxFragCount = 1; rxDesc.LLDRxFragList[0].FSDataLen = Length; rxDesc.LLDRxFragList[0].FSDataPtr = skb->data; /*retrieve whole packet from LLD*/ LLDReceive(&rxDesc,0,Length); skb->len = Length; /* NOTE: check if thisRangeLan is 0 or not */ skb->dev = thisRangeLan; skb->protocol=eth_type_trans(skb,thisRangeLan); stats.rx_packets++; /* tell linux we have a packet*/ netif_rx(skb); } unsigned_16 LLSSendComplete (struct LLDTxPacketDescriptor *PktDesc) { /* note the successful transmission*/ stats.tx_packets++; printk(KERN_NOTICE "LLSSendComplete\n"); #ifdef BUFFER /*send completed, free up the resources*/ outcount--; if(outcount < LLDMAXSEND) thisRangeLan->tbusy = 0; /* free the buffer we allocated in send routine */ kfree(PktDesc); #else /* free the SKB and let upper layer know we sent the packet */ dev_kfree_skb(saveptr, FREE_WRITE); thisRangeLan->tbusy = 0; #endif mark_bh(NET_BH); return SUCCESS; /* POD added */ } unsigned_8 LLSRegisterInterrupt (unsigned_8 IntNum, void (*CallBackFunc) ()) { int ret; dev_link_t *link = dev_list; modconf_t *mod; printk(KERN_NOTICE "LLSDRegisterInt: %d\n",IntNum); mod->Attributes = CONF_ENABLE_IRQ; ret = CardServices(ModifyConfiguration, link->handle, &mod); printk(KERN_NOTICE "ModifyConfig ret: %d\n",ret); #ifdef NOPE_ALREADY_DONE if(request_irq(IntNum, &rl2_interrupt, 0, "RangeLan2/ISA",thisRangeLan)) { return FAILURE; } #endif return SUCCESS; } unsigned_16 LLSGetCurrentTime (void) { return jiffies; } /**************************************************************** * These 3 LLS routines will never be called but are * included since the linker will expect them * * *****************************************************************/ void LLSRawReceiveLookAhead (unsigned_8 Buffer[], unsigned int Length) { printk(KERN_NOTICE "RawReceiveLA %d bytes", Length); } unsigned_16 LLSRawSendComplete (unsigned_8 *Buffer) { printk(KERN_NOTICE "RawSendComplete\n"); return SUCCESS; } unsigned_8 LLSDeRegisterInterrupt (unsigned_8 IntNum) { printk(KERN_NOTICE "LLSDDeRegisterInt\n"); return SUCCESS; } /**************************************************************** * Linux-required routines start here. These routines * will make use of the LLD routines in CLLD. * * *****************************************************************/ static int rl2_ioctl(struct device *dev, struct ifreq *rq, int cmd) { struct rl2_ioctl *ioc = (struct rl2_ioctl *) &rq->ifr_data; unsigned char tmp[128]; printk(KERN_NOTICE "rl2_ioctl %d\n",jiffies); switch(ioc->cmd) { case RL2NODETABLE: rl2_ioctl_printnodes(); break; case RL2INFO: rl2_ioctl_nodeinfo(); break; case RL2MASTEROPTS: memcpy_fromfs(tmp,ioc->data,sizeof(struct rl2_master_opts)); rl2_ioctl_setmaster(tmp); break; case RL2LISTAPS: RL2_Ioctl_Listaps(); break; case RL2ROAM: LLDRoam(); break; } return 0; } /**************************************************************** * polltime () * routine to yield some time to LLDPoll * * *****************************************************************/ void polltime(unsigned long d) { #if 0 static pollcnt=0; if(++pollcnt % 8 == 0) printk(KERN_NOTICE "timer %d \n",pollcnt); #endif printk(KERN_NOTICE "polltime %d\n",jiffies); if(poll_on) { LLDPoll(); init_timer(&poll_timer); poll_timer.function=polltime; poll_timer.expires=jiffies + POLL_FREQ; add_timer(&poll_timer); } } static int rl2_open(struct device *dev) { MOD_INC_USE_COUNT; if(LLDReset()) return -ENODEV; /*start the polling timer*/ poll_on = 1; init_timer(&poll_timer); poll_timer.expires=POLL_FREQ; poll_timer.function=polltime; add_timer(&poll_timer); return 0; } static int rl2_close(struct device *dev) { MOD_DEC_USE_COUNT; del_timer(&poll_timer); poll_on = 0; return 0; } #ifdef POD_NO_MORE static void rl2_interrupt(int irq, void *dev_id, struct pt_regs *regs) { if(thisRangeLan->interrupt) printk(KERN_NOTICE "RangeLan2: reentrant IRQ\n"); thisRangeLan->interrupt = 1; LLDIsr(); thisRangeLan->interrupt = 0; return; } #endif static int rl2_start_xmit(struct sk_buff *skb, struct device *dev) { int i; if(dev->tbusy) { /* LLD will restart itself so we'll ignore upper layer when it kicks us */ return 1; } if (skb == NULL ) { printk(KERN_NOTICE "RangeLan2: missed interrupt?\n"); dev_tint(dev); return 0; } if(skb->len <= 0 || dev == NULL) { printk(KERN_NOTICE "RangeLan2: null device\n"); return 0; } if(set_bit(0,(void *)&dev->tbusy) != 0) { printk(KERN_NOTICE "RangeLan2: Transmitter access conflict\n"); } if(skb->len < 60) { i = 60; } else i = skb->len; #ifdef BUFFER /*allocate a packet descriptor big enough for the packet*/ i+=sizeof(struct LLDTxPacketDescriptor)+4; txDesc = kmalloc(i,GFP_ATOMIC); /* copy our packet into the LLD structure */ memcpy(txDesc->LLDImmediateData, skb->data, skb->len); /*fill in the length for transmit decriptor*/ txDesc->LLDTxDataLength = skb->len; txDesc->LLDImmediateDataLength = skb->len; /*point frag list to our static structure that has 0 fragments*/ txFragList.LLDTxFragmentCount = 0; txDesc->LLDTxFragmentListPtr = &txFragList; /* give packet over to LLD for transmission */ i = LLDSend(txDesc); /* check for max buffering */ outcount++; if (outcount < LLDMAXSEND) dev->tbusy = 0; else if (outcount > LLDMAXSEND) printk(KERN_NOTICE "RangeLan2: Exceeded LLDMAXSEND: %d\n", outcount); #else /* save the skb for release in LLSSendComplete */ saveptr = skb; /*point frag list to our static structure that has 1 fragments*/ txFragList.LLDTxFragmentCount = 1; txDesc.LLDTxFragmentListPtr = &txFragList; txFragList.LLDTxFragList[0].FSDataPtr = skb->data; /*fill in the length for transmit decriptor*/ txFragList.LLDTxFragList[0].FSDataLen = i; txDesc.LLDTxDataLength = skb->len; txDesc.LLDImmediateDataLength = 0; i = LLDSend(&txDesc); #endif /* return codes aren't used properly by LLD but we'll check anyway*/ if(i==1) printk(KERN_NOTICE "RangeLan2: send delayed\n"); else if(i) { stats.tx_errors++; printk(KERN_NOTICE "RangeLan2: LLDsend transmit failure!!\n"); } #ifdef BUFFER /* free the SKB and let upper layer know we sent the packet */ dev_kfree_skb(skb, FREE_WRITE); #endif mark_bh(NET_BH); return 0; } static struct enet_statistics *rl2_get_stats(struct device *dev) { return &stats; } /****************************************************************/ /* Init Failure (reason) Codes for rl2_probe() */ /* 0 - Successful Initialization */ /* 1 - Error resetting the RFNC */ /* 2 - Error setting the interrupt vector */ /* 3 - Error sending the initialize command */ /* 4 - Error getting the ROM version */ /* 5 - Error getting the global address */ /* 6 - Error setting the local address */ /* 7 - Error setting the inactivity time out */ /* 8 - Error disabling hopping */ /* 9 - Error setting security ID */ /* 10 - Error sending configure MAC */ /* 11 - Error sending set roaming parameters command*/ /* 12 - Error sending multicast command */ /* 13 - Error in card and socket services */ /* 14 - Error configuring socket - improper card seating*/ /* 15 - Error configuring socket - power imporperly supplied*/ /* 16 - Error configuring socket - no PCMCIA bus ready signal*/ /****************************************************************/ extern unsigned_8 LLDInit365Flag; extern unsigned_8 LLDPCMCIA; extern unsigned_32 LLDMemoryAddress1; /* extern unsigned_16 LLDMemoryAddress1; */ extern unsigned_16 LLDMemorySize1; static unsigned_32 pcmcia_mem_adr = 0; /* 8K core dumps 16K give err 18 */ #define PROXIM_MEM_SIZE (16 * 1024) static int AddResources(void *a1,void *a2,void *a3,void *a4) { printk(KERN_NOTICE "PROXIM: AddResources %x %x %x %x\n", (unsigned_32)(a1), (unsigned_32)(a2), (unsigned_32)(a3), (unsigned_32)(a4) ); return(1); } static int CSSUnload(void) { printk(KERN_NOTICE "PROXIM: CSSUnload\n"); return 0; } static int DeRegisterClient(void) { printk(KERN_NOTICE "PROXIM: DeRegisterClient\n"); return SUCCESS; } /****------------------------------------------------------------------**** * * return 0 if ok * <0 on error ****------------------------------------------------------------------****/ static int rl2_probe(struct device *dev) { int inival,i; unsigned_32 flags; /* CLEAN */ printk(KERN_NOTICE "PROXIM: irq %d, io_base_addr %x mem_addr %x\n", dev->irq, dev->base_addr,pcmcia_mem_adr); if (dev->base_addr == 0) { printk(KERN_NOTICE "%s: RangeLan can't autoprobe\n",dev->name); return -ENODEV; } #ifdef NO_LONGER_NEEDED request_region(dev->base_addr, 6, "rl2lls"); #endif printk(KERN_NOTICE "PROXIM: after request_region???\n"); LLDIOAddress1 = dev->base_addr; LLDIntLine1 = dev->irq; LLDPCMCIA = 1; LLDInit365Flag = 0; if (pcmcia_mem_adr == 0) { printk(KERN_NOTICE "PROXIM: pcmcia_mem_adr is 0???\n"); } LLDMemoryAddress1 = pcmcia_mem_adr; LLDMemorySize1 = PROXIM_MEM_SIZE; /* POD TEST */ #ifdef NO_MORE for(i=0;i<6;i++) { /* dev->dev_addr[i] = LLDPhysAddress[i]; */ LLDPhysAddress[i] = dev->base_addr + i; printk(KERN_NOTICE " %2.2x", dev->dev_addr[i]); } printk(KERN_NOTICE ".\n"); #endif flags=PreserveFlag(); /* same as save_flags(flags); */ /* sti(); */ LLDRoamConfig(0); inival = LLDInit(); RestoreFlag(flags); /* same as restore_flags(flags); */ printk(KERN_NOTICE "RangeLAN val %d\n",inival); if (inival) { printk(KERN_NOTICE "%s: Can't init RangeLan, reason %d\n",dev->name,inival); /* this is done in deattach free_irq(dev->irq, dev); release_region(dev->base_addr, LLDIORange1); */ return -ENODEV; } printk(version); printk(KERN_NOTICE "rlmod.o: Original linux port, 2/96, by Paul "); printk(KERN_NOTICE "Chinn (loomer@1000klub.com).\n"); #ifdef BUFFER printk(KERN_NOTICE "%s: RangeLan2 (BUFF) %#3.3lx, IRQ %d, ROM %s, mac", #else printk(KERN_NOTICE "%s: RangeLan2 (NOBUFF) %#3.3lx, IRQ %d, ROM %s, mac", #endif dev->name, dev->base_addr, dev->irq, LLDROMVersion); for(i=0;i<6;i++) { dev->dev_addr[i] = LLDPhysAddress[i]; printk(KERN_NOTICE " %2.2x", dev->dev_addr[i]); } printk(KERN_NOTICE ".\n"); dev->open = &rl2_open; dev->hard_start_xmit = &rl2_start_xmit; dev->stop = &rl2_close; dev->get_stats = rl2_get_stats; dev->do_ioctl = rl2_ioctl; stats.rx_packets = stats.tx_packets = 0; ether_setup(dev); return 0; } /****------------------------------------------------------------------**** * ****------------------------------------------------------------------****/ static int proxim_init(device *dev) { printk(KERN_NOTICE "PROXIM: proxim_init\n"); /* CLEAN */ return(0); } /****------------------------------------------------------------------**** * ****------------------------------------------------------------------****/ int rl2_init() { printk(KERN_NOTICE "I don't wanna init\n"); return 1; } /* START OF ADDED CODE */ /****------------------------------------------------------------------**** * ****------------------------------------------------------------------****/ static void cs_error(client_handle_t handle, int func, int ret) { error_info_t err = { func, ret }; CardServices(ReportError, handle, &err); } /****------------------------------------------------------------------**** * proxim_attach() creates an "instance" of the driver, allocating * local data structures for one device. The device is registered * with Card Services. * * The dev_link structure is initialized, but we don't actually * configure the card at this point -- we wait until we receive a * card insertion event. * ****------------------------------------------------------------------****/ static dev_link_t *proxim_attach(void) { client_reg_t client_reg; /* Register with cardmgr */ dev_link_t *link; /* Info for cardmgr */ device *dev; /* */ net_local *lp; /* Proxim Specific Data */ int ret; DEBUG(0, "proxim_attach()\n"); printk(KERN_NOTICE "PROXIM Attach\n"); /* Initialize the dev_link_t structure */ link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); memset(link, 0, sizeof(struct dev_link_t)); link->release.function = &proxim_release; link->release.data = (u_long)link; /* The io structure describes IO port mapping */ link->io.BasePort1 = 0x0; link->io.NumPorts1 = 6; /* 6 */; /* QUESTION: is it with _8 or _16 or _AUTO ? */ link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; link->io.BasePort2 = 0; link->io.IOAddrLines = 3; /* Interrupt setup */ link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; link->irq.IRQInfo1 = 7; link->irq.IRQInfo2 = 0x0080; #ifdef TEST link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID; if( irq_list[0] == -1 ) link->irq.IRQInfo2 = irq_mask; else { int i; link->irq.IRQInfo2 = 0; for( i = 0; i < 4; i++) link->irq.IRQInfo2 |= 1 << irq_list[i]; } #endif link->irq.Handler = &proxim_interrupt; link->irq.Instance = (void *)link; /* CLEAN */ printk(KERN_NOTICE "AA: irq.attr %x\n",link->irq.Attributes); printk(KERN_NOTICE " irq.info2 %x, irq_mask %x\n", link->irq.IRQInfo2,irq_mask); /* General socket configuration */ /* QUEST: CONF_ENABLE_DMA */ link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.Vcc = 50; link->conf.IntType = INT_MEMORY_AND_IO; link->conf.ConfigIndex = 1; /* Which of these do we need */ link->conf.Present = PRESENT_OPTION | PRESENT_STATUS /* | PRESENT_PIN_REPLACE */ /* | PRESENT_COPY */ /* | PRESENT_EXT_STATUS */ ; /* Chain Drivers */ link->next = dev_list; dev_list = link; /* Allocate the generic data structure */ dev = kmalloc(sizeof(struct device), GFP_KERNEL); memset(dev, 0x00, sizeof(struct device)); link->priv = link->irq.Instance = dev; thisRangeLan = dev; /* Allocate the proxim specific data structure. */ dev->priv = lp = (net_local *) kmalloc(sizeof(net_local), GFP_KERNEL); memset(lp, 0x00, sizeof(net_local)); lp->configured = 0; lp->nresets = 0; /* Set the watchdog timer to avoi blocking */ /* NO lp->watchdog.function = proxim_watchdog; lp->watchdog.data = (unsigned long) dev; */ /* back link */ lp->link = link; lp->dev = dev; /* Standard setup for generic data */ ether_setup(dev); dev->name = "rl2lls"; dev->init = &proxim_init; dev->open = &rl2_open; dev->stop = &rl2_close; dev->tbusy = 1; dev->do_ioctl = rl2_ioctl; /* Register with Card Services */ client_reg.dev_info = &dev_info; client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; client_reg.EventMask = CS_EVENT_REGISTRATION_COMPLETE | CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; client_reg.event_handler = &proxim_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = CardServices(RegisterClient, &link->handle, &client_reg); if (ret != 0) { cs_error(link->handle, RegisterClient, ret); proxim_detach(link); return NULL; } return link; } /* proxim_attach */ /****------------------------------------------------------------------**** * This deletes a driver "instance". The device is de-registered * with Card Services. If it has been released, all local data * structures are freed. Otherwise, the structures will be freed * when the device is released. * ****------------------------------------------------------------------****/ static void proxim_detach(dev_link_t *link) { dev_link_t **linkp; DEBUG(0, "proxim_detach(0x%p)\n", link); printk(KERN_NOTICE "proxim_detach\n"); /* CLEAN */ /* Locate device structure */ for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) if (*linkp == link) break; if (*linkp == NULL) return; /* * If the device is currently configured and active, we won't * actually delete it yet. Instead, it is marked so that when * the release() function is called, that will trigger a proper * detach(). */ if (link->state & DEV_CONFIG) { #ifdef PCMCIA_DEBUG printk(KERN_NOTICE "proxim_cs: detach postponed, '%s' " "still locked\n", link->dev->dev_name); #endif link->state |= DEV_STALE_LINK; return; } /* Break the link with Card Services */ if (link->handle) CardServices(DeregisterClient, link->handle); /* Unlink device structure, free pieces */ *linkp = link->next; if (link->priv) { device *dev = (device *)link->priv; /* Paranoia is a Good Thing(tm) */ ((net_local *) dev->priv)->link = (dev_link_t *) NULL; ((net_local *) dev->priv)->dev = (device *) NULL; kfree_s(link->priv, sizeof(local_info_t)); } kfree_s(link, sizeof(struct dev_link_t)); } /* proxim_detach */ /****------------------------------------------------------------------**** * ****------------------------------------------------------------------****/ #define CS_CHECK(fn, args...) \ while ((last_ret=CardServices(last_fn=(fn),args))!=0) goto cs_failed /****------------------------------------------------------------------**** * proxim_config() is scheduled to run after a CARD_INSERTION event * is received, to configure the PCMCIA socket, and to make the * ethernet device available to the system. * ****------------------------------------------------------------------****/ static void proxim_config(dev_link_t *link) { client_handle_t handle; tuple_t tuple; cisparse_t parse; struct device *dev; int last_fn, last_ret, ret; u_char buf[64]; win_req_t req; /* */ memreq_t mem; handle = link->handle; dev = (device *)link->priv; DEBUG(0, "proxim_config(0x%p)\n", link); printk(KERN_NOTICE "proxim_config\n"); /* * This reads the card's CONFIG tuple to find its configuration * registers. */ tuple.Attributes = 0; tuple.DesiredTuple = CISTPL_CONFIG; CS_CHECK(GetFirstTuple, handle, &tuple); tuple.TupleData = buf; tuple.TupleDataMax = 64; tuple.TupleOffset = 0; CS_CHECK(GetTupleData, handle, &tuple); CS_CHECK(ParseTuple, handle, &tuple, &parse); link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; /* Configure card */ link->state |= DEV_CONFIG; #ifdef WHAT_THE /* Try allocating IO ports. This tries a few fixed addresses. If you want, you can also read the card's config table to pick addresses -- see the serial driver for an example. */ for (j = 0; j < 0x400; j += 0x20) { /* The '^0x300' is so that we probe 0x300-0x3ff first, then 0x200-0x2ff, and so on, because this seems safer */ link->io.BasePort1 = j^0x300; link->io.BasePort2 = link->io.BasePort1 + 0x10; i = CardServices(RequestIO, link->handle, &link->io); if (i == CS_SUCCESS) break; } if (i != CS_SUCCESS) { cs_error(link->handle, RequestIO, i); goto failed; } #endif /* * Allocate IO port */ CS_CHECK(RequestIO, link->handle, &link->io); printk(KERN_NOTICE "proxim: got io1 %x io2 %x\n", link->io.BasePort1, link->io.BasePort2); /* * Now allocate an interrupt line. Note that this does not * actually assign a handler to the interrupt. */ printk(KERN_NOTICE "BB: irq.attr %x\n",link->irq.Attributes); printk(KERN_NOTICE " irq.info2 %x\n",link->irq.IRQInfo2); CS_CHECK(RequestIRQ, link->handle, &link->irq); printk(KERN_NOTICE "proxim: got interrupt %d\n",link->irq.AssignedIRQ); /* * This actually configures the PCMCIA socket -- setting up * the I/O windows and the interrupt mapping. */ CS_CHECK(RequestConfiguration, link->handle, &link->conf); /* * Allocate a 4K memory window. Note that the dev_link_t * structure provides space for one window handle -- if your * device needs several windows, you'll need to keep track of * the handles in your private data structure, link->priv. */ /* req.Attributes = WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_AM | WIN_ENABLE; req.Attributes = WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_AM | WIN_ENABLE; req.Attributes = WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_CM | WIN_ENABLE; req.Attributes = WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_CM | WIN_ENABLE; */ req.Attributes = WIN_DATA_WIDTH_32 | WIN_MEMORY_TYPE_AM | WIN_ENABLE; req.Base = NULL; req.Size = PROXIM_MEM_SIZE; /* req.AccessSpeed = mem_speed; */ req.AccessSpeed = 12; link->win = (window_handle_t)link->handle; CS_CHECK(RequestWindow, &link->win, &req); #ifdef NOT_NEEDED mod.Attributes = WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_CM | WIN_ENABLE; CS_CHECK(ModifyWindow, link->win, &mod); #endif dev->rmem_start = dev->mem_start = (u_long)req.Base; dev->rmem_end = dev->mem_end = dev->mem_start + req.Size; dev->tbusy = 0; mem.CardOffset = 0; mem.Page = 0; CS_CHECK(MapMemPage, link->win, &mem); dev->irq = link->irq.AssignedIRQ; dev->base_addr = link->io.BasePort1; dev->tbusy = 0; pcmcia_mem_adr = (unsigned_32)req.Base; #if 0 LLDDomain = domain; LLDNodeType = type; #endif printk(KERN_NOTICE "proxim: got mem base %x\n",(unsigned_32)req.Base); /* Pass info to RangeLane library codec */ LLDPCMCIA = 1; LLDInit365Flag = 0; LLDIOAddress1 = dev->base_addr; LLDIntLine1 = dev->irq; LLDMemoryAddress1 = pcmcia_mem_adr; LLDMemorySize1 = PROXIM_MEM_SIZE; /* PODPOD wv_pcmcia_config(link) link->state &= ~DEV_CONFIG_PENDING;k wv_hw_config(dev) wv_init_info(dev) */ /* Reset PCMCIA Interface */ { int i; conf_reg_t reg = { 0, CS_READ, CISREG_COR, 0 }; i = CardServices(AccessConfigurationRegister, link->handle, ®); if (i != CS_SUCCESS) { cs_error(link->handle, AccessConfigurationRegister, i); goto failed; } printk(KERN_NOTICE "%s: proxim_pcmcia_reset(): Config reg is 0x%x\n", dev->name, (u_int) reg.Value); /* reg.Action = CS_WRITE; reg.Value = reg.Value | COR_SOFT_RESET; i = CardServices(AccessConfigurationRegister, link->handle, ®); if (i != CS_SUCCESS) { cs_error(link->handle, AccessConfigurationRegister, i); goto failed; } */ printk(KERN_NOTICE "proxim_cs: wrote COR with SW_RESET\n"); /* CLEAN */ reg.Action = CS_WRITE; reg.Value = COR_LEVEL_REQ | COR_FUNC_ENA; i = CardServices(AccessConfigurationRegister, link->handle, ®); if (i != CS_SUCCESS) { cs_error(link->handle, AccessConfigurationRegister, i); goto failed; } printk(KERN_NOTICE "proxim_cs: wrote COR with LEVEL_IRQ/CONFIG\n"); /* CLEAN */ reg.Action = CS_READ; i = CardServices(AccessConfigurationRegister, link->handle, ®); if (i != CS_SUCCESS) { cs_error(link->handle, AccessConfigurationRegister, i); goto failed; } printk(KERN_NOTICE "%s: proxim_pcmcia_reset(): Config reg is 0x%x\n", dev->name, (u_int) reg.Value); } if ( (ret = register_netdev(dev)) != 0) { printk(KERN_INFO "proxim_config(): register_netdev() failed %d\n",ret); goto failed; } printk(KERN_INFO "proxim_cs: register_netdev() success\n"); /** Init/Config RangeLAN 2 Card **/ if ( (ret = rl2_probe(dev)) != 0) { unregister_netdev(dev); printk(KERN_INFO "proxim_config(): rl2_probe() failed %d\n",ret); goto failed; } /* link->dev = &dev->node; */ /* why? don't know, I'm just hackin */ link->dev = &((net_local *) dev->priv)->node; link->state &= ~DEV_CONFIG_PENDING; printk(KERN_NOTICE "proxim device loaded\n"); /* CLEAN */ return; cs_failed: cs_error(link->handle, last_fn, last_ret); failed: proxim_release((u_long)link); return; } /* proxim_config */ /****------------------------------------------------------------------**** * After a card is removed, proxim_release() will unregister the net * device, and release the PCMCIA configuration. If the device is * still open, this will be postponed until it is closed. * ****------------------------------------------------------------------****/ static void proxim_release(u_long arg) { dev_link_t *link = (dev_link_t *)arg; struct device *dev = (struct device *)link->priv; DEBUG(0, "proxim_release(0x%p)\n", link); printk(KERN_NOTICE "proxim_release\n"); /* * If the device is currently in use, we won't release until it * is actually closed. */ /* NOTE: dev->open should link->open++ * dev->close should link->open-- * */ #ifdef NOT_NOW if (link->open) { DEBUG(1, "proxim_cs: release postponed, '%s' still open\n", link->dev->dev_name); link->state |= DEV_STALE_CONFIG; return; } #endif #if 0 if (MOD_IN_USE) printk(KERN_NOTICE "rl2: device busy, remove delayed\n"); else #endif del_timer(&poll_timer); LLDStop(); unregister_netdev(dev); /* Unlink the device chain */ /* wv if (link->dev != NULL) unregister_netdev(dev); */ link->dev = NULL; /* Don't bother checking to see if these succeed or not */ CardServices(ReleaseWindow, link->win); CardServices(ReleaseConfiguration, link->handle); CardServices(ReleaseIO, link->handle, &link->io); CardServices(ReleaseIRQ, link->handle, &link->irq); link->state &= ~DEV_CONFIG; /* No long necessary free_irq(dev.irq, &dev); release_region(dev.base_addr, LLDIORange1); */ if (link->state & DEV_STALE_LINK) proxim_detach(link); } /* proxim_release */ /****------------------------------------------------------------------**** * The card status event handler. Mostly, this schedules other * stuff to run after an event is received. A CARD_REMOVAL event * also sets some flags to discourage the net drivers from trying * to talk to the card any more. * * When a CARD_REMOVAL event is received, we immediately set a flag * to block future accesses to this device. All the functions that * actually access the device should check this flag to make sure * the card is still present. * ****------------------------------------------------------------------****/ static int proxim_event(event_t event, int priority, event_callback_args_t *args) { dev_link_t *link = (dev_link_t *)args->client_data; /* device *dev = (device *)link->priv; */ DEBUG(1, "proxim_event(0x%06x)\n", event); printk(KERN_NOTICE "Proxim: Event\n"); switch (event) { case CS_EVENT_REGISTRATION_COMPLETE: #ifdef DEBUG_PCMCIA_INFO printk(KERN_NOTICE "proxim_cs: registration complete\n"); #endif break; case CS_EVENT_CARD_REMOVAL: printk(KERN_NOTICE "Proxim: Card Removal\n"); link->state &= ~DEV_PRESENT; if (link->state & DEV_CONFIG) { link->release.expires = RUN_AT(HZ/20); add_timer(&link->release); } break; case CS_EVENT_CARD_INSERTION: printk(KERN_NOTICE "Proxim: Card Insertion\n"); link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; proxim_config(link); break; case CS_EVENT_PM_SUSPEND: printk(KERN_NOTICE "Proxim: Card Suspend\n"); /* QUESTION: what to do here?? */ link->state |= DEV_SUSPEND; /* Fall through... */ case CS_EVENT_RESET_PHYSICAL: printk(KERN_NOTICE "Proxim: Card Reset\n"); if (link->state & DEV_CONFIG) { /* QUESTION do anything here?? */ CardServices(ReleaseConfiguration, link->handle); } break; case CS_EVENT_PM_RESUME: printk(KERN_NOTICE "Proxim: Card Resume\n"); link->state &= ~DEV_SUSPEND; /* Fall through... */ case CS_EVENT_CARD_RESET: printk(KERN_NOTICE "Proxim: Card Reset\n"); if (link->state & DEV_CONFIG) { CardServices(RequestConfiguration, link->handle, &link->conf); /* QUESTION: reset card here?? */ } break; } return 0; } /* proxim_event */ /****------------------------------------------------------------------**** * ****------------------------------------------------------------------****/ static void proxim_interrupt IRQ(int irq, void *dev_id, struct pt_regs *regs) { printk(KERN_NOTICE "proxim_cs: interrupt\n"); if(thisRangeLan->interrupt) printk(KERN_NOTICE "RangeLan2: reentrant IRQ\n"); thisRangeLan->interrupt = 1; LLDIsr(); thisRangeLan->interrupt = 0; return; } /* proxim_interrupt */ /****------------------------------------------------------------------**** * ****------------------------------------------------------------------****/ int init_module(void) { servinfo_t serv; #ifdef DEBUG_MODULE_TRACE printk(KERN_NOTICE "-> init_proxim_cs()\n"); printk(KERN_NOTICE "%s", version); #endif memset(&serv, 0, sizeof(servinfo_t)); printk(KERN_NOTICE "Proxim init module: size %d val %08x\n",sizeof(servinfo_t),(unsigned int)&serv); CardServices(GetCardServicesInfo, (void *)(&serv) ); printk(KERN_NOTICE "Proxim init module: CS revision %x\n",serv.Revision); printk(KERN_NOTICE "Proxim init module: CS count %x\n",serv.Count); printk(KERN_NOTICE "Proxim init module: CS level %x\n",serv.CSLevel); printk(KERN_NOTICE "Proxim init module: CS vendor %s\n",serv.VendorString); if (serv.Revision != CS_RELEASE_CODE) { printk(KERN_NOTICE "proxim: Card Services release %x %x" "does not match!\n",serv.Revision,CS_RELEASE_CODE); return -1; } register_pcmcia_driver(&dev_info, &proxim_attach, &proxim_detach); return 0; } /****------------------------------------------------------------------**** * ****------------------------------------------------------------------****/ extern void cleanup_module(void) { DEBUG(0, "proxim_cs: unloading\n"); printk(KERN_NOTICE "proxim_cs: unloading\n"); unregister_pcmcia_driver(&dev_info); while (dev_list != NULL) { if (dev_list->state & DEV_CONFIG) proxim_release((u_long)dev_list); proxim_detach(dev_list); } }