static void if_usb_setup_firmware(struct lbs_private *priv) { struct if_usb_card *cardp = priv->card; struct cmd_ds_set_boot2_ver b2_cmd; struct cmd_ds_802_11_fw_wake_method wake_method; b2_cmd.hdr.size = cpu_to_le16(sizeof(b2_cmd)); b2_cmd.action = 0; b2_cmd.version = cardp->boot2_version; if (lbs_cmd_with_response(priv, CMD_SET_BOOT2_VER, &b2_cmd)) lbs_deb_usb("Setting boot2 version failed\n"); priv->wol_gpio = 2; /* Wake via GPIO2... */ priv->wol_gap = 20; /* ... after 20ms */ lbs_host_sleep_cfg(priv, EHS_WAKE_ON_UNICAST_DATA); wake_method.hdr.size = cpu_to_le16(sizeof(wake_method)); wake_method.action = cpu_to_le16(CMD_ACT_GET); if (lbs_cmd_with_response(priv, CMD_802_11_FW_WAKE_METHOD, &wake_method)) { lbs_pr_info("Firmware does not seem to support PS mode\n"); } else { if (le16_to_cpu(wake_method.method) == CMD_WAKE_METHOD_COMMAND_INT) { lbs_deb_usb("Firmware seems to support PS with wake-via-command\n"); priv->ps_supported = 1; } else { /* The versions which boot up this way don't seem to work even if we set it to the command interrupt */ lbs_pr_info("Firmware doesn't wake via command interrupt; disabling PS mode\n"); } } }
static int lbs_ethtool_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u8 * bytes) { struct lbs_private *priv = dev->ml_priv; struct cmd_ds_802_11_eeprom_access cmd; int ret; if (eeprom->offset + eeprom->len > LBS_EEPROM_LEN || eeprom->len > LBS_EEPROM_READ_LEN) { ret = -EINVAL; goto out; } cmd.hdr.size = cpu_to_le16(sizeof(struct cmd_ds_802_11_eeprom_access) - LBS_EEPROM_READ_LEN + eeprom->len); cmd.action = cpu_to_le16(CMD_ACT_GET); cmd.offset = cpu_to_le16(eeprom->offset); cmd.len = cpu_to_le16(eeprom->len); ret = lbs_cmd_with_response(priv, CMD_802_11_EEPROM_ACCESS, &cmd); if (!ret) memcpy(bytes, cmd.value, eeprom->len); out: return ret; }
int lbs_start_iface(struct lbs_private *priv) { struct cmd_ds_802_11_mac_address cmd; int ret; if (priv->power_restore) { ret = priv->power_restore(priv); if (ret) return ret; } cmd.hdr.size = cpu_to_le16(sizeof(cmd)); cmd.action = cpu_to_le16(CMD_ACT_SET); memcpy(cmd.macadd, priv->current_addr, ETH_ALEN); ret = lbs_cmd_with_response(priv, CMD_802_11_MAC_ADDRESS, &cmd); if (ret) { lbs_deb_net("set MAC address failed\n"); goto err; } lbs_update_channel(priv); priv->iface_running = true; return 0; err: if (priv->power_save) priv->power_save(priv); return ret; }
static int __lbs_mesh_config_send(struct lbs_private *priv, struct cmd_ds_mesh_config *cmd, uint16_t action, uint16_t type) { int ret; u16 command = CMD_MESH_CONFIG_OLD; lbs_deb_enter(LBS_DEB_CMD); /* * Command id is 0xac for v10 FW along with mesh interface * id in bits 14-13-12. */ if (priv->mesh_tlv == TLV_TYPE_MESH_ID) command = CMD_MESH_CONFIG | (MESH_IFACE_ID << MESH_IFACE_BIT_OFFSET); cmd->hdr.command = cpu_to_le16(command); cmd->hdr.size = cpu_to_le16(sizeof(struct cmd_ds_mesh_config)); cmd->hdr.result = 0; cmd->type = cpu_to_le16(type); cmd->action = cpu_to_le16(action); ret = lbs_cmd_with_response(priv, command, cmd); lbs_deb_leave(LBS_DEB_CMD); return ret; }
/** * lbs_mesh_bt_add_del - Add or delete Mesh Blinding Table entries * * @priv: A pointer to &struct lbs_private structure * @add: TRUE to add the entry, FALSE to delete it * @addr1: Destination address to blind or unblind * * returns: 0 on success, error on failure */ int lbs_mesh_bt_add_del(struct lbs_private *priv, bool add, u8 *addr1) { struct cmd_ds_bt_access cmd; int ret = 0; lbs_deb_enter(LBS_DEB_CMD); BUG_ON(addr1 == NULL); memset(&cmd, 0, sizeof(cmd)); cmd.hdr.size = cpu_to_le16(sizeof(cmd)); memcpy(cmd.addr1, addr1, ETH_ALEN); if (add) { cmd.action = cpu_to_le16(CMD_ACT_BT_ACCESS_ADD); lbs_deb_hex(LBS_DEB_MESH, "BT_ADD: blinded MAC addr", addr1, ETH_ALEN); } else { cmd.action = cpu_to_le16(CMD_ACT_BT_ACCESS_DEL); lbs_deb_hex(LBS_DEB_MESH, "BT_DEL: blinded MAC addr", addr1, ETH_ALEN); } ret = lbs_cmd_with_response(priv, CMD_BT_ACCESS, &cmd); lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); return ret; }
static ssize_t lbs_threshold_read(uint16_t tlv_type, uint16_t event_mask, struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { struct cmd_ds_802_11_subscribe_event *subscribed; struct mrvl_ie_thresholds *got; struct lbs_private *priv = file->private_data; ssize_t ret = 0; size_t pos = 0; char *buf; u8 value; u8 freq; int events = 0; buf = (char *)get_zeroed_page(GFP_KERNEL); if (!buf) return -ENOMEM; subscribed = kzalloc(sizeof(*subscribed), GFP_KERNEL); if (!subscribed) { ret = -ENOMEM; goto out_page; } subscribed->hdr.size = cpu_to_le16(sizeof(*subscribed)); subscribed->action = cpu_to_le16(CMD_ACT_GET); ret = lbs_cmd_with_response(priv, CMD_802_11_SUBSCRIBE_EVENT, subscribed); if (ret) goto out_cmd; got = lbs_tlv_find(tlv_type, subscribed->tlv, sizeof(subscribed->tlv)); if (got) { value = got->value; freq = got->freq; events = le16_to_cpu(subscribed->events); pos += snprintf(buf, len, "%d %d %d\n", value, freq, !!(events & event_mask)); } ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos); out_cmd: kfree(subscribed); out_page: free_page((unsigned long)buf); return ret; }
static int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action, struct cmd_ds_mesh_access *cmd) { int ret; cmd->hdr.command = cpu_to_le16(CMD_MESH_ACCESS); cmd->hdr.size = cpu_to_le16(sizeof(*cmd)); cmd->hdr.result = 0; cmd->action = cpu_to_le16(cmd_action); ret = lbs_cmd_with_response(priv, CMD_MESH_ACCESS, cmd); return ret; }
/** * lbs_mesh_bt_reset - Reset/clear the mesh blinding table * * @priv: A pointer to &struct lbs_private structure * * returns: 0 on success, error on failure */ int lbs_mesh_bt_reset(struct lbs_private *priv) { struct cmd_ds_bt_access cmd; int ret = 0; lbs_deb_enter(LBS_DEB_CMD); memset(&cmd, 0, sizeof(cmd)); cmd.hdr.size = cpu_to_le16(sizeof(cmd)); cmd.action = cpu_to_le16(CMD_ACT_BT_ACCESS_RESET); ret = lbs_cmd_with_response(priv, CMD_BT_ACCESS, &cmd); lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); return ret; }
/** * lbs_cmd_fwt_access - Access the mesh forwarding table * * @priv: A pointer to &struct lbs_private structure * @cmd_action: The forwarding table action to perform * @cmd: The pre-filled FWT_ACCESS command * * returns: 0 on success and 'cmd' will be filled with the * firmware's response */ int lbs_cmd_fwt_access(struct lbs_private *priv, u16 cmd_action, struct cmd_ds_fwt_access *cmd) { int ret; lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action); cmd->hdr.command = cpu_to_le16(CMD_FWT_ACCESS); cmd->hdr.size = cpu_to_le16(sizeof(struct cmd_ds_fwt_access)); cmd->hdr.result = 0; cmd->action = cpu_to_le16(cmd_action); ret = lbs_cmd_with_response(priv, CMD_FWT_ACCESS, cmd); lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); return 0; }
int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action, struct cmd_ds_mesh_access *cmd) { int ret; lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action); cmd->hdr.command = cpu_to_le16(CMD_MESH_ACCESS); cmd->hdr.size = cpu_to_le16(sizeof(*cmd)); cmd->hdr.result = 0; cmd->action = cpu_to_le16(cmd_action); ret = lbs_cmd_with_response(priv, CMD_MESH_ACCESS, cmd); lbs_deb_leave(LBS_DEB_CMD); return ret; }
/** * lbs_mesh_bt_get_inverted - Gets the inverted status of the mesh * blinding table * * Normally the firmware "blinds" or ignores traffic from mesh nodes in the * table, but an inverted table allows *only* traffic from nodes listed in * the table. * * @priv: A pointer to &struct lbs_private structure * @inverted: On success, TRUE if the blinding table is inverted, * FALSE if it is not inverted * * returns: 0 on success, error on failure */ int lbs_mesh_bt_get_inverted(struct lbs_private *priv, bool *inverted) { struct cmd_ds_bt_access cmd; int ret = 0; lbs_deb_enter(LBS_DEB_CMD); BUG_ON(inverted == NULL); memset(&cmd, 0, sizeof(cmd)); cmd.hdr.size = cpu_to_le16(sizeof(cmd)); cmd.action = cpu_to_le16(CMD_ACT_BT_ACCESS_GET_INVERT); ret = lbs_cmd_with_response(priv, CMD_BT_ACCESS, &cmd); if (ret == 0) *inverted = !!cmd.id; lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); return ret; }
/** * lbs_mesh_bt_get_entry - List an entry in the mesh blinding table * * @priv: A pointer to &struct lbs_private structure * @id: The ID of the entry to list * @addr1: MAC address associated with the table entry * * returns: 0 on success, error on failure */ int lbs_mesh_bt_get_entry(struct lbs_private *priv, u32 id, u8 *addr1) { struct cmd_ds_bt_access cmd; int ret = 0; lbs_deb_enter(LBS_DEB_CMD); BUG_ON(addr1 == NULL); memset(&cmd, 0, sizeof(cmd)); cmd.hdr.size = cpu_to_le16(sizeof(cmd)); cmd.action = cpu_to_le16(CMD_ACT_BT_ACCESS_SET_INVERT); cmd.id = cpu_to_le32(id); ret = lbs_cmd_with_response(priv, CMD_BT_ACCESS, &cmd); if (ret == 0) memcpy(addr1, cmd.addr1, sizeof(cmd.addr1)); lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); return ret; }
static ssize_t lbs_threshold_write(uint16_t tlv_type, uint16_t event_mask, struct file *file, const char __user *userbuf, size_t count, loff_t *ppos) { struct cmd_ds_802_11_subscribe_event *events; struct mrvl_ie_thresholds *tlv; struct lbs_private *priv = file->private_data; ssize_t buf_size; int value, freq, new_mask; uint16_t curr_mask; char *buf; int ret; buf = (char *)get_zeroed_page(GFP_KERNEL); if (!buf) return -ENOMEM; buf_size = min(count, len - 1); if (copy_from_user(buf, userbuf, buf_size)) { ret = -EFAULT; goto out_page; } ret = sscanf(buf, "%d %d %d", &value, &freq, &new_mask); if (ret != 3) { ret = -EINVAL; goto out_page; } events = kzalloc(sizeof(*events), GFP_KERNEL); if (!events) { ret = -ENOMEM; goto out_page; } events->hdr.size = cpu_to_le16(sizeof(*events)); events->action = cpu_to_le16(CMD_ACT_GET); ret = lbs_cmd_with_response(priv, CMD_802_11_SUBSCRIBE_EVENT, events); if (ret) goto out_events; curr_mask = le16_to_cpu(events->events); if (new_mask) new_mask = curr_mask | event_mask; else new_mask = curr_mask & ~event_mask; /* Now everything is set and we can send stuff down to the firmware */ tlv = (void *)events->tlv; events->action = cpu_to_le16(CMD_ACT_SET); events->events = cpu_to_le16(new_mask); tlv->header.type = cpu_to_le16(tlv_type); tlv->header.len = cpu_to_le16(sizeof(*tlv) - sizeof(tlv->header)); tlv->value = value; if (tlv_type != TLV_TYPE_BCNMISS) tlv->freq = freq; /* The command header, the action, the event mask, and one TLV */ events->hdr.size = cpu_to_le16(sizeof(events->hdr) + 4 + sizeof(*tlv)); ret = lbs_cmd_with_response(priv, CMD_802_11_SUBSCRIBE_EVENT, events); if (!ret) ret = count; out_events: kfree(events); out_page: free_page((unsigned long)buf); return ret; }