ray_cs.c
来自「LINUX 2.6.17.4的源码」· C语言 代码 · 共 1,911 行 · 第 1/5 页
C
1,911 行
ray_dev_t *local; DEBUG(1, "ray_detach(0x%p)\n", link); this_device = NULL; dev = link->priv; ray_release(link); local = (ray_dev_t *)dev->priv; del_timer(&local->timer); if (link->priv) { if (link->dev_node) unregister_netdev(dev); free_netdev(dev); } DEBUG(2,"ray_cs ray_detach ending\n");} /* ray_detach *//*============================================================================= ray_config() is run after a CARD_INSERTION event is received, to configure the PCMCIA socket, and to make the ethernet device available to the system.=============================================================================*/#define CS_CHECK(fn, ret) \do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)#define MAX_TUPLE_SIZE 128static int ray_config(struct pcmcia_device *link){ tuple_t tuple; cisparse_t parse; int last_fn = 0, last_ret = 0; int i; u_char buf[MAX_TUPLE_SIZE]; win_req_t req; memreq_t mem; struct net_device *dev = (struct net_device *)link->priv; ray_dev_t *local = (ray_dev_t *)dev->priv; DEBUG(1, "ray_config(0x%p)\n", link); /* This reads the card's CONFIG tuple to find its configuration regs */ tuple.DesiredTuple = CISTPL_CONFIG; CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); tuple.TupleData = buf; tuple.TupleDataMax = MAX_TUPLE_SIZE; tuple.TupleOffset = 0; CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; /* Determine card type and firmware version */ buf[0] = buf[MAX_TUPLE_SIZE - 1] = 0; tuple.DesiredTuple = CISTPL_VERS_1; CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); tuple.TupleData = buf; tuple.TupleDataMax = MAX_TUPLE_SIZE; tuple.TupleOffset = 2; CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); for (i=0; i<tuple.TupleDataLen - 4; i++) if (buf[i] == 0) buf[i] = ' '; printk(KERN_INFO "ray_cs Detected: %s\n",buf); /* Now allocate an interrupt line. Note that this does not actually assign a handler to the interrupt. */ CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); dev->irq = link->irq.AssignedIRQ; /* This actually configures the PCMCIA socket -- setting up the I/O windows and the interrupt mapping. */ CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));/*** Set up 32k window for shared memory (transmit and control) ************/ req.Attributes = WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_CM | WIN_ENABLE | WIN_USE_WAIT; req.Base = 0; req.Size = 0x8000; req.AccessSpeed = ray_mem_speed; CS_CHECK(RequestWindow, pcmcia_request_window(&link, &req, &link->win)); mem.CardOffset = 0x0000; mem.Page = 0; CS_CHECK(MapMemPage, pcmcia_map_mem_page(link->win, &mem)); local->sram = ioremap(req.Base,req.Size);/*** Set up 16k window for shared memory (receive buffer) ***************/ req.Attributes = WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_CM | WIN_ENABLE | WIN_USE_WAIT; req.Base = 0; req.Size = 0x4000; req.AccessSpeed = ray_mem_speed; CS_CHECK(RequestWindow, pcmcia_request_window(&link, &req, &local->rmem_handle)); mem.CardOffset = 0x8000; mem.Page = 0; CS_CHECK(MapMemPage, pcmcia_map_mem_page(local->rmem_handle, &mem)); local->rmem = ioremap(req.Base,req.Size);/*** Set up window for attribute memory ***********************************/ req.Attributes = WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_AM | WIN_ENABLE | WIN_USE_WAIT; req.Base = 0; req.Size = 0x1000; req.AccessSpeed = ray_mem_speed; CS_CHECK(RequestWindow, pcmcia_request_window(&link, &req, &local->amem_handle)); mem.CardOffset = 0x0000; mem.Page = 0; CS_CHECK(MapMemPage, pcmcia_map_mem_page(local->amem_handle, &mem)); local->amem = ioremap(req.Base,req.Size); DEBUG(3,"ray_config sram=%p\n",local->sram); DEBUG(3,"ray_config rmem=%p\n",local->rmem); DEBUG(3,"ray_config amem=%p\n",local->amem); if (ray_init(dev) < 0) { ray_release(link); return -ENODEV; } SET_NETDEV_DEV(dev, &handle_to_dev(link)); i = register_netdev(dev); if (i != 0) { printk("ray_config register_netdev() failed\n"); ray_release(link); return i; } strcpy(local->node.dev_name, dev->name); link->dev_node = &local->node; printk(KERN_INFO "%s: RayLink, irq %d, hw_addr ", dev->name, dev->irq); for (i = 0; i < 6; i++) printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n")); return 0;cs_failed: cs_error(link, last_fn, last_ret); ray_release(link); return -ENODEV;} /* ray_config */static inline struct ccs __iomem *ccs_base(ray_dev_t *dev){ return dev->sram + CCS_BASE;}static inline struct rcs __iomem *rcs_base(ray_dev_t *dev){ /* * This looks nonsensical, since there is a separate * RCS_BASE. But the difference between a "struct rcs" * and a "struct ccs" ends up being in the _index_ off * the base, so the base pointer is the same for both * ccs/rcs. */ return dev->sram + CCS_BASE;}/*===========================================================================*/static int ray_init(struct net_device *dev){ int i; UCHAR *p; struct ccs __iomem *pccs; ray_dev_t *local = (ray_dev_t *)dev->priv; struct pcmcia_device *link = local->finder; DEBUG(1, "ray_init(0x%p)\n", dev); if (!(pcmcia_dev_present(link))) { DEBUG(0,"ray_init - device not present\n"); return -1; } local->net_type = net_type; local->sta_type = TYPE_STA; /* Copy the startup results to local memory */ memcpy_fromio(&local->startup_res, local->sram + ECF_TO_HOST_BASE,\ sizeof(struct startup_res_6)); /* Check Power up test status and get mac address from card */ if (local->startup_res.startup_word != 0x80) { printk(KERN_INFO "ray_init ERROR card status = %2x\n", local->startup_res.startup_word); local->card_status = CARD_INIT_ERROR; return -1; } local->fw_ver = local->startup_res.firmware_version[0]; local->fw_bld = local->startup_res.firmware_version[1]; local->fw_var = local->startup_res.firmware_version[2]; DEBUG(1,"ray_init firmware version %d.%d \n",local->fw_ver, local->fw_bld); local->tib_length = 0x20; if ((local->fw_ver == 5) && (local->fw_bld >= 30)) local->tib_length = local->startup_res.tib_length; DEBUG(2,"ray_init tib_length = 0x%02x\n", local->tib_length); /* Initialize CCS's to buffer free state */ pccs = ccs_base(local); for (i=0; i<NUMBER_OF_CCS; i++) { writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status); } init_startup_params(local); /* copy mac address to startup parameters */ if (parse_addr(phy_addr, local->sparm.b4.a_mac_addr)) { p = local->sparm.b4.a_mac_addr; } else { memcpy(&local->sparm.b4.a_mac_addr, &local->startup_res.station_addr, ADDRLEN); p = local->sparm.b4.a_mac_addr; } clear_interrupt(local); /* Clear any interrupt from the card */ local->card_status = CARD_AWAITING_PARAM; DEBUG(2,"ray_init ending\n"); return 0;} /* ray_init *//*===========================================================================*//* Download startup parameters to the card and command it to read them */static int dl_startup_params(struct net_device *dev){ int ccsindex; ray_dev_t *local = (ray_dev_t *)dev->priv; struct ccs __iomem *pccs; struct pcmcia_device *link = local->finder; DEBUG(1,"dl_startup_params entered\n"); if (!(pcmcia_dev_present(link))) { DEBUG(2,"ray_cs dl_startup_params - device not present\n"); return -1; } /* Copy parameters to host to ECF area */ if (local->fw_ver == 0x55) memcpy_toio(local->sram + HOST_TO_ECF_BASE, &local->sparm.b4, sizeof(struct b4_startup_params)); else memcpy_toio(local->sram + HOST_TO_ECF_BASE, &local->sparm.b5, sizeof(struct b5_startup_params)); /* Fill in the CCS fields for the ECF */ if ((ccsindex = get_free_ccs(local)) < 0) return -1; local->dl_param_ccs = ccsindex; pccs = ccs_base(local) + ccsindex; writeb(CCS_DOWNLOAD_STARTUP_PARAMS, &pccs->cmd); DEBUG(2,"dl_startup_params start ccsindex = %d\n", local->dl_param_ccs); /* Interrupt the firmware to process the command */ if (interrupt_ecf(local, ccsindex)) { printk(KERN_INFO "ray dl_startup_params failed - " "ECF not ready for intr\n"); local->card_status = CARD_DL_PARAM_ERROR; writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status); return -2; } local->card_status = CARD_DL_PARAM; /* Start kernel timer to wait for dl startup to complete. */ local->timer.expires = jiffies + HZ/2; local->timer.data = (long)local; local->timer.function = &verify_dl_startup; add_timer(&local->timer); DEBUG(2,"ray_cs dl_startup_params started timer for verify_dl_startup\n"); return 0;} /* dl_startup_params *//*===========================================================================*/static void init_startup_params(ray_dev_t *local){ int i; if (country > JAPAN_TEST) country = USA; else if (country < USA) country = USA; /* structure for hop time and beacon period is defined here using * New 802.11D6.1 format. Card firmware is still using old format * until version 6. * Before After * a_hop_time ms byte a_hop_time ms byte * a_hop_time 2s byte a_hop_time ls byte * a_hop_time ls byte a_beacon_period ms byte * a_beacon_period a_beacon_period ls byte * * a_hop_time = uS a_hop_time = KuS * a_beacon_period = hops a_beacon_period = KuS */ /* 64ms = 010000 */ if (local->fw_ver == 0x55) { memcpy((UCHAR *)&local->sparm.b4, b4_default_startup_parms, sizeof(struct b4_startup_params)); /* Translate sane kus input values to old build 4/5 format */ /* i = hop time in uS truncated to 3 bytes */ i = (hop_dwell * 1024) & 0xffffff; local->sparm.b4.a_hop_time[0] = (i >> 16) & 0xff; local->sparm.b4.a_hop_time[1] = (i >> 8) & 0xff; local->sparm.b4.a_beacon_period[0] = 0; local->sparm.b4.a_beacon_period[1] = ((beacon_period/hop_dwell) - 1) & 0xff; local->sparm.b4.a_curr_country_code = country; local->sparm.b4.a_hop_pattern_length = hop_pattern_length[(int)country] - 1; if (bc) { local->sparm.b4.a_ack_timeout = 0x50; local->sparm.b4.a_sifs = 0x3f; } } else { /* Version 5 uses real kus values */ memcpy((UCHAR *)&local->sparm.b5, b5_default_startup_parms, sizeof(struct b5_startup_params)); local->sparm.b5.a_hop_time[0] = (hop_dwell >> 8) & 0xff; local->sparm.b5.a_hop_time[1] = hop_dwell & 0xff; local->sparm.b5.a_beacon_period[0] = (beacon_period >> 8) & 0xff; local->sparm.b5.a_beacon_period[1] = beacon_period & 0xff; if (psm) local->sparm.b5.a_power_mgt_state = 1; local->sparm.b5.a_curr_country_code = country; local->sparm.b5.a_hop_pattern_length = hop_pattern_length[(int)country]; } local->sparm.b4.a_network_type = net_type & 0x01; local->sparm.b4.a_acting_as_ap_status = TYPE_STA; if (essid != NULL) strncpy(local->sparm.b4.a_current_ess_id, essid, ESSID_SIZE);} /* init_startup_params */ /*===========================================================================*/static void verify_dl_startup(u_long data){ ray_dev_t *local = (ray_dev_t *)data; struct ccs __iomem *pccs = ccs_base(local) + local->dl_param_ccs; UCHAR status; struct pcmcia_device *link = local->finder; if (!(pcmcia_dev_present(link))) { DEBUG(2,"ray_cs verify_dl_startup - device not present\n"); return; }#ifdef PCMCIA_DEBUG if (pc_debug > 2) { int i; printk(KERN_DEBUG "verify_dl_startup parameters sent via ccs %d:\n", local->dl_param_ccs); for (i=0; i<sizeof(struct b5_startup_params); i++) { printk(" %2x", (unsigned int) readb(local->sram + HOST_TO_ECF_BASE + i)); } printk("\n"); }#endif status = readb(&pccs->buffer_status); if (status!= CCS_BUFFER_FREE) { printk(KERN_INFO "Download startup params failed. Status = %d\n", status); local->card_status = CARD_DL_PARAM_ERROR; return; } if (local->sparm.b4.a_network_type == ADHOC) start_net((u_long)local); else join_net((u_long)local); return;} /* end verify_dl_startup *//*===========================================================================*//* Command card to start a network */static void start_net(u_long data){ ray_dev_t *local = (ray_dev_t *)data; struct ccs __iomem *pccs; int ccsindex; struct pcmcia_device *link = local->finder; if (!(pcmcia_dev_present(link))) { DEBUG(2,"ray_cs start_net - device not present\n"); return; } /* Fill in the CCS fields for the ECF */ if ((ccsindex = get_free_ccs(local)) < 0) return; pccs = ccs_base(local) + ccsindex; writeb(CCS_START_NETWORK, &pccs->cmd); writeb(0, &pccs->var.start_network.update_param); /* Interrupt the firmware to process the command */ if (interrupt_ecf(local, ccsindex)) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?