📄 ray_cs.c
字号:
} /* 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; dev_link_t *link = local->finder; if (!(link->state & DEV_PRESENT)) { 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; dev_link_t *link = local->finder; if (!(link->state & DEV_PRESENT)) { 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)) { DEBUG(1,"ray start net failed - card not ready for intr\n"); writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status); return; } local->card_status = CARD_DOING_ACQ; return;} /* end start_net *//*===========================================================================*//* Command card to join a network */static void join_net(u_long data){ ray_dev_t *local = (ray_dev_t *)data; struct ccs __iomem *pccs; int ccsindex; dev_link_t *link = local->finder; if (!(link->state & DEV_PRESENT)) { DEBUG(2,"ray_cs join_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_JOIN_NETWORK, &pccs->cmd); writeb(0, &pccs->var.join_network.update_param); writeb(0, &pccs->var.join_network.net_initiated); /* Interrupt the firmware to process the command */ if (interrupt_ecf(local, ccsindex)) { DEBUG(1,"ray join net failed - card not ready for intr\n"); writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status); return; } local->card_status = CARD_DOING_ACQ; return;}/*============================================================================ After a card is removed, ray_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 ray_release(dev_link_t *link){ struct net_device *dev = link->priv; ray_dev_t *local = dev->priv; int i; DEBUG(1, "ray_release(0x%p)\n", link); del_timer(&local->timer); link->state &= ~DEV_CONFIG; iounmap(local->sram); iounmap(local->rmem); iounmap(local->amem); /* Do bother checking to see if these succeed or not */ i = pcmcia_release_window(link->win); if ( i != CS_SUCCESS ) DEBUG(0,"ReleaseWindow(link->win) ret = %x\n",i); i = pcmcia_release_window(local->amem_handle); if ( i != CS_SUCCESS ) DEBUG(0,"ReleaseWindow(local->amem) ret = %x\n",i); i = pcmcia_release_window(local->rmem_handle); if ( i != CS_SUCCESS ) DEBUG(0,"ReleaseWindow(local->rmem) ret = %x\n",i); i = pcmcia_release_configuration(link->handle); if ( i != CS_SUCCESS ) DEBUG(0,"ReleaseConfiguration ret = %x\n",i); i = pcmcia_release_irq(link->handle, &link->irq); if ( i != CS_SUCCESS ) DEBUG(0,"ReleaseIRQ ret = %x\n",i); DEBUG(2,"ray_release ending\n");}/*============================================================================= 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 ray_event(event_t event, int priority, event_callback_args_t *args){ dev_link_t *link = args->client_data; struct net_device *dev = link->priv; ray_dev_t *local = (ray_dev_t *)dev->priv; DEBUG(1, "ray_event(0x%06x)\n", event); switch (event) { case CS_EVENT_CARD_REMOVAL: link->state &= ~DEV_PRESENT; netif_device_detach(dev); if (link->state & DEV_CONFIG) { ray_release(link); del_timer(&local->timer); } break; case CS_EVENT_CARD_INSERTION: link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; ray_config(link); break; case CS_EVENT_PM_SUSPEND: link->state |= DEV_SUSPEND; /* Fall through... */ case CS_EVENT_RESET_PHYSICAL: if (link->state & DEV_CONFIG) { if (link->open) netif_device_detach(dev); pcmcia_release_configuration(link->handle); } break; case CS_EVENT_PM_RESUME: link->state &= ~DEV_SUSPEND; /* Fall through... */ case CS_EVENT_CARD_RESET: if (link->state & DEV_CONFIG) { pcmcia_request_configuration(link->handle, &link->conf); if (link->open) { ray_reset(dev); netif_device_attach(dev); } } break; } return 0; DEBUG(2,"ray_event ending\n");} /* ray_event *//*===========================================================================*/int ray_dev_init(struct net_device *dev){#ifdef RAY_IMMEDIATE_INIT int i;#endif /* RAY_IMMEDIATE_INIT */ ray_dev_t *local = dev->priv; dev_link_t *link = local->finder; DEBUG(1,"ray_dev_init(dev=%p)\n",dev); if (!(link->state & DEV_PRESENT)) { DEBUG(2,"ray_dev_init - device not present\n"); return -1; }#ifdef RAY_IMMEDIATE_INIT /* Download startup parameters */ if ( (i = dl_startup_params(dev)) < 0) { printk(KERN_INFO "ray_dev_init dl_startup_params failed - " "returns 0x%x\n",i); return -1; }#else /* RAY_IMMEDIATE_INIT */ /* Postpone the card init so that we can still configure the card, * for example using the Wireless Extensions. The init will happen * in ray_open() - Jean II */ DEBUG(1,"ray_dev_init: postponing card init to ray_open() ; Status = %d\n", local->card_status);#endif /* RAY_IMMEDIATE_INIT */ /* copy mac and broadcast addresses to linux device */ memcpy(&dev->dev_addr, &local->sparm.b4.a_mac_addr, ADDRLEN); memset(dev->broadcast, 0xff, ETH_ALEN); DEBUG(2,"ray_dev_init ending\n"); return 0;}/*===========================================================================*/static int ray_dev_config(struct net_device *dev, struct ifmap *map){ ray_dev_t *local = dev->priv; dev_link_t *link = local->finder; /* Dummy routine to satisfy device structure */ DEBUG(1,"ray_dev_config(dev=%p,ifmap=%p)\n",dev,map); if (!(link->state & DEV_PRESENT)) { DEBUG(2,"ray_dev_config - device not present\n"); return -1; } return 0;}/*===========================================================================*/static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev){ ray_dev_t *local = dev->priv; dev_link_t *link = local->finder; short length = skb->len; if (!(link->state & DEV_PRESENT)) { DEBUG(2,"ray_dev_start_xmit - device not present\n"); return -1; } DEBUG(3,"ray_dev_start_xmit(skb=%p, dev=%p)\n",skb,dev); if (local->authentication_state == NEED_TO_AUTH) { DEBUG(0,"ray_cs Sending authentication request.\n"); if (!build_auth_frame (local, local->auth_id, OPEN_AUTH_REQUEST)) { local->authentication_state = AUTHENTICATED; netif_stop_queue(dev); return 1; } } if (length < ETH_ZLEN) { skb = skb_padto(skb, ETH_ZLEN); if (skb == NULL) return 0; length = ETH_ZLEN; } switch (ray_hw_xmit( skb->data, length, dev, DATA_TYPE)) { case XMIT_NO_CCS: case XMIT_NEED_AUTH: netif_stop_queue(dev); return 1; case XMIT_NO_INTR: case XMIT_MSG_BAD: case XMIT_OK: default: dev->trans_start = jiffies; dev_kfree_skb(skb); return 0; } return 0;} /* ray_dev_start_xmit *//*===========================================================================*/static int ray_hw_xmit(unsigned char* data, int len, struct net_device* dev, UCHAR msg_type){ ray_dev_t *local = (ray_dev_t *)dev->priv; struct ccs __iomem *pccs; int ccsindex; int offset; struct tx_msg __iomem *ptx; /* Address of xmit buffer in PC space */ short int addr; /* Address of xmit buffer in card space */ DEBUG(3,"ray_hw_xmit(data=%p, len=%d, dev=%p)\n",data,len,dev); if (len + TX_HEADER_LENGTH > TX_BUF_SIZE) { printk(KERN_INFO "ray_hw_xmit packet too large: %d bytes\n",len); return XMIT_MSG_BAD; } switch (ccsindex = get_free_tx_ccs(local)) { case ECCSBUSY: DEBUG(2,"ray_hw_xmit tx_ccs table busy\n"); case ECCSFULL: DEBUG(2,"ray_hw_xmit No free tx ccs\n"); case ECARDGONE: netif_stop_queue(dev); return XMIT_NO_CCS; default: break; } addr = TX_BUF_BASE + (ccsindex << 11); if (msg_type == DATA_TYPE) { local->stats.tx_bytes += len; local->stats.tx_packets++; } ptx = local->sram + addr; ray_build_header(local, ptx, msg_type, data); if (translate) { offset = translate_frame(local, ptx, data, len); } else { /* Encapsulate frame */ /* TBD TIB length will move address of ptx->var */ memcpy_toio(&ptx->var, data, len); offset = 0; } /* fill in the CCS */ pccs = ccs_base(local) + ccsindex; len += TX_HEADER_LENGTH + offset; writeb(CCS_TX_REQUEST, &pccs->cmd); writeb(addr >> 8, &pccs->var.tx_request.tx_data_ptr[0]); writeb(local->tib_length, &pccs->var.tx_request.tx_data_ptr[1]); writeb(len >> 8, &pccs->var.tx_request.tx_data_length[0]); writeb(len & 0xff, &pccs->var.tx_request.tx_data_length[1]);/* TBD still need psm_cam? */ writeb(PSM_CAM, &pccs->var.tx_request.pow_sav_mode); writeb(local->net_default_tx_rate, &pccs->var.tx_request.tx_rate); writeb(0, &pccs->var.tx_request.antenna); DEBUG(3,"ray_hw_xmit default_tx_rate = 0x%x\n",\ local->net_default_tx_rate); /* Interrupt the firmware to process the command */ if (interrupt_ecf(local, ccsindex)) { DEBUG(2,"ray_hw_xmit failed - ECF not ready for intr\n");/* TBD very inefficient to copy packet to buffer, and then not send it, but the alternative is to queue the messages and that won't be done for a while. Maybe set tbusy until a CCS is free?*/ writeb(CCS_BUFFER_FREE, &pccs->buffer_status); return XMIT_NO_INTR; } return XMIT_OK;} /* end ray_hw_xmit *//*===========================================================================*/static int translate_frame(ray_dev_t *local, struct tx_msg __iomem *ptx, unsigned char *data, int len){ unsigned short int proto = ((struct ethhdr *)data)->h_proto; if (ntohs(proto) >= 1536) { /* DIX II ethernet frame */ DEBUG(3,"ray_cs translate_frame DIX II\n"); /* Copy LLC header to card buffer */ memcpy_toio(&ptx->var, eth2_llc, sizeof(eth2_llc)); memcpy_toio( ((void __iomem *)&ptx->var) + sizeof(eth2_llc), (UCHAR *)&proto, 2); if ((proto == 0xf380) || (proto == 0x3781)) { /* This is the selective translation table, only 2 entries */ writeb(0xf8, &((struct snaphdr_t __iomem *)ptx->var)->org[3]); } /* Copy body of ethernet packet without ethernet header */ memcpy_toio((void __iomem *)&ptx->var + sizeof(struct snaphdr_t), \ data + ETH_HLEN, len - ETH_HLEN); return (int) sizeof(struct snaphdr_t) - ETH_HLEN; } else { /* already 802 type, and proto is length */ DEBUG(3,"ray_cs translate_frame 802\n"); if (proto == 0xffff) { /* evil netware IPX 802.3 without LLC */ DEBUG(3,"ray_cs translate_frame evil IPX\n"); memcpy_toio(&ptx->var, data + ETH_HLEN, len - ETH_HLEN); return 0 - ETH_HLEN; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -