📄 at76c503.c
字号:
memcpy(dev->bb_cr, hwcfg->r5.bb_cr, 14); memcpy(dev->pidvid, hwcfg->r5.pidvid, 4); memcpy(dev->mac_addr, hwcfg->r5.mac_addr, ETH_ALEN); dev->regulatory_domain = hwcfg->r5.regulatory_domain; memcpy(dev->cr15_values, hwcfg->r5.cr15_values, 14); break; default: err("Bad board type set (%d). Unable to get hardware config.", dev->board_type); ret = -EINVAL; } kfree(hwcfg); if (ret < 0) { err("Get HW Config failed (%d)", ret); } return ret;}/* == PROC getRegDomain == */struct reg_domain const *getRegDomain(u16 code){ static struct reg_domain const fd_tab[] = { {0x10, "FCC (U.S)", 0x7ff}, /* ch 1-11 */ {0x20, "IC (Canada)", 0x7ff}, /* ch 1-11 */ {0x30, "ETSI (Europe - (Spain+France)", 0x1fff}, /* ch 1-13 */ {0x31, "Spain", 0x600}, /* ch 10,11 */ {0x32, "France", 0x1e00}, /* ch 10-13 */ {0x40, "MKK (Japan)", 0x2000}, /* ch 14 */ {0x41, "MKK1 (Japan)", 0x3fff}, /* ch 1-14 */ {0x50, "Israel", 0x3fc}, /* ch 3-9 */ }; static int const tab_len = sizeof(fd_tab) / sizeof(struct reg_domain); /* use this if an unknown code comes in */ static struct reg_domain const unknown = {0, "<unknown>", 0xffffffff}; int i; for(i=0; i < tab_len; i++) if (code == fd_tab[i].code) break; return (i >= tab_len) ? &unknown : &fd_tab[i];} /* getFreqDomain */static inlineint get_mib(struct usb_device *udev, u16 mib, u8 *buf, int buf_size){ return usb_control_msg(udev, usb_rcvctrlpipe(udev,0), 0x33, INTERFACE_VENDOR_REQUEST_IN, mib << 8, 0, buf, buf_size, HZ * USB_CTRL_GET_TIMEOUT);}static inlineint get_cmd_status(struct usb_device *udev, u8 cmd, u8 *cmd_status){ return usb_control_msg(udev, usb_rcvctrlpipe(udev,0), 0x22, INTERFACE_VENDOR_REQUEST_IN, cmd, 0, cmd_status, 40, HZ * USB_CTRL_GET_TIMEOUT);}#define EXT_FW_BLOCK_SIZE 1024static int download_external_fw(struct usb_device *udev, u8 *buf, int size){ int i = 0, ret = 0; u8 *block; if (size < 0) return -EINVAL; if ((size > 0) && (buf == NULL)) return -EFAULT; block = kmalloc(EXT_FW_BLOCK_SIZE, GFP_KERNEL); if (block == NULL) return -ENOMEM; dbg(DBG_DEVSTART, "downloading external firmware"); while(size > 0){ int bsize = size > EXT_FW_BLOCK_SIZE ? EXT_FW_BLOCK_SIZE : size; memcpy(block, buf, bsize); dbg(DBG_DEVSTART, "ext fw, size left = %5d, bsize = %4d, i = %2d", size, bsize, i); if((ret = load_ext_fw_block(udev, i, block, bsize)) < 0){ err("load_ext_fw_block failed: %d, i = %d", ret, i); goto exit; } buf += bsize; size -= bsize; i++; } /* for fw >= 0.100, the device needs an extra empty block: */ if((ret = load_ext_fw_block(udev, i, block, 0)) < 0){ err("load_ext_fw_block failed: %d, i = %d", ret, i); goto exit; } exit: kfree(block); return ret;}staticint set_card_command(struct usb_device *udev, int cmd, unsigned char *buf, int buf_size){ int ret; struct at76c503_command *cmd_buf = (struct at76c503_command *)kmalloc( sizeof(struct at76c503_command) + buf_size, GFP_KERNEL); if(cmd_buf){ cmd_buf->cmd = cmd; cmd_buf->reserved = 0; cmd_buf->size = cpu_to_le16(buf_size); if(buf_size > 0) memcpy(&(cmd_buf[1]), buf, buf_size); ret = usb_control_msg(udev, usb_sndctrlpipe(udev,0), 0x0e, DEVICE_VENDOR_REQUEST_OUT, 0, 0, cmd_buf, sizeof(struct at76c503_command) + buf_size, HZ * USB_CTRL_GET_TIMEOUT); kfree(cmd_buf); return ret; } return -ENOMEM;}#define MAKE_CMD_STATUS_CASE(c) case (c): return #cstatic const char* get_cmd_status_string(u8 cmd_status){ switch (cmd_status) { MAKE_CMD_STATUS_CASE(CMD_STATUS_IDLE); MAKE_CMD_STATUS_CASE(CMD_STATUS_COMPLETE); MAKE_CMD_STATUS_CASE(CMD_STATUS_UNKNOWN); MAKE_CMD_STATUS_CASE(CMD_STATUS_INVALID_PARAMETER); MAKE_CMD_STATUS_CASE(CMD_STATUS_FUNCTION_NOT_SUPPORTED); MAKE_CMD_STATUS_CASE(CMD_STATUS_TIME_OUT); MAKE_CMD_STATUS_CASE(CMD_STATUS_IN_PROGRESS); MAKE_CMD_STATUS_CASE(CMD_STATUS_HOST_FAILURE); MAKE_CMD_STATUS_CASE(CMD_STATUS_SCAN_FAILED); } return "UNKNOWN";}/* TODO: should timeout */int wait_completion(struct at76c503 *dev, int cmd){ u8 *cmd_status = kmalloc(40, GFP_KERNEL); struct net_device *netdev = dev->netdev; int ret = 0; do{ ret = get_cmd_status(dev->udev, cmd, cmd_status); if(ret < 0){ err("%s: get_cmd_status failed: %d", netdev->name, ret); break; } dbg(DBG_WAIT_COMPLETE, "%s: Waiting on cmd %d, cmd_status[5] = %d (%s)", dev->netdev->name, cmd, cmd_status[5], get_cmd_status_string(cmd_status[5])); if(cmd_status[5] == CMD_STATUS_IN_PROGRESS || cmd_status[5] == CMD_STATUS_IDLE){ set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(HZ/10); // 100 ms }else break; }while(1); if (ret >= 0) /* if get_cmd_status did not fail, return the status retrieved */ ret = cmd_status[5]; kfree(cmd_status); return ret;}staticint set_mib(struct at76c503 *dev, struct set_mib_buffer *buf){ struct usb_device *udev = dev->udev; int ret; struct at76c503_command *cmd_buf = (struct at76c503_command *)kmalloc( sizeof(struct at76c503_command) + buf->size + 4, GFP_KERNEL); if(cmd_buf){ cmd_buf->cmd = CMD_SET_MIB; cmd_buf->reserved = 0; cmd_buf->size = cpu_to_le16(buf->size + 4); memcpy(&(cmd_buf[1]), buf, buf->size + 4); ret = usb_control_msg(udev, usb_sndctrlpipe(udev,0), 0x0e, DEVICE_VENDOR_REQUEST_OUT, 0, 0, cmd_buf, sizeof(struct at76c503_command) + buf->size + 4, HZ * USB_CTRL_GET_TIMEOUT); if (ret >= 0) if ((ret=wait_completion(dev, CMD_SET_MIB)) != CMD_STATUS_COMPLETE) { info("%s: set_mib: wait_completion failed with %d", dev->netdev->name, ret); ret = -156; /* ??? */ } kfree(cmd_buf); return ret; } return -ENOMEM;}/* return < 0 on error, == 0 if no command sent, == 1 if cmd sent */staticint set_radio(struct at76c503 *dev, int on_off){ int ret; if(dev->radio_on != on_off){ ret = set_card_command(dev->udev, CMD_RADIO, NULL, 0); if(ret < 0){ err("%s: set_card_command(CMD_RADIO) failed: %d", dev->netdev->name, ret); } else ret = 1; dev->radio_on = on_off; } else ret = 0; return ret;}/* == PROC set_pm_mode == sets power save modi (PM_ACTIVE/PM_SAVE/PM_SMART_SAVE) */static int set_pm_mode(struct at76c503 *dev, u8 mode) __attribute__ ((unused));static int set_pm_mode(struct at76c503 *dev, u8 mode){ int ret = 0; memset(&dev->mib_buf, 0, sizeof(struct set_mib_buffer)); dev->mib_buf.type = MIB_MAC_MGMT; dev->mib_buf.size = 1; dev->mib_buf.index = POWER_MGMT_MODE_OFFSET; dev->mib_buf.data[0] = mode; ret = set_mib(dev, &dev->mib_buf); if(ret < 0){ err("%s: set_mib (pm_mode) failed: %d", dev->netdev->name, ret); } return ret;}/* == PROC set_associd == sets the assoc id for power save mode */static int set_associd(struct at76c503 *dev, u16 id) __attribute__ ((unused));static int set_associd(struct at76c503 *dev, u16 id){ int ret = 0; memset(&dev->mib_buf, 0, sizeof(struct set_mib_buffer)); dev->mib_buf.type = MIB_MAC_MGMT; dev->mib_buf.size = 2; dev->mib_buf.index = STATION_ID_OFFSET; dev->mib_buf.data[0] = id & 0xff; dev->mib_buf.data[1] = id >> 8; ret = set_mib(dev, &dev->mib_buf); if(ret < 0){ err("%s: set_mib (associd) failed: %d", dev->netdev->name, ret); } return ret;}/* == PROC set_listen_interval == sets the listen interval for power save mode. really needed, as we have a similar parameter in the assocreq ??? */static int set_listen_interval(struct at76c503 *dev, u16 interval) __attribute__ ((unused));static int set_listen_interval(struct at76c503 *dev, u16 interval){ int ret = 0; memset(&dev->mib_buf, 0, sizeof(struct set_mib_buffer)); dev->mib_buf.type = MIB_MAC; dev->mib_buf.size = 2; dev->mib_buf.index = STATION_ID_OFFSET; dev->mib_buf.data[0] = interval & 0xff; dev->mib_buf.data[1] = interval >> 8; ret = set_mib(dev, &dev->mib_buf); if(ret < 0){ err("%s: set_mib (listen_interval) failed: %d", dev->netdev->name, ret); } return ret;}staticint set_preamble(struct at76c503 *dev, u8 type){ int ret = 0; memset(&dev->mib_buf, 0, sizeof(struct set_mib_buffer)); dev->mib_buf.type = MIB_LOCAL; dev->mib_buf.size = 1; dev->mib_buf.index = PREAMBLE_TYPE_OFFSET; dev->mib_buf.data[0] = type; ret = set_mib(dev, &dev->mib_buf); if(ret < 0){ err("%s: set_mib (preamble) failed: %d", dev->netdev->name, ret); } return ret;}staticint set_frag(struct at76c503 *dev, u16 size){ int ret = 0; memset(&dev->mib_buf, 0, sizeof(struct set_mib_buffer)); dev->mib_buf.type = MIB_MAC; dev->mib_buf.size = 2; dev->mib_buf.index = FRAGMENTATION_OFFSET; *(u16*)dev->mib_buf.data = cpu_to_le16(size); ret = set_mib(dev, &dev->mib_buf); if(ret < 0){ err("%s: set_mib (frag threshold) failed: %d", dev->netdev->name, ret); } return ret;}staticint set_rts(struct at76c503 *dev, u16 size){ int ret = 0; memset(&dev->mib_buf, 0, sizeof(struct set_mib_buffer)); dev->mib_buf.type = MIB_MAC; dev->mib_buf.size = 2; dev->mib_buf.index = RTS_OFFSET; *(u16*)dev->mib_buf.data = cpu_to_le16(size); ret = set_mib(dev, &dev->mib_buf); if(ret < 0){ err("%s: set_mib (rts) failed: %d", dev->netdev->name, ret); } return ret;}staticint set_autorate_fallback(struct at76c503 *dev, int onoff){ int ret = 0; memset(&dev->mib_buf, 0, sizeof(struct set_mib_buffer)); dev->mib_buf.type = MIB_LOCAL; dev->mib_buf.size = 1; dev->mib_buf.index = TX_AUTORATE_FALLBACK_OFFSET; dev->mib_buf.data[0] = onoff; ret = set_mib(dev, &dev->mib_buf); if(ret < 0){ err("%s: set_mib (autorate fallback) failed: %d", dev->netdev->name, ret); } return ret;}static int set_mac_address(struct at76c503 *dev, void *addr){ int ret = 0; memset(&dev->mib_buf, 0, sizeof(struct set_mib_buffer)); dev->mib_buf.type = MIB_MAC_ADD; dev->mib_buf.size = ETH_ALEN; dev->mib_buf.index = offsetof(struct mib_mac_addr, mac_addr); memcpy(dev->mib_buf.data, addr, ETH_ALEN); ret = set_mib(dev, &dev->mib_buf); if(ret < 0){ err("%s: set_mib (MAC_ADDR, mac_addr) failed: %d", dev->netdev->name, ret); } return ret;}#if 0/* implemented to get promisc. mode working, but does not help. May still be useful for multicast eventually. */static int set_group_address(struct at76c503 *dev, u8 *addr, int n){ int ret = 0; memset(&dev->mib_buf, 0, sizeof(struct set_mib_buffer)); dev->mib_buf.type = MIB_MAC_ADD; dev->mib_buf.size = ETH_ALEN; dev->mib_buf.index = offsetof(struct mib_mac_addr, group_addr) + n*ETH_ALEN; memcpy(dev->mib_buf.data, addr, ETH_ALEN); ret = set_mib(dev, &dev->mib_buf); if(ret < 0){ err("%s: set_mib (MIB_MAC_ADD, group_addr) failed: %d", dev->netdev->name, ret); }#if 1 /* I do not know anything about the group_addr_status field... (oku)*/ memset(&dev->mib_buf, 0, sizeof(struct set_mib_buffer)); dev->mib_buf.type = MIB_MAC_ADD; dev->mib_buf.size = 1; dev->mib_buf.index = offsetof(struct mib_mac_addr, group_addr_status) + n; dev->mib_buf.data[0] = 1; ret = set_mib(dev, &dev->mib_buf); if(ret < 0){ err("%s: set_mib (MIB_MAC_ADD, group_addr_status) failed: %d", dev->netdev->name, ret); }#endif return ret;}#endifstaticint set_promisc(struct at76c503 *dev, int onoff){ int ret = 0; memset(&dev->mib_buf, 0, sizeof(struct set_mib_buffer)); dev->mib_buf.type = MIB_LOCAL; dev->mib_buf.size = 1; dev->mib_buf.index = offsetof(struct mib_local, promiscuous_mode); dev->mib_buf.data[0] = onoff ? 1 : 0; ret = set_mib(dev, &dev->mib_buf); if(ret < 0){ err("%s: set_mib (promiscous_mode) failed: %d", dev->netdev->name, ret); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -