/* * Send an DoExitIdle command to the device to ask it to go out of * basestation-idle mode. * * @i2400m: device descriptor * * This starts a renegotiation with the basestation that might involve * another crypto handshake with user space. * * Returns: 0 if ok, < 0 errno code on error. */ int i2400m_cmd_exit_idle(struct i2400m *i2400m) { int result; struct device *dev = i2400m_dev(i2400m); struct sk_buff *ack_skb; struct i2400m_l3l4_hdr *cmd; char strerr[32]; result = -ENOMEM; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (cmd == NULL) goto error_alloc; cmd->type = cpu_to_le16(I2400M_MT_CMD_EXIT_IDLE); cmd->length = 0; cmd->version = cpu_to_le16(I2400M_L3L4_VERSION); ack_skb = i2400m_msg_to_dev(i2400m, cmd, sizeof(*cmd)); result = PTR_ERR(ack_skb); if (IS_ERR(ack_skb)) { dev_err(dev, "Failed to issue 'exit idle' command: %d\n", result); goto error_msg_to_dev; } result = i2400m_msg_check_status(wimax_msg_data(ack_skb), strerr, sizeof(strerr)); kfree_skb(ack_skb); error_msg_to_dev: kfree(cmd); error_alloc: return result; }
/* * Request entering power save * * This command is (mainly) executed when the device indicates that it * is ready to go into powersave mode via a REPORT_POWERSAVE_READY. */ int i2400m_cmd_enter_powersave(struct i2400m *i2400m) { int result; struct device *dev = i2400m_dev(i2400m); struct sk_buff *ack_skb; struct i2400m_cmd_enter_power_save *cmd; char strerr[32]; result = -ENOMEM; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (cmd == NULL) goto error_alloc; cmd->hdr.type = cpu_to_le16(I2400M_MT_CMD_ENTER_POWERSAVE); cmd->hdr.length = cpu_to_le16(sizeof(*cmd) - sizeof(cmd->hdr)); cmd->hdr.version = cpu_to_le16(I2400M_L3L4_VERSION); cmd->tlv.type = cpu_to_le16(I2400M_TLV_TYPE_WAKEUP_MODE); cmd->tlv.length = cpu_to_le16(sizeof(cmd->val)); cmd->val = cpu_to_le32(I2400M_WAKEUP_ENABLED); ack_skb = i2400m_msg_to_dev(i2400m, cmd, sizeof(*cmd)); result = PTR_ERR(ack_skb); if (IS_ERR(ack_skb)) { dev_err(dev, "Failed to issue 'Enter power save' command: %d\n", result); goto error_msg_to_dev; } result = i2400m_msg_check_status(wimax_msg_data(ack_skb), strerr, sizeof(strerr)); if (result == -EACCES) d_printf(1, dev, "Cannot enter power save mode\n"); else if (result < 0) dev_err(dev, "'Enter power save' (0x%04x) command failed: " "%d - %s\n", I2400M_MT_CMD_ENTER_POWERSAVE, result, strerr); else d_printf(1, dev, "device ready to power save\n"); kfree_skb(ack_skb); error_msg_to_dev: kfree(cmd); error_alloc: return result; }
/** * Set basic configuration settings * * @i2400m: device descriptor * @args: array of pointers to the TLV headers to send for * configuration (each followed by its payload). * TLV headers and payloads must be properly initialized, with the * right endianess (LE). * @arg_size: number of pointers in the @args array */ static int i2400m_set_init_config(struct i2400m *i2400m, const struct i2400m_tlv_hdr **arg, size_t args) { int result; struct device *dev = i2400m_dev(i2400m); struct sk_buff *ack_skb; struct i2400m_l3l4_hdr *cmd; char strerr[32]; unsigned argc, argsize, tlv_size; const struct i2400m_tlv_hdr *tlv_hdr; void *buf, *itr; d_fnstart(3, dev, "(i2400m %p arg %p args %zu)\n", i2400m, arg, args); result = 0; if (args == 0) goto none; /* Compute the size of all the TLVs, so we can alloc a * contiguous command block to copy them. */ argsize = 0; for (argc = 0; argc < args; argc++) { tlv_hdr = arg[argc]; argsize += sizeof(*tlv_hdr) + le16_to_cpu(tlv_hdr->length); } WARN_ON(argc >= 9); /* As per hw spec */ /* Alloc the space for the command and TLVs*/ result = -ENOMEM; buf = kzalloc(sizeof(*cmd) + argsize, GFP_KERNEL); if (buf == NULL) goto error_alloc; cmd = buf; cmd->type = cpu_to_le16(I2400M_MT_SET_INIT_CONFIG); cmd->length = cpu_to_le16(argsize); cmd->version = cpu_to_le16(I2400M_L3L4_VERSION); /* Copy the TLVs */ itr = buf + sizeof(*cmd); for (argc = 0; argc < args; argc++) { tlv_hdr = arg[argc]; tlv_size = sizeof(*tlv_hdr) + le16_to_cpu(tlv_hdr->length); memcpy(itr, tlv_hdr, tlv_size); itr += tlv_size; } /* Send the message! */ ack_skb = i2400m_msg_to_dev(i2400m, buf, sizeof(*cmd) + argsize); result = PTR_ERR(ack_skb); if (IS_ERR(ack_skb)) { dev_err(dev, "Failed to issue 'init config' command: %d\n", result); goto error_msg_to_dev; } result = i2400m_msg_check_status(wimax_msg_data(ack_skb), strerr, sizeof(strerr)); if (result < 0) dev_err(dev, "'init config' (0x%04x) command failed: %d - %s\n", I2400M_MT_SET_INIT_CONFIG, result, strerr); kfree_skb(ack_skb); error_msg_to_dev: kfree(buf); error_alloc: none: d_fnend(3, dev, "(i2400m %p arg %p args %zu) = %d\n", i2400m, arg, args, result); return result; }
int i2400m_op_rfkill_sw_toggle(struct wimax_dev *wimax_dev, enum wimax_rf_state state) { int result; struct i2400m *i2400m = wimax_dev_to_i2400m(wimax_dev); struct device *dev = i2400m_dev(i2400m); struct sk_buff *ack_skb; struct { struct i2400m_l3l4_hdr hdr; struct i2400m_tlv_rf_operation sw_rf; } __attribute__((packed)) *cmd; char strerr[32]; d_fnstart(4, dev, "(wimax_dev %p state %d)\n", wimax_dev, state); result = -ENOMEM; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (cmd == NULL) goto error_alloc; cmd->hdr.type = cpu_to_le16(I2400M_MT_CMD_RF_CONTROL); cmd->hdr.length = sizeof(cmd->sw_rf); cmd->hdr.version = cpu_to_le16(I2400M_L3L4_VERSION); cmd->sw_rf.hdr.type = cpu_to_le16(I2400M_TLV_RF_OPERATION); cmd->sw_rf.hdr.length = cpu_to_le16(sizeof(cmd->sw_rf.status)); switch (state) { case WIMAX_RF_OFF: cmd->sw_rf.status = cpu_to_le32(2); break; case WIMAX_RF_ON: cmd->sw_rf.status = cpu_to_le32(1); break; default: BUG(); } ack_skb = i2400m_msg_to_dev(i2400m, cmd, sizeof(*cmd)); result = PTR_ERR(ack_skb); if (IS_ERR(ack_skb)) { dev_err(dev, "Failed to issue 'RF Control' command: %d\n", result); goto error_msg_to_dev; } result = i2400m_msg_check_status(wimax_msg_data(ack_skb), strerr, sizeof(strerr)); if (result < 0) { dev_err(dev, "'RF Control' (0x%04x) command failed: %d - %s\n", I2400M_MT_CMD_RF_CONTROL, result, strerr); goto error_cmd; } result = wait_event_timeout( i2400m->state_wq, i2400m_radio_is(i2400m, state), 5 * HZ); if (result == 0) result = -ETIMEDOUT; if (result < 0) dev_err(dev, "Error waiting for device to toggle RF state: " "%d\n", result); result = 0; error_cmd: kfree_skb(ack_skb); error_msg_to_dev: error_alloc: d_fnend(4, dev, "(wimax_dev %p state %d) = %d\n", wimax_dev, state, result); return result; }