Пример #1
0
static
void i2400mu_bus_dev_stop(struct i2400m *i2400m)
{
	struct i2400mu *i2400mu = container_of(i2400m, struct i2400mu, i2400m);
	struct device *dev = &i2400mu->usb_iface->dev;

	d_fnstart(3, dev, "(i2400m %p)\n", i2400m);
	i2400mu_notification_release(i2400mu);
	i2400mu_rx_release(i2400mu);
	i2400mu_tx_release(i2400mu);
	d_fnend(3, dev, "(i2400m %p) = void\n", i2400m);
}
Пример #2
0
Файл: fw.c Проект: 020gzh/linux
/**
 * i2400m_bm_cmd - Execute a boot mode command
 *
 * @cmd: buffer containing the command data (pointing at the header).
 *     This data can be ANYWHERE (for USB, we will copy it to an
 *     specific buffer). Make sure everything is in proper little
 *     endian.
 *
 *     A raw buffer can be also sent, just cast it and set flags to
 *     I2400M_BM_CMD_RAW.
 *
 *     This function will generate a checksum for you if the
 *     checksum bit in the command is set (unless I2400M_BM_CMD_RAW
 *     is set).
 *
 *     You can use the i2400m->bm_cmd_buf to stage your commands and
 *     send them.
 *
 *     If NULL, no command is sent (we just wait for an ack).
 *
 * @cmd_size: size of the command. Will be auto padded to the
 *     bus-specific drivers padding requirements.
 *
 * @ack: buffer where to place the acknowledgement. If it is a regular
 *     command response, all fields will be returned with the right,
 *     native endianess.
 *
 *     You *cannot* use i2400m->bm_ack_buf for this buffer.
 *
 * @ack_size: size of @ack, 16 aligned; you need to provide at least
 *     sizeof(*ack) bytes and then enough to contain the return data
 *     from the command
 *
 * @flags: see I2400M_BM_CMD_* above.
 *
 * @returns: bytes received by the notification; if < 0, an errno code
 *     denoting an error or:
 *
 *     -ERESTARTSYS  The device has rebooted
 *
 * Executes a boot-mode command and waits for a response, doing basic
 * validation on it; if a zero length response is received, it retries
 * waiting for a response until a non-zero one is received (timing out
 * after %I2400M_BOOT_RETRIES retries).
 */
static
ssize_t i2400m_bm_cmd(struct i2400m *i2400m,
		      const struct i2400m_bootrom_header *cmd, size_t cmd_size,
		      struct i2400m_bootrom_header *ack, size_t ack_size,
		      int flags)
{
	ssize_t result = -ENOMEM, rx_bytes;
	struct device *dev = i2400m_dev(i2400m);
	int opcode = cmd == NULL ? -1 : i2400m_brh_get_opcode(cmd);

	d_fnstart(6, dev, "(i2400m %p cmd %p size %zu ack %p size %zu)\n",
		  i2400m, cmd, cmd_size, ack, ack_size);
	BUG_ON(ack_size < sizeof(*ack));
	BUG_ON(i2400m->boot_mode == 0);

	if (cmd != NULL) {		/* send the command */
		result = i2400m->bus_bm_cmd_send(i2400m, cmd, cmd_size, flags);
		if (result < 0)
			goto error_cmd_send;
		if ((flags & I2400M_BM_CMD_RAW) == 0)
			d_printf(5, dev,
				 "boot-mode cmd %d csum %u rr %u da %u: "
				 "addr 0x%04x size %u block csum 0x%04x\n",
				 opcode, i2400m_brh_get_use_checksum(cmd),
				 i2400m_brh_get_response_required(cmd),
				 i2400m_brh_get_direct_access(cmd),
				 cmd->target_addr, cmd->data_size,
				 cmd->block_checksum);
	}
	result = i2400m->bus_bm_wait_for_ack(i2400m, ack, ack_size);
	if (result < 0) {
		dev_err(dev, "boot-mode cmd %d: error waiting for an ack: %d\n",
			opcode, (int) result);	/* bah, %zd doesn't work */
		goto error_wait_for_ack;
	}
	rx_bytes = result;
	/* verify the ack and read more if necessary [result is the
	 * final amount of bytes we get in the ack]  */
	result = __i2400m_bm_ack_verify(i2400m, opcode, ack, ack_size, flags);
	if (result < 0)
		goto error_bad_ack;
	/* Don't you love this stack of empty targets? Well, I don't
	 * either, but it helps track exactly who comes in here and
	 * why :) */
	result = rx_bytes;
error_bad_ack:
error_wait_for_ack:
error_cmd_send:
	d_fnend(6, dev, "(i2400m %p cmd %p size %zu ack %p size %zu) = %d\n",
		i2400m, cmd, cmd_size, ack, ack_size, (int) result);
	return result;
}
Пример #3
0
/**
 * wimax_dev_rm - Unregister an existing WiMAX device
 *
 * @wimax_dev: WiMAX device descriptor
 *
 * Unregisters a WiMAX device previously registered for use with
 * wimax_add_rm().
 *
 * IMPORTANT! Must call before calling unregister_netdev().
 *
 * After this function returns, you will not get any more user space
 * control requests (via netlink or debugfs) and thus to wimax_dev->ops.
 *
 * Reentrancy control is ensured by setting the state to
 * %__WIMAX_ST_QUIESCING. rfkill operations coming through
 * wimax_*rfkill*() will be stopped by the quiescing state; ops coming
 * from the rfkill subsystem will be stopped by the support being
 * removed by wimax_rfkill_rm().
 */
void wimax_dev_rm(struct wimax_dev *wimax_dev)
{
	d_fnstart(3, NULL, "(wimax_dev %p)\n", wimax_dev);

	mutex_lock(&wimax_dev->mutex);
	__wimax_state_change(wimax_dev, __WIMAX_ST_QUIESCING);
	wimax_debugfs_rm(wimax_dev);
	wimax_id_table_rm(wimax_dev);
	__wimax_state_change(wimax_dev, WIMAX_ST_DOWN);
	mutex_unlock(&wimax_dev->mutex);
	wimax_rfkill_rm(wimax_dev);
	d_fnend(3, NULL, "(wimax_dev %p) = void\n", wimax_dev);
}
Пример #4
0
static
int i2400mu_reset_resume(struct usb_interface *iface)
{
	int result;
	struct device *dev = &iface->dev;
	struct i2400mu *i2400mu = usb_get_intfdata(iface);
	struct i2400m *i2400m = &i2400mu->i2400m;

	d_fnstart(3, dev, "(iface %p)\n", iface);
	result = i2400m_dev_reset_handle(i2400m, "device reset on resume");
	d_fnend(3, dev, "(iface %p) = %d\n", iface, result);
	return result < 0 ? result : 0;
}
Пример #5
0
/*
 * Tear down SDIO RX
 *
 * Disables IRQs in the device and removes the IRQ handler.
 */
void i2400ms_rx_release(struct i2400ms *i2400ms)
{
	int result;
	struct sdio_func *func = i2400ms->func;
	struct device *dev = &func->dev;

	d_fnstart(5, dev, "(i2400ms %p)\n", i2400ms);
	sdio_claim_host(func);
	sdio_writeb(func, 0, I2400MS_INTR_ENABLE_ADDR, &result);
	sdio_release_irq(func);
	sdio_release_host(func);
	d_fnend(5, dev, "(i2400ms %p) = %d\n", i2400ms, result);
}
Пример #6
0
/*
 * Tear down of the notification mechanism
 *
 * @i2400m: device descriptor
 *
 * Kill the interrupt endpoint urb, free any allocated resources.
 *
 * We need to check if we have done it before as for example,
 * _suspend() call this; if after a suspend() we get a _disconnect()
 * (as the case is when hibernating), nothing bad happens.
 */
void i2400mu_notification_release(struct i2400mu *i2400mu)
{
	struct device *dev = &i2400mu->usb_iface->dev;

	d_fnstart(4, dev, "(i2400mu %p)\n", i2400mu);
	if (i2400mu->notif_urb != NULL) {
		usb_kill_urb(i2400mu->notif_urb);
		kfree(i2400mu->notif_urb->transfer_buffer);
		usb_free_urb(i2400mu->notif_urb);
		i2400mu->notif_urb = NULL;
	}
	d_fnend(4, dev, "(i2400mu %p)\n", i2400mu);
}
Пример #7
0
/*
 * Read data from the device (when in normal)
 *
 * Allocate an SKB of the right size, read the data in and then
 * deliver it to the generic layer.
 *
 * We also check for a reboot barker. That means the device died and
 * we have to reboot it.
 */
static
void i2400ms_rx(struct i2400ms *i2400ms)
{
	int ret;
	struct sdio_func *func = i2400ms->func;
	struct device *dev = &func->dev;
	struct i2400m *i2400m = &i2400ms->i2400m;
	struct sk_buff *skb;
	ssize_t rx_size;

	d_fnstart(7, dev, "(i2400ms %p)\n", i2400ms);
	rx_size = __i2400ms_rx_get_size(i2400ms);
	if (rx_size < 0) {
		ret = rx_size;
		goto error_get_size;
	}
	ret = -ENOMEM;
	skb = alloc_skb(rx_size, GFP_ATOMIC);
	if (NULL == skb) {
		dev_err(dev, "RX: unable to alloc skb\n");
		goto error_alloc_skb;
	}

	ret = sdio_memcpy_fromio(func, skb->data,
				 I2400MS_DATA_ADDR, rx_size);
	if (ret < 0) {
		dev_err(dev, "RX: SDIO data read failed: %d\n", ret);
		goto error_memcpy_fromio;
	}
	/* Check if device has reset */
	if (!memcmp(skb->data, i2400m_NBOOT_BARKER,
		    sizeof(i2400m_NBOOT_BARKER))
	    || !memcmp(skb->data, i2400m_SBOOT_BARKER,
		       sizeof(i2400m_SBOOT_BARKER))) {
		ret = i2400m_dev_reset_handle(i2400m);
		kfree_skb(skb);
	} else {
		skb_put(skb, rx_size);
		i2400m_rx(i2400m, skb);
	}
	d_fnend(7, dev, "(i2400ms %p) = void\n", i2400ms);
	return;

error_memcpy_fromio:
	kfree_skb(skb);
error_alloc_skb:
error_get_size:
	d_fnend(7, dev, "(i2400ms %p) = %d\n", i2400ms, ret);
	return;
}
Пример #8
0
/*
 * Enable the SDIO function
 *
 * Tries to enable the SDIO function; might fail if it is still not
 * ready (in some hardware, the SDIO WiMAX function is only enabled
 * when we ask it to explicitly doing). Tries until a timeout is
 * reached.
 *
 * The @maxtries argument indicates how many times (at most) it should
 * be tried to enable the function. 0 means forever. This acts along
 * with the timeout (ie: it'll stop trying as soon as the maximum
 * number of tries is reached _or_ as soon as the timeout is reached).
 *
 * The reverse of this is...sdio_disable_function()
 *
 * Returns: 0 if the SDIO function was enabled, < 0 errno code on
 *     error (-ENODEV when it was unable to enable the function).
 */
static
int i2400ms_enable_function(struct i2400ms *i2400ms, unsigned maxtries)
{
	struct sdio_func *func = i2400ms->func;
	u64 timeout;
	int err;
	struct device *dev = &func->dev;
	unsigned tries = 0;

	d_fnstart(3, dev, "(func %p)\n", func);
	/* Setup timeout (FIXME: This needs to read the CIS table to
	 * get a real timeout) and then wait for the device to signal
	 * it is ready */
	timeout = get_jiffies_64() + ioe_timeout * HZ;
	err = -ENODEV;
	while (err != 0 && time_before64(get_jiffies_64(), timeout)) {
		sdio_claim_host(func);
		/*
		 * There is a sillicon bug on the IWMC3200, where the
		 * IOE timeout will cause problems on Moorestown
		 * platforms (system hang). We explicitly overwrite
		 * func->enable_timeout here to work around the issue.
		 */
		if (i2400ms->iwmc3200)
			func->enable_timeout = IWMC3200_IOR_TIMEOUT;
		err = sdio_enable_func(func);
		if (0 == err) {
			sdio_release_host(func);
			d_printf(2, dev, "SDIO function enabled\n");
			goto function_enabled;
		}
		d_printf(2, dev, "SDIO function failed to enable: %d\n", err);
		sdio_release_host(func);
		if (maxtries > 0 && ++tries >= maxtries) {
			err = -ETIME;
			break;
		}
		msleep(I2400MS_INIT_SLEEP_INTERVAL);
	}
	/* If timed out, device is not there yet -- get -ENODEV so
	 * the device driver core will retry later on. */
	if (err == -ETIME) {
		dev_err(dev, "Can't enable WiMAX function; "
			" has the function been enabled?\n");
		err = -ENODEV;
	}
function_enabled:
	d_fnend(3, dev, "(func %p) = %d\n", func, err);
	return err;
}
Пример #9
0
Файл: fw.c Проект: 020gzh/linux
/*
 * Do the final steps of uploading firmware
 *
 * @bcf_hdr: BCF header we are actually using
 * @bcf: pointer to the firmware image (which matches the first header
 *     that is followed by the actual payloads).
 * @offset: [byte] offset into @bcf for the command we need to send.
 *
 * Depending on the boot mode (signed vs non-signed), different
 * actions need to be taken.
 */
static
int i2400m_dnload_finalize(struct i2400m *i2400m,
			   const struct i2400m_bcf_hdr *bcf_hdr,
			   const struct i2400m_bcf_hdr *bcf, size_t offset)
{
	int ret = 0;
	struct device *dev = i2400m_dev(i2400m);
	struct i2400m_bootrom_header *cmd, ack;
	struct {
		struct i2400m_bootrom_header cmd;
		u8 cmd_pl[0];
	} __packed *cmd_buf;
	size_t signature_block_offset, signature_block_size;

	d_fnstart(3, dev, "offset %zu\n", offset);
	cmd = (void *) bcf + offset;
	if (i2400m_boot_is_signed(i2400m) == 0) {
		struct i2400m_bootrom_header jump_ack;
		d_printf(1, dev, "unsecure boot, jumping to 0x%08x\n",
			le32_to_cpu(cmd->target_addr));
		cmd_buf = i2400m->bm_cmd_buf;
		memcpy(&cmd_buf->cmd, cmd, sizeof(*cmd));
		cmd = &cmd_buf->cmd;
		/* now cmd points to the actual bootrom_header in cmd_buf */
		i2400m_brh_set_opcode(cmd, I2400M_BRH_JUMP);
		cmd->data_size = 0;
		ret = i2400m_bm_cmd(i2400m, cmd, sizeof(*cmd),
				    &jump_ack, sizeof(jump_ack), 0);
	} else {
		d_printf(1, dev, "secure boot, jumping to 0x%08x\n",
			 le32_to_cpu(cmd->target_addr));
		cmd_buf = i2400m->bm_cmd_buf;
		memcpy(&cmd_buf->cmd, cmd, sizeof(*cmd));
		signature_block_offset =
			sizeof(*bcf_hdr)
			+ le32_to_cpu(bcf_hdr->key_size) * sizeof(u32)
			+ le32_to_cpu(bcf_hdr->exponent_size) * sizeof(u32);
		signature_block_size =
			le32_to_cpu(bcf_hdr->modulus_size) * sizeof(u32);
		memcpy(cmd_buf->cmd_pl,
		       (void *) bcf_hdr + signature_block_offset,
		       signature_block_size);
		ret = i2400m_bm_cmd(i2400m, &cmd_buf->cmd,
				    sizeof(cmd_buf->cmd) + signature_block_size,
				    &ack, sizeof(ack), I2400M_BM_CMD_RAW);
	}
	d_fnend(3, dev, "returning %d\n", ret);
	return ret;
}
Пример #10
0
/*
 * Parse a 'state report' and extract carrier on/off information
 *
 * @i2400m: device descriptor
 * @l3l4_hdr: pointer to message; it has been already validated for
 *            consistent size.
 * @size: size of the message (header + payload). The header length
 *        declaration is assumed to be congruent with @size (as in
 *        sizeof(*l3l4_hdr) + l3l4_hdr->length == size)
 *
 * Extract from the report state the system state TLV and infer from
 * there if we have a carrier or not. Update our local state and tell
 * netdev.
 *
 * When setting the carrier, it's fine to set OFF twice (for example),
 * as netif_carrier_off() will not generate two OFF events (just on
 * the transitions).
 */
static
void i2400m_report_state_hook(struct i2400m *i2400m,
			      const struct i2400m_l3l4_hdr *l3l4_hdr,
			      size_t size, const char *tag)
{
	struct device *dev = i2400m_dev(i2400m);
	const struct i2400m_tlv_hdr *tlv;
	const struct i2400m_tlv_system_state *ss;
	const struct i2400m_tlv_rf_switches_status *rfss;
	const struct i2400m_tlv_media_status *ms;
	size_t tlv_size = le16_to_cpu(l3l4_hdr->length);

	d_fnstart(4, dev, "(i2400m %p, l3l4_hdr %p, size %zu, %s)\n",
		  i2400m, l3l4_hdr, size, tag);
	tlv = NULL;

	while ((tlv = i2400m_tlv_buffer_walk(i2400m, &l3l4_hdr->pl,
					     tlv_size, tlv))) {
		if (0 == i2400m_tlv_match(tlv, I2400M_TLV_SYSTEM_STATE,
					  sizeof(*ss))) {
			ss = container_of(tlv, typeof(*ss), hdr);
			d_printf(2, dev, "%s: system state TLV "
				 "found (0x%04x), state 0x%08x\n",
				 tag, I2400M_TLV_SYSTEM_STATE,
				 le32_to_cpu(ss->state));
			i2400m_report_tlv_system_state(i2400m, ss);
		}
		if (0 == i2400m_tlv_match(tlv, I2400M_TLV_RF_STATUS,
					  sizeof(*rfss))) {
			rfss = container_of(tlv, typeof(*rfss), hdr);
			d_printf(2, dev, "%s: RF status TLV "
				 "found (0x%04x), sw 0x%02x hw 0x%02x\n",
				 tag, I2400M_TLV_RF_STATUS,
				 le32_to_cpu(rfss->sw_rf_switch),
				 le32_to_cpu(rfss->hw_rf_switch));
			i2400m_report_tlv_rf_switches_status(i2400m, rfss);
		}
		if (0 == i2400m_tlv_match(tlv, I2400M_TLV_MEDIA_STATUS,
					  sizeof(*ms))) {
			ms = container_of(tlv, typeof(*ms), hdr);
			d_printf(2, dev, "%s: Media Status TLV: %u\n",
				 tag, le32_to_cpu(ms->media_status));
			i2400m_report_tlv_media_status(i2400m, ms);
		}
	}
	d_fnend(4, dev, "(i2400m %p, l3l4_hdr %p, size %zu, %s) = void\n",
		i2400m, l3l4_hdr, size, tag);
}
/* Shutdown the wimax stack */
static
int __init wimax_subsys_init(void)
{
	int result, cnt;

	d_fnstart(4, NULL, "()\n");
	d_parse_params(D_LEVEL, D_LEVEL_SIZE, wimax_debug_params,
		       "wimax.debug");

	snprintf(wimax_gnl_family.name, sizeof(wimax_gnl_family.name),
		 "WiMAX");
	result = genl_register_family(&wimax_gnl_family);
	if (unlikely(result < 0)) {
		printk(KERN_ERR "cannot register generic netlink family: %d\n",
		       result);
		goto error_register_family;
	}

	for (cnt = 0; cnt < ARRAY_SIZE(wimax_gnl_ops); cnt++) {
		result = genl_register_ops(&wimax_gnl_family,
					   wimax_gnl_ops[cnt]);
		d_printf(4, NULL, "registering generic netlink op code "
			 "%u: %d\n", wimax_gnl_ops[cnt]->cmd, result);
		if (unlikely(result < 0)) {
			printk(KERN_ERR "cannot register generic netlink op "
			       "code %u: %d\n",
			       wimax_gnl_ops[cnt]->cmd, result);
			goto error_register_ops;
		}
	}

	result = genl_register_mc_group(&wimax_gnl_family, &wimax_gnl_mcg);
	if (result < 0)
		goto error_mc_group;
	d_fnend(4, NULL, "() = 0\n");
	return 0;

error_mc_group:
error_register_ops:
	for (cnt--; cnt >= 0; cnt--)
		genl_unregister_ops(&wimax_gnl_family,
				    wimax_gnl_ops[cnt]);
	genl_unregister_family(&wimax_gnl_family);
error_register_family:
	d_fnend(4, NULL, "() = %d\n", result);
	return result;

}
Пример #12
0
ssize_t i2400ms_bus_bm_cmd_send(struct i2400m *i2400m,
				const struct i2400m_bootrom_header *_cmd,
				size_t cmd_size, int flags)
{
	ssize_t result;
	struct device *dev = i2400m_dev(i2400m);
	struct i2400ms *i2400ms = container_of(i2400m, struct i2400ms, i2400m);
	int opcode = _cmd == NULL ? -1 : i2400m_brh_get_opcode(_cmd);
	struct i2400m_bootrom_header *cmd;
	
	size_t cmd_size_a = ALIGN(cmd_size, I2400MS_BLK_SIZE);

	d_fnstart(5, dev, "(i2400m %p cmd %p size %zu)\n",
		  i2400m, _cmd, cmd_size);
	result = -E2BIG;
	if (cmd_size > I2400M_BM_CMD_BUF_SIZE)
		goto error_too_big;

	if (_cmd != i2400m->bm_cmd_buf)
		memmove(i2400m->bm_cmd_buf, _cmd, cmd_size);
	cmd = i2400m->bm_cmd_buf;
	if (cmd_size_a > cmd_size)			
		memset(i2400m->bm_cmd_buf + cmd_size, 0, cmd_size_a - cmd_size);
	if ((flags & I2400M_BM_CMD_RAW) == 0) {
		if (WARN_ON(i2400m_brh_get_response_required(cmd) == 0))
			dev_warn(dev, "SW BUG: response_required == 0\n");
		i2400m_bm_cmd_prepare(cmd);
	}
	d_printf(4, dev, "BM cmd %d: %zu bytes (%zu padded)\n",
		 opcode, cmd_size, cmd_size_a);
	d_dump(5, dev, cmd, cmd_size);

	sdio_claim_host(i2400ms->func);			
	result = sdio_memcpy_toio(i2400ms->func, I2400MS_DATA_ADDR,
				  i2400m->bm_cmd_buf, cmd_size_a);
	sdio_release_host(i2400ms->func);
	if (result < 0) {
		dev_err(dev, "BM cmd %d: cannot send: %ld\n",
			opcode, (long) result);
		goto error_cmd_send;
	}
	result = cmd_size;
error_cmd_send:
error_too_big:
	d_fnend(5, dev, "(i2400m %p cmd %p size %zu) = %d\n",
		i2400m, _cmd, cmd_size, (int) result);
	return result;
}
Пример #13
0
static
void i2400ms_remove(struct sdio_func *func)
{
	struct device *dev = &func->dev;
	struct i2400ms *i2400ms = sdio_get_drvdata(func);
	struct i2400m *i2400m = &i2400ms->i2400m;
	struct net_device *net_dev = i2400m->wimax_dev.net_dev;

	d_fnstart(3, dev, "SDIO func %p\n", func);
	debugfs_remove_recursive(i2400ms->debugfs_dentry);
	i2400ms->debugfs_dentry = NULL;
	i2400m_release(i2400m);
	sdio_set_drvdata(func, NULL);
	free_netdev(net_dev);
	d_fnend(3, dev, "SDIO func %p\n", func);
}
Пример #14
0
static
int i2400mu_suspend(struct usb_interface *iface, pm_message_t pm_msg)
{
	int result = 0;
	struct device *dev = &iface->dev;
	struct i2400mu *i2400mu = usb_get_intfdata(iface);
#ifdef CONFIG_PM
	struct usb_device *usb_dev = i2400mu->usb_dev;
#endif
	unsigned is_autosuspend = 0;
	struct i2400m *i2400m = &i2400mu->i2400m;

#ifdef CONFIG_PM
	if (usb_dev->auto_pm > 0)
		is_autosuspend = 1;
#endif

	d_fnstart(3, dev, "(iface %p pm_msg %u)\n", iface, pm_msg.event);
	if (i2400m->updown == 0)
		goto no_firmware;
	if (i2400m->state == I2400M_SS_DATA_PATH_CONNECTED && is_autosuspend) {
		
		result = -EBADF;
		d_printf(1, dev, "fw up, link up, not-idle, autosuspend: "
			 "not entering powersave\n");
		goto error_not_now;
	}
	d_printf(1, dev, "fw up: entering powersave\n");
	atomic_dec(&i2400mu->do_autopm);
	result = i2400m_cmd_enter_powersave(i2400m);
	atomic_inc(&i2400mu->do_autopm);
	if (result < 0 && !is_autosuspend) {
		
		dev_err(dev, "failed to suspend, will reset on resume\n");
		result = 0;
	}
	if (result < 0)
		goto error_enter_powersave;
	i2400mu_notification_release(i2400mu);
	d_printf(1, dev, "powersave requested\n");
error_enter_powersave:
error_not_now:
no_firmware:
	d_fnend(3, dev, "(iface %p pm_msg %u) = %d\n",
		iface, pm_msg.event, result);
	return result;
}
Пример #15
0
static
int i2400m_open(struct net_device *net_dev)
{
	int result;
	struct i2400m *i2400m = net_dev_to_i2400m(net_dev);
	struct device *dev = i2400m_dev(i2400m);

	d_fnstart(3, dev, "(net_dev %p [i2400m %p])\n", net_dev, i2400m);
	if (i2400m->ready == 0) {
		dev_err(dev, "Device is still initializing\n");
		result = -EBUSY;
	} else
		result = 0;
	d_fnend(3, dev, "(net_dev %p [i2400m %p]) = %d\n",
		net_dev, i2400m, result);
	return result;
}
Пример #16
0
/*
 * Disconect a i2400m from the system.
 *
 * i2400m_stop() has been called before, so al the rx and tx contexts
 * have been taken down already. Make sure the queue is stopped,
 * unregister netdev and i2400m, free and kill.
 */
static
void i2400mu_disconnect(struct usb_interface *iface)
{
	struct i2400mu *i2400mu = usb_get_intfdata(iface);
	struct i2400m *i2400m = &i2400mu->i2400m;
	struct net_device *net_dev = i2400m->wimax_dev.net_dev;
	struct device *dev = &iface->dev;

	d_fnstart(3, dev, "(iface %p i2400m %p)\n", iface, i2400m);

	debugfs_remove_recursive(i2400mu->debugfs_dentry);
	i2400m_release(i2400m);
	usb_set_intfdata(iface, NULL);
	usb_put_dev(i2400mu->usb_dev);
	free_netdev(net_dev);
	d_fnend(3, dev, "(iface %p i2400m %p) = void\n", iface, i2400m);
}
Пример #17
0
/**
 * i2400m_netdev_setup - Setup setup @net_dev's i2400m private data
 *
 * Called by alloc_netdev()
 */
void i2400m_netdev_setup(struct net_device *net_dev)
{
	d_fnstart(3, NULL, "(net_dev %p)\n", net_dev);
	ether_setup(net_dev);
	net_dev->mtu = I2400M_MAX_MTU;
	net_dev->tx_queue_len = I2400M_TX_QLEN;
	net_dev->features =
		  NETIF_F_VLAN_CHALLENGED
		| NETIF_F_HIGHDMA;
	net_dev->flags =
		IFF_NOARP		/* i2400m is apure IP device */
		& (~IFF_BROADCAST	/* i2400m is P2P */
		   & ~IFF_MULTICAST);
	net_dev->watchdog_timeo = I2400M_TX_TIMEOUT;
	net_dev->netdev_ops = &i2400m_netdev_ops;
	d_fnend(3, NULL, "(net_dev %p) = void\n", net_dev);
}
Пример #18
0
/*
 * Wake up the device and transmit a held SKB, then restart the net queue
 *
 * When the device goes into basestation-idle mode, we need to tell it
 * to exit that mode; it will negotiate with the base station, user
 * space may have to intervene to rehandshake crypto and then tell us
 * when it is ready to transmit the packet we have "queued". Still we
 * need to give it sometime after it reports being ok.
 *
 * On error, there is not much we can do. If the error was on TX, we
 * still wake the queue up to see if the next packet will be luckier.
 *
 * If _cmd_exit_idle() fails...well, it could be many things; most
 * commonly it is that something else took the device out of IDLE mode
 * (for example, the base station). In that case we get an -EILSEQ and
 * we are just going to ignore that one. If the device is back to
 * connected, then fine -- if it is someother state, the packet will
 * be dropped anyway.
 */
void i2400m_wake_tx_work(struct work_struct *ws)
{
	int result;
	struct i2400m *i2400m = container_of(ws, struct i2400m, wake_tx_ws);
	struct device *dev = i2400m_dev(i2400m);
	struct sk_buff *skb = i2400m->wake_tx_skb;
	unsigned long flags;

	spin_lock_irqsave(&i2400m->tx_lock, flags);
	skb = i2400m->wake_tx_skb;
	i2400m->wake_tx_skb = NULL;
	spin_unlock_irqrestore(&i2400m->tx_lock, flags);

	d_fnstart(3, dev, "(ws %p i2400m %p skb %p)\n", ws, i2400m, skb);
	result = -EINVAL;
	if (skb == NULL) {
		dev_err(dev, "WAKE&TX: skb dissapeared!\n");
		goto out_put;
	}
	result = i2400m_cmd_exit_idle(i2400m);
	if (result == -EILSEQ)
		result = 0;
	if (result < 0) {
		dev_err(dev, "WAKE&TX: device didn't get out of idle: "
			"%d\n", result);
			goto error;
	}
	result = wait_event_timeout(i2400m->state_wq,
				    i2400m->state != I2400M_SS_IDLE, 5 * HZ);
	if (result == 0)
		result = -ETIMEDOUT;
	if (result < 0) {
		dev_err(dev, "WAKE&TX: error waiting for device to exit IDLE: "
			"%d\n", result);
		goto error;
	}
	msleep(20);	/* device still needs some time or it drops it */
	result = i2400m_tx(i2400m, skb->data, skb->len, I2400M_PT_DATA);
	netif_wake_queue(i2400m->wimax_dev.net_dev);
error:
	kfree_skb(skb);	/* refcount transferred by _hard_start_xmit() */
out_put:
	i2400m_put(i2400m);
	d_fnend(3, dev, "(ws %p i2400m %p skb %p) = void [%d]\n",
		ws, i2400m, skb, result);
}
Пример #19
0
/*
 * Get the next TX message in the TX FIFO and send it to the device
 *
<<<<<<< HEAD
 * Note we exit the loop if i2400mu_tx() fails; that function only
=======
 * Note we exit the loop if i2400mu_tx() fails; that funtion only
>>>>>>> 296c66da8a02d52243f45b80521febece5ed498a
 * fails on hard error (failing to tx a buffer not being one of them,
 * see its doc).
 *
 * Return: 0
 */
static
int i2400mu_txd(void *_i2400mu)
{
	int result = 0;
	struct i2400mu *i2400mu = _i2400mu;
	struct i2400m *i2400m = &i2400mu->i2400m;
	struct device *dev = &i2400mu->usb_iface->dev;
	struct i2400m_msg_hdr *tx_msg;
	size_t tx_msg_size;
	unsigned long flags;

	d_fnstart(4, dev, "(i2400mu %p)\n", i2400mu);

	spin_lock_irqsave(&i2400m->tx_lock, flags);
	BUG_ON(i2400mu->tx_kthread != NULL);
	i2400mu->tx_kthread = current;
	spin_unlock_irqrestore(&i2400m->tx_lock, flags);

	while (1) {
		d_printf(2, dev, "TX: waiting for messages\n");
		tx_msg = NULL;
		wait_event_interruptible(
			i2400mu->tx_wq,
			(kthread_should_stop()	/* check this first! */
			 || (tx_msg = i2400m_tx_msg_get(i2400m, &tx_msg_size)))
			);
		if (kthread_should_stop())
			break;
		WARN_ON(tx_msg == NULL);	/* should not happen...*/
		d_printf(2, dev, "TX: submitting %zu bytes\n", tx_msg_size);
		d_dump(5, dev, tx_msg, tx_msg_size);
		/* Yeah, we ignore errors ... not much we can do */
		i2400mu_tx(i2400mu, tx_msg, tx_msg_size);
		i2400m_tx_msg_sent(i2400m);	/* ack it, advance the FIFO */
		if (result < 0)
			break;
	}

	spin_lock_irqsave(&i2400m->tx_lock, flags);
	i2400mu->tx_kthread = NULL;
	spin_unlock_irqrestore(&i2400m->tx_lock, flags);

	d_fnend(4, dev, "(i2400mu %p) = %d\n", i2400mu, result);
	return result;
}
Пример #20
0
void i2400m_report_tlv_rf_switches_status(
	struct i2400m *i2400m,
	const struct i2400m_tlv_rf_switches_status *rfss)
{
	struct device *dev = i2400m_dev(i2400m);
	enum i2400m_rf_switch_status hw, sw;
	enum wimax_st wimax_state;

	sw = le32_to_cpu(rfss->sw_rf_switch);
	hw = le32_to_cpu(rfss->hw_rf_switch);

	d_fnstart(3, dev, "(i2400m %p rfss %p [hw %u sw %u])\n",
		  i2400m, rfss, hw, sw);
	
	wimax_state = wimax_state_get(&i2400m->wimax_dev);
	if (wimax_state < WIMAX_ST_RADIO_OFF) {
		d_printf(3, dev, "ignoring RF switches report, state %u\n",
			 wimax_state);
		goto out;
	}
	switch (sw) {
	case I2400M_RF_SWITCH_ON:	
		wimax_report_rfkill_sw(&i2400m->wimax_dev, WIMAX_RF_ON);
		break;
	case I2400M_RF_SWITCH_OFF:	
		wimax_report_rfkill_sw(&i2400m->wimax_dev, WIMAX_RF_OFF);
		break;
	default:
		dev_err(dev, "HW BUG? Unknown RF SW state 0x%x\n", sw);
	}

	switch (hw) {
	case I2400M_RF_SWITCH_ON:	
		wimax_report_rfkill_hw(&i2400m->wimax_dev, WIMAX_RF_ON);
		break;
	case I2400M_RF_SWITCH_OFF:	
		wimax_report_rfkill_hw(&i2400m->wimax_dev, WIMAX_RF_OFF);
		break;
	default:
		dev_err(dev, "HW BUG? Unknown RF HW state 0x%x\n", hw);
	}
out:
	d_fnend(3, dev, "(i2400m %p rfss %p [hw %u sw %u]) = void\n",
		i2400m, rfss, hw, sw);
}
Пример #21
0
/*
 * Send a boot-mode command over the bulk-out pipe
 *
 * Command can be a raw command, which requires no preparation (and
 * which might not even be following the command format). Checks that
 * the right amount of data was transferred.
 *
 * To satisfy USB requirements (no onstack, vmalloc or in data segment
 * buffers), we copy the command to i2400m->bm_cmd_buf and send it from
 * there.
 *
 * @flags: pass thru from i2400m_bm_cmd()
 * @return: cmd_size if ok, < 0 errno code on error.
 */
ssize_t i2400mu_bus_bm_cmd_send(struct i2400m *i2400m,
				const struct i2400m_bootrom_header *_cmd,
				size_t cmd_size, int flags)
{
	ssize_t result;
	struct device *dev = i2400m_dev(i2400m);
	struct i2400mu *i2400mu = container_of(i2400m, struct i2400mu, i2400m);
	int opcode = _cmd == NULL ? -1 : i2400m_brh_get_opcode(_cmd);
	struct i2400m_bootrom_header *cmd;
	size_t cmd_size_a = ALIGN(cmd_size, 16);	/* USB restriction */

	d_fnstart(8, dev, "(i2400m %p cmd %p size %zu)\n",
		  i2400m, _cmd, cmd_size);
	result = -E2BIG;
	if (cmd_size > I2400M_BM_CMD_BUF_SIZE)
		goto error_too_big;
	if (_cmd != i2400m->bm_cmd_buf)
		memmove(i2400m->bm_cmd_buf, _cmd, cmd_size);
	cmd = i2400m->bm_cmd_buf;
	if (cmd_size_a > cmd_size)			/* Zero pad space */
		memset(i2400m->bm_cmd_buf + cmd_size, 0, cmd_size_a - cmd_size);
	if ((flags & I2400M_BM_CMD_RAW) == 0) {
		if (WARN_ON(i2400m_brh_get_response_required(cmd) == 0))
			dev_warn(dev, "SW BUG: response_required == 0\n");
		i2400m_bm_cmd_prepare(cmd);
	}
	result = i2400mu_tx_bulk_out(i2400mu, i2400m->bm_cmd_buf, cmd_size);
	if (result < 0) {
		dev_err(dev, "boot-mode cmd %d: cannot send: %zd\n",
			opcode, result);
		goto error_cmd_send;
	}
	if (result != cmd_size) {		/* all was transferred? */
		dev_err(dev, "boot-mode cmd %d: incomplete transfer "
			"(%zu vs %zu submitted)\n",  opcode, result, cmd_size);
		result = -EIO;
		goto error_cmd_size;
	}
error_cmd_size:
error_cmd_send:
error_too_big:
	d_fnend(8, dev, "(i2400m %p cmd %p size %zu) = %zd\n",
		i2400m, _cmd, cmd_size, result);
	return result;
}
Пример #22
0
/*
 * Tear down SDIO RX
 *
 * Disables IRQs in the device and removes the IRQ handler.
 */
void i2400ms_rx_release(struct i2400ms *i2400ms)
{
	int result;
	struct sdio_func *func = i2400ms->func;
	struct device *dev = &func->dev;
	struct i2400m *i2400m = &i2400ms->i2400m;

	d_fnstart(5, dev, "(i2400ms %p)\n", i2400ms);
	spin_lock(&i2400m->rx_lock);
	i2400ms->bm_ack_size = -EINTR;
	spin_unlock(&i2400m->rx_lock);
	wake_up_all(&i2400ms->bm_wfa_wq);
	sdio_claim_host(func);
	sdio_writeb(func, 0, I2400MS_INTR_ENABLE_ADDR, &result);
	sdio_release_irq(func);
	sdio_release_host(func);
	d_fnend(5, dev, "(i2400ms %p) = %d\n", i2400ms, result);
}
Пример #23
0
/**
 * wimax_dev_add - Register a new WiMAX device
 *
 * @wimax_dev: WiMAX device descriptor (as embedded in your @net_dev's
 *     priv data). You must have called wimax_dev_init() on it before.
 *
 * @net_dev: net device the @wimax_dev is associated with. The
 *     function expects SET_NETDEV_DEV() and register_netdev() were
 *     already called on it.
 *
 * Registers the new WiMAX device, sets up the user-kernel control
 * interface (generic netlink) and common WiMAX infrastructure.
 *
 * Note that the parts that will allow interaction with user space are
 * setup at the very end, when the rest is in place, as once that
 * happens, the driver might get user space control requests via
 * netlink or from debugfs that might translate into calls into
 * wimax_dev->op_*().
 */
int wimax_dev_add(struct wimax_dev *wimax_dev, struct net_device *net_dev)
{
	int result;
	struct device *dev = net_dev->dev.parent;
	char addr_str[32];

	d_fnstart(3, dev, "(wimax_dev %p net_dev %p)\n", wimax_dev, net_dev);

	/* Do the RFKILL setup before locking, as RFKILL will call
	 * into our functions. */
	wimax_dev->net_dev = net_dev;
	result = wimax_rfkill_add(wimax_dev);
	if (result < 0)
		goto error_rfkill_add;

	/* Set up user-space interaction */
	mutex_lock(&wimax_dev->mutex);
	wimax_id_table_add(wimax_dev);
	result = wimax_debugfs_add(wimax_dev);
	if (result < 0) {
		dev_err(dev, "cannot initialize debugfs: %d\n",
			result);
		goto error_debugfs_add;
	}

	__wimax_state_set(wimax_dev, WIMAX_ST_DOWN);
	mutex_unlock(&wimax_dev->mutex);

	wimax_addr_scnprint(addr_str, sizeof(addr_str),
			    net_dev->dev_addr, net_dev->addr_len);
	dev_err(dev, "WiMAX interface %s (%s) ready\n",
		net_dev->name, addr_str);
	d_fnend(3, dev, "(wimax_dev %p net_dev %p) = 0\n", wimax_dev, net_dev);
	return 0;

error_debugfs_add:
	wimax_id_table_rm(wimax_dev);
	mutex_unlock(&wimax_dev->mutex);
	wimax_rfkill_rm(wimax_dev);
error_rfkill_add:
	d_fnend(3, dev, "(wimax_dev %p net_dev %p) = %d\n",
		wimax_dev, net_dev, result);
	return result;
}
Пример #24
0
/**
 * Control the software RF Kill switch and obtain switch status
 *
 * \param wmx WiMAX device handle
 *
 * \param state State to which you want to toggle the sofware RF Kill
 *     switch (%WIMAX_RF_ON, %WIMAX_RF_OFF or %WIMAX_RF_QUERY for just
 *     querying the current state of the hardware and software
 *     switches).
 *
 * \return Negative errno code on error. Otherwise, radio kill switch
 *     status (bit 0 \e hw switch, bit 1 \e sw switch, \e 0 OFF, \e 1
 *     ON):
 *     - 3 @c 0b11: Both HW and SW switches are \e on, radio is \e on
 *     - 2 @c 0b10: HW switch is \e off, radio is \e off
 *     - 1 @c 0b01: SW switch is \e on, radio is \e off
 *     - 0 @c 0b00: Both HW and SW switches are \e off, radio is \e off
 *
 * Allows the caller to control the state of the software RF Kill
 * switch (if present) and in return, obtain the current status of
 * both the hardware and software RF Kill switches.
 *
 * If there is no hardware or software switch, that switch is assumed
 * to be always on (radio on).
 *
 * Changing the radio state might cause the device to change state,
 * and cause the kernel to send reports indicating so.
 *
 * \note The state of the radio (\e ON or \e OFF) is the inverse of
 *       the state of the RF-Kill switch (\e enabled/on kills the
 *       radio, radio \e off; \e disabled/off allows the radio to
 *       work, radio \e on).
 *
 * \ingroup device_management
 * \internal
 *
 * This implementation simply marshalls the call to the kernel's
 * wimax_rfkill() and returns it's return code.
 */
int wimaxll_rfkill(struct wimaxll_handle *wmx, enum wimax_rf_state state)
{
	ssize_t result;
	struct nl_msg *msg;

	d_fnstart(3, wmx, "(wmx %p state %u)\n", wmx, state);
	result = -EBADF;
	if (wmx->ifidx == 0)
		goto error_not_any;
	msg = nlmsg_new();
	if (msg == NULL) {
		result = errno;
		wimaxll_msg(wmx, "E: RFKILL: cannot allocate generic netlink "
			  "message: %m\n");
		goto error_msg_alloc;
	}
	if (genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ,
			wimaxll_family_id(wmx), 0, 0,
			WIMAX_GNL_OP_RFKILL, WIMAX_GNL_VERSION) == NULL) {
		result = -ENOMEM;
		wimaxll_msg(wmx, "E: RFKILL: error preparing message: "
			  "%zd 0x%08x\n", result, (unsigned int) result);
		goto error_msg_prep;
	}
	nla_put_u32(msg, WIMAX_GNL_RFKILL_IFIDX, (__u32) wmx->ifidx);
	nla_put_u32(msg, WIMAX_GNL_RFKILL_STATE, (__u32) state);
	result = nl_send_auto_complete(wmx->nlh_tx, msg);
	if (result < 0) {
		wimaxll_msg(wmx, "E: RFKILL: error sending message: %zd\n",
			  result);
		goto error_msg_send;
	}
	/* Read the message ACK from netlink */
	result = wimaxll_wait_for_ack(wmx);
	if (result < 0 && result != -ENODEV)
		wimaxll_msg(wmx, "E: RFKILL: operation failed: %zd\n", result);
error_msg_prep:
error_msg_send:
	nlmsg_free(msg);
error_msg_alloc:
error_not_any:
	d_fnend(3, wmx, "(wmx %p state %u) = %zd\n", wmx, state, result);
	return result;
}
Пример #25
0
/*
 * setup the notification endpoint
 *
 * @i2400m: device descriptor
 *
 * This procedure prepares the notification urb and handler for receiving
 * unsolicited barkers from the device.
 */
int i2400mu_notification_setup(struct i2400mu *i2400mu)
{
	struct device *dev = &i2400mu->usb_iface->dev;
	int usb_pipe, ret = 0;
	struct usb_endpoint_descriptor *epd;
	char *buf;

	d_fnstart(4, dev, "(i2400m %p)\n", i2400mu);
	buf = kmalloc(I2400MU_MAX_NOTIFICATION_LEN, GFP_KERNEL | GFP_DMA);
	if (buf == NULL) {
		dev_err(dev, "notification: buffer allocation failed\n");
		ret = -ENOMEM;
		goto error_buf_alloc;
	}

	i2400mu->notif_urb = usb_alloc_urb(0, GFP_KERNEL);
	if (!i2400mu->notif_urb) {
		ret = -ENOMEM;
		dev_err(dev, "notification: cannot allocate URB\n");
		goto error_alloc_urb;
	}
	epd = usb_get_epd(i2400mu->usb_iface,
			  i2400mu->endpoint_cfg.notification);
	usb_pipe = usb_rcvintpipe(i2400mu->usb_dev, epd->bEndpointAddress);
	usb_fill_int_urb(i2400mu->notif_urb, i2400mu->usb_dev, usb_pipe,
			 buf, I2400MU_MAX_NOTIFICATION_LEN,
			 i2400mu_notification_cb, i2400mu, epd->bInterval);
	ret = usb_submit_urb(i2400mu->notif_urb, GFP_KERNEL);
	if (ret != 0) {
		dev_err(dev, "notification: cannot submit URB: %d\n", ret);
		goto error_submit;
	}
	d_fnend(4, dev, "(i2400m %p) = %d\n", i2400mu, ret);
	return ret;

error_submit:
	usb_free_urb(i2400mu->notif_urb);
error_alloc_urb:
	kfree(buf);
error_buf_alloc:
	d_fnend(4, dev, "(i2400m %p) = %d\n", i2400mu, ret);
	return ret;
}
Пример #26
0
/*
 * Parse a 'state report' and extract information
 *
 * @i2400m: device descriptor
 * @l3l4_hdr: pointer to message; it has been already validated for
 *            consistent size.
 * @size: size of the message (header + payload). The header length
 *        declaration is assumed to be congruent with @size (as in
 *        sizeof(*l3l4_hdr) + l3l4_hdr->length == size)
 *
 * Walk over the TLVs in a report state and act on them.
 */
static
void i2400m_report_state_hook(struct i2400m *i2400m,
			      const struct i2400m_l3l4_hdr *l3l4_hdr,
			      size_t size, const char *tag)
{
	struct device *dev = i2400m_dev(i2400m);
	const struct i2400m_tlv_hdr *tlv;
	size_t tlv_size = le16_to_cpu(l3l4_hdr->length);

	d_fnstart(4, dev, "(i2400m %p, l3l4_hdr %p, size %zu, %s)\n",
		  i2400m, l3l4_hdr, size, tag);
	tlv = NULL;

	while ((tlv = i2400m_tlv_buffer_walk(i2400m, &l3l4_hdr->pl,
					     tlv_size, tlv)))
		i2400m_report_state_parse_tlv(i2400m, tlv, tag);
	d_fnend(4, dev, "(i2400m %p, l3l4_hdr %p, size %zu, %s) = void\n",
		i2400m, l3l4_hdr, size, tag);
}
Пример #27
0
static
int i2400m_open(struct net_device *net_dev)
{
	int result;
	struct i2400m *i2400m = net_dev_to_i2400m(net_dev);
	struct device *dev = i2400m_dev(i2400m);

	d_fnstart(3, dev, "(net_dev %p [i2400m %p])\n", net_dev, i2400m);
	/* Make sure we wait until init is complete... */
	mutex_lock(&i2400m->init_mutex);
	if (i2400m->updown)
		result = 0;
	else
		result = -EBUSY;
	mutex_unlock(&i2400m->init_mutex);
	d_fnend(3, dev, "(net_dev %p [i2400m %p]) = %d\n",
		net_dev, i2400m, result);
	return result;
}
Пример #28
0
/*
 * TX an skb to an idle device
 *
 * When the device is in basestation-idle mode, we need to wake it up
 * and then TX. So we queue a work_struct for doing so.
 *
 * We need to get an extra ref for the skb (so it is not dropped), as
 * well as be careful not to queue more than one request (won't help
 * at all). If more than one request comes or there are errors, we
 * just drop the packets (see i2400m_hard_start_xmit()).
 */
static
int i2400m_net_wake_tx(struct i2400m *i2400m, struct net_device *net_dev,
		       struct sk_buff *skb)
{
	int result;
	struct device *dev = i2400m_dev(i2400m);
	unsigned long flags;

	d_fnstart(3, dev, "(skb %p net_dev %p)\n", skb, net_dev);
	if (net_ratelimit()) {
		d_printf(3, dev, "WAKE&NETTX: "
			 "skb %p sending %d bytes to radio\n",
			 skb, skb->len);
		d_dump(4, dev, skb->data, skb->len);
	}
	/* We hold a ref count for i2400m and skb, so when
	 * stopping() the device, we need to cancel that work
	 * and if pending, release those resources. */
	result = 0;
	spin_lock_irqsave(&i2400m->tx_lock, flags);
	if (!i2400m->wake_tx_skb) {
		netif_stop_queue(net_dev);
		i2400m_get(i2400m);
		i2400m->wake_tx_skb = skb_get(skb);	/* transfer ref count */
		i2400m_tx_prep_header(skb);
		result = schedule_work(&i2400m->wake_tx_ws);
		WARN_ON(result == 0);
	}
	spin_unlock_irqrestore(&i2400m->tx_lock, flags);
	if (result == 0) {
		/* Yes, this happens even if we stopped the
		 * queue -- blame the queue disciplines that
		 * queue without looking -- I guess there is a reason
		 * for that. */
		if (net_ratelimit())
			d_printf(1, dev, "NETTX: device exiting idle, "
				 "dropping skb %p, queue running %d\n",
				 skb, netif_queue_stopped(net_dev));
		result = -EBUSY;
	}
	d_fnend(3, dev, "(skb %p net_dev %p) = %d\n", skb, net_dev, result);
	return result;
}
Пример #29
0
static
int i2400mu_txd(void *_i2400mu)
{
	struct i2400mu *i2400mu = _i2400mu;
	struct i2400m *i2400m = &i2400mu->i2400m;
	struct device *dev = &i2400mu->usb_iface->dev;
	struct i2400m_msg_hdr *tx_msg;
	size_t tx_msg_size;
	unsigned long flags;

	d_fnstart(4, dev, "(i2400mu %p)\n", i2400mu);

	spin_lock_irqsave(&i2400m->tx_lock, flags);
	BUG_ON(i2400mu->tx_kthread != NULL);
	i2400mu->tx_kthread = current;
	spin_unlock_irqrestore(&i2400m->tx_lock, flags);

	while (1) {
		d_printf(2, dev, "TX: waiting for messages\n");
		tx_msg = NULL;
		wait_event_interruptible(
			i2400mu->tx_wq,
			(kthread_should_stop()	/*                   */
			 || (tx_msg = i2400m_tx_msg_get(i2400m, &tx_msg_size)))
			);
		if (kthread_should_stop())
			break;
		WARN_ON(tx_msg == NULL);	/*                     */
		d_printf(2, dev, "TX: submitting %zu bytes\n", tx_msg_size);
		d_dump(5, dev, tx_msg, tx_msg_size);
		/*                                               */
		i2400mu_tx(i2400mu, tx_msg, tx_msg_size);
		i2400m_tx_msg_sent(i2400m);	/*                          */
	}

	spin_lock_irqsave(&i2400m->tx_lock, flags);
	i2400mu->tx_kthread = NULL;
	spin_unlock_irqrestore(&i2400m->tx_lock, flags);

	d_fnend(4, dev, "(i2400mu %p)\n", i2400mu);
	return 0;
}
Пример #30
0
/*
 * Transmit a packet to the base station on behalf of the network stack.
 *
 * Returns: 0 if ok, < 0 errno code on error.
 *
 * We need to pull the ethernet header and add the hardware header,
 * which is currently set to all zeroes and reserved.
 */
static
int i2400m_net_tx(struct i2400m *i2400m, struct net_device *net_dev,
		  struct sk_buff *skb)
{
	int result;
	struct device *dev = i2400m_dev(i2400m);

	d_fnstart(3, dev, "(i2400m %p net_dev %p skb %p)\n",
		  i2400m, net_dev, skb);
	/* FIXME: check eth hdr, only IPv4 is routed by the device as of now */
	net_dev->trans_start = jiffies;
	i2400m_tx_prep_header(skb);
	d_printf(3, dev, "NETTX: skb %p sending %d bytes to radio\n",
		 skb, skb->len);
	d_dump(4, dev, skb->data, skb->len);
	result = i2400m_tx(i2400m, skb->data, skb->len, I2400M_PT_DATA);
	d_fnend(3, dev, "(i2400m %p net_dev %p skb %p) = %d\n",
		i2400m, net_dev, skb, result);
	return result;
}