/*
 * 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;

}
Example #4
0
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;
}