[PATCH, take 2] libertas: rework event subscription

Dan Williams dcbw at redhat.com
Tue Nov 27 11:08:02 EST 2007


On Mon, 2007-11-26 at 10:07 +0100, Holger Schurig wrote:
> This patch moves re-works the implementation of event subscription
> via debugfs. For this:
> 
> * it tells cmd.c and cmdresp.c about CMD_802_11_SUBSCRIBE_EVENT
> * removes lots of low-level cmd stuff from debugfs.c
> * create unified functions to read/write snr, rssi, bcnmiss and
>   failcount
> * introduces #define's for subscription event bitmask values
> * add a function to search for a specific element in an IE
>   (a.k.a. TLV)
> * add a function to find out the size of the TLV. This is needed
>   because lbs_prepare_and_send_command() has an argument for a
>   data buffer, but not for it's lengths and TLVs can be, by
>   definition, vary in size.
> * fix a bug where it was not possible to disable an event
> 
> Signed-off-by: Holger Schurig <hs4233 at mail.mn-solutions.de>

Looks like quite a nice cleanup.

Acked-by: Dan Williams <dcbw at redhat.com>

> ---
> As a side effect, the size of libertas.ko went down:
> 
>  131653    3980       8  135641   211d9 libertas-orig.ko
>  126284    3980       8  130272   1fce0 libertas.ko
> 
> The old code also contained this bug:
> 
> $ cd /sys/kernel/debug/lbs_wireless/eth1
> $ cat failure_count
> 0 0 0
> $ echo 60 1 1 >failure_count
> $ cat failure_count
> 60 1 1
> $ echo 0 0 0 >failure_count
> $ cat failure_count
> 0 0 1
> 
> The new code turns off the proper event bitmask as well, so the
> last "cat" returns "0 0 0".
> 
> 
> Index: wireless-2.6/drivers/net/wireless/libertas/cmd.c
> ===================================================================
> --- wireless-2.6.orig/drivers/net/wireless/libertas/cmd.c	2007-11-26 10:56:45.000000000 +0100
> +++ wireless-2.6/drivers/net/wireless/libertas/cmd.c	2007-11-26 10:58:08.000000000 +0100
> @@ -246,6 +246,52 @@ static int lbs_cmd_802_11_enable_rsn(str
>  }
>  
> 
> +static ssize_t lbs_tlv_size(const u8 *tlv, u16 size)
> +{
> +	ssize_t pos = 0;
> +	struct mrvlietypesheader *tlv_h;
> +	while (pos < size) {
> +		u16 length;
> +		tlv_h = (struct mrvlietypesheader *) tlv;
> +		if (tlv_h->len == 0)
> +			return pos;
> +		length = le16_to_cpu(tlv_h->len) +
> +			sizeof(struct mrvlietypesheader);
> +		pos += length;
> +		tlv += length;
> +	}
> +	return pos;
> +}
> +
> +
> +static void lbs_cmd_802_11_subscribe_event(struct lbs_private *priv,
> +	struct cmd_ds_command *cmd, u16 cmd_action,
> +	void *pdata_buf)
> +{
> +	struct cmd_ds_802_11_subscribe_event *events =
> +		(struct cmd_ds_802_11_subscribe_event *) pdata_buf;
> +
> +	/* pdata_buf points to a struct cmd_ds_802_11_subscribe_event and room
> +	 * for various Marvell TLVs */
> +
> +	lbs_deb_enter(LBS_DEB_CMD);
> +
> +	cmd->size = cpu_to_le16(sizeof(*events)
> +			- sizeof(events->tlv)
> +			+ S_DS_GEN);
> +	cmd->params.subscribe_event.action = cpu_to_le16(cmd_action);
> +	if (cmd_action == CMD_ACT_GET) {
> +		cmd->params.subscribe_event.events = 0;
> +	} else {
> +		ssize_t sz = lbs_tlv_size(events->tlv, sizeof(events->tlv));
> +		cmd->size = cpu_to_le16(le16_to_cpu(cmd->size) + sz);
> +		cmd->params.subscribe_event.events = events->events;
> +		memcpy(cmd->params.subscribe_event.tlv, events->tlv, sz);
> +	}
> +
> +	lbs_deb_leave(LBS_DEB_CMD);
> +}
> +
>  static void set_one_wpa_key(struct MrvlIEtype_keyParamSet * pkeyparamset,
>                              struct enc_key * pkey)
>  {
> @@ -1372,6 +1418,10 @@ int lbs_prepare_and_send_command(struct 
>  			ret = 0;
>  			break;
>  		}
> +	case CMD_802_11_SUBSCRIBE_EVENT:
> +		lbs_cmd_802_11_subscribe_event(priv, cmdptr,
> +			cmd_action, pdata_buf);
> +		break;
>  	case CMD_802_11_PWR_CFG:
>  		cmdptr->command = cpu_to_le16(CMD_802_11_PWR_CFG);
>  		cmdptr->size =
> Index: wireless-2.6/drivers/net/wireless/libertas/cmdresp.c
> ===================================================================
> --- wireless-2.6.orig/drivers/net/wireless/libertas/cmdresp.c	2007-11-26 10:56:45.000000000 +0100
> +++ wireless-2.6/drivers/net/wireless/libertas/cmdresp.c	2007-11-26 11:02:00.000000000 +0100
> @@ -536,6 +536,26 @@ static int lbs_ret_802_11_enable_rsn(str
>  	return 0;
>  }
>  
> +static int lbs_ret_802_11_subscribe_event(struct lbs_private *priv,
> +	struct cmd_ds_command *resp)
> +{
> +	struct lbs_adapter *adapter = priv->adapter;
> +	struct cmd_ds_802_11_subscribe_event *cmd_event =
> +		&resp->params.subscribe_event;
> +	struct cmd_ds_802_11_subscribe_event *dst_event =
> +		adapter->cur_cmd->pdata_buf;
> +
> +	lbs_deb_enter(LBS_DEB_CMD);
> +
> +	if (dst_event->action == cpu_to_le16(CMD_ACT_GET)) {
> +		dst_event->events = le16_to_cpu(cmd_event->events);
> +		memcpy(dst_event->tlv, cmd_event->tlv, sizeof(dst_event->tlv));
> +	}
> +
> +	lbs_deb_leave(LBS_DEB_CMD);
> +	return 0;
> +}
> +
>  static inline int handle_cmd_response(u16 respcmd,
>  				      struct cmd_ds_command *resp,
>  				      struct lbs_private *priv)
> @@ -671,6 +691,10 @@ static inline int handle_cmd_response(u1
>  			sizeof(struct cmd_ds_802_11_led_ctrl));
>  		spin_unlock_irqrestore(&adapter->driver_lock, flags);
>  		break;
> +	case CMD_RET(CMD_802_11_SUBSCRIBE_EVENT):
> +		ret = lbs_ret_802_11_subscribe_event(priv, resp);
> +		break;
> +
>  	case CMD_RET(CMD_802_11_PWR_CFG):
>  		spin_lock_irqsave(&adapter->driver_lock, flags);
>  		memmove(adapter->cur_cmd->pdata_buf, &resp->params.pwrcfg,
> Index: wireless-2.6/drivers/net/wireless/libertas/debugfs.c
> ===================================================================
> --- wireless-2.6.orig/drivers/net/wireless/libertas/debugfs.c	2007-11-26 10:56:45.000000000 +0100
> +++ wireless-2.6/drivers/net/wireless/libertas/debugfs.c	2007-11-26 10:58:29.000000000 +0100
> @@ -383,524 +383,162 @@ out_unlock:
>  	return count;
>  }
>  
> -static int lbs_event_initcmd(struct lbs_private *priv, void **response_buf,
> -			struct cmd_ctrl_node **cmdnode,
> -			struct cmd_ds_command **cmd)
> -{
> -	u16 wait_option = CMD_OPTION_WAITFORRSP;
> -
> -	if (!(*cmdnode = lbs_get_free_cmd_ctrl_node(priv))) {
> -		lbs_deb_debugfs("failed lbs_get_free_cmd_ctrl_node\n");
> -		return -ENOMEM;
> -	}
> -	if (!(*response_buf = kmalloc(3000, GFP_KERNEL))) {
> -		lbs_deb_debugfs("failed to allocate response buffer!\n");
> -		return -ENOMEM;
> -	}
> -	lbs_set_cmd_ctrl_node(priv, *cmdnode, 0, wait_option, NULL);
> -	init_waitqueue_head(&(*cmdnode)->cmdwait_q);
> -	(*cmdnode)->pdata_buf = *response_buf;
> -	(*cmdnode)->cmdflags |= CMD_F_HOSTCMD;
> -	(*cmdnode)->cmdwaitqwoken = 0;
> -	*cmd = (struct cmd_ds_command *)(*cmdnode)->bufvirtualaddr;
> -	(*cmd)->command = cpu_to_le16(CMD_802_11_SUBSCRIBE_EVENT);
> -	(*cmd)->seqnum = cpu_to_le16(++priv->adapter->seqnum);
> -	(*cmd)->result = 0;
> -	return 0;
> -}
>  
> -static ssize_t lbs_lowrssi_read(struct file *file, char __user *userbuf,
> -				  size_t count, loff_t *ppos)
> +/*
> + * When calling CMD_802_11_SUBSCRIBE_EVENT with CMD_ACT_GET, me might
> + * get a bunch of vendor-specific TLVs (a.k.a. IEs) back from the
> + * firmware. Here's an example:
> + *	04 01 02 00 00 00 05 01 02 00 00 00 06 01 02 00
> + *	00 00 07 01 02 00 3c 00 00 00 00 00 00 00 03 03
> + *	00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
> + *
> + * The 04 01 is the TLV type (here TLV_TYPE_RSSI_LOW), 02 00 is the length,
> + * 00 00 are the data bytes of this TLV. For this TLV, their meaning is
> + * defined in mrvlietypes_thresholds
> + *
> + * This function searches in this TLV data chunk for a given TLV type
> + * and returns a pointer to the first data byte of the TLV, or to NULL
> + * if the TLV hasn't been found.
> + */
> +static void *lbs_tlv_find(u16 tlv_type, const u8 *tlv, u16 size)
>  {
> -	struct lbs_private *priv = file->private_data;
> -	struct lbs_adapter *adapter = priv->adapter;
> -	struct cmd_ctrl_node *pcmdnode;
> -	struct cmd_ds_command *pcmdptr;
> -	struct cmd_ds_802_11_subscribe_event *event;
> -	void *response_buf;
> -	int res, cmd_len;
> +	__le16 le_type = cpu_to_le16(tlv_type);
>  	ssize_t pos = 0;
> -	unsigned long addr = get_zeroed_page(GFP_KERNEL);
> -	char *buf = (char *)addr;
> -
> -	res = lbs_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
> -	if (res < 0) {
> -		free_page(addr);
> -		return res;
> -	}
> -
> -	event = &pcmdptr->params.subscribe_event;
> -	event->action = cpu_to_le16(CMD_ACT_GET);
> -	pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
> -	lbs_queue_cmd(adapter, pcmdnode, 1);
> -	wake_up_interruptible(&priv->waitq);
> -
> -	/* Sleep until response is generated by FW */
> -	wait_event_interruptible(pcmdnode->cmdwait_q,
> -				 pcmdnode->cmdwaitqwoken);
> -
> -	pcmdptr = response_buf;
> -	if (pcmdptr->result) {
> -		lbs_pr_err("%s: fail, result=%d\n", __func__,
> -			   le16_to_cpu(pcmdptr->result));
> -		kfree(response_buf);
> -		free_page(addr);
> -		return 0;
> -	}
> -
> -	if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
> -		lbs_pr_err("command response incorrect!\n");
> -		kfree(response_buf);
> -		free_page(addr);
> -		return 0;
> -	}
> -
> -	cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
> -	event = (void *)(response_buf + S_DS_GEN);
> -	while (cmd_len < le16_to_cpu(pcmdptr->size)) {
> -		struct mrvlietypesheader *header = (void *)(response_buf + cmd_len);
> -		switch (header->type) {
> -		struct mrvlietypes_rssithreshold  *Lowrssi;
> -		case __constant_cpu_to_le16(TLV_TYPE_RSSI_LOW):
> -			Lowrssi = (void *)(response_buf + cmd_len);
> -			pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
> -					Lowrssi->rssivalue,
> -					Lowrssi->rssifreq,
> -					(event->events & cpu_to_le16(0x0001))?1:0);
> -		default:
> -			cmd_len += sizeof(struct mrvlietypes_snrthreshold);
> -			break;
> -		}
> +	struct mrvlietypesheader *tlv_h;
> +	while (pos < size) {
> +		u16 length;
> +		tlv_h = (struct mrvlietypesheader *) tlv;
> +		if (tlv_h->type == le_type)
> +			return tlv_h;
> +		if (tlv_h->len == 0)
> +			return NULL;
> +		length = le16_to_cpu(tlv_h->len) +
> +			sizeof(struct mrvlietypesheader);
> +		pos += length;
> +		tlv += length;
>  	}
> -
> -	kfree(response_buf);
> -	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
> -	free_page(addr);
> -	return res;
> +	return NULL;
>  }
>  
> +
> +/*
> + * This just gets the bitmap of currently subscribed events. Used when
> + * adding an additonal event subscription.
> + */
>  static u16 lbs_get_events_bitmap(struct lbs_private *priv)
>  {
> -	struct lbs_adapter *adapter = priv->adapter;
> -	struct cmd_ctrl_node *pcmdnode;
> -	struct cmd_ds_command *pcmdptr;
> -	struct cmd_ds_802_11_subscribe_event *event;
> -	void *response_buf;
> -	int res;
> -	u16 event_bitmap;
> -
> -	res = lbs_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
> -	if (res < 0)
> -		return res;
> -
> -	event = &pcmdptr->params.subscribe_event;
> -	event->action = cpu_to_le16(CMD_ACT_GET);
> -	pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
> -	lbs_queue_cmd(adapter, pcmdnode, 1);
> -	wake_up_interruptible(&priv->waitq);
> -
> -	/* Sleep until response is generated by FW */
> -	wait_event_interruptible(pcmdnode->cmdwait_q,
> -				 pcmdnode->cmdwaitqwoken);
> +	ssize_t res;
>  
> -	pcmdptr = response_buf;
> +	struct cmd_ds_802_11_subscribe_event *events = kzalloc(
> +		sizeof(struct cmd_ds_802_11_subscribe_event),
> +		GFP_KERNEL);
>  
> -	if (pcmdptr->result) {
> -		lbs_pr_err("%s: fail, result=%d\n", __func__,
> -			   le16_to_cpu(pcmdptr->result));
> -		kfree(response_buf);
> -		return 0;
> -	}
> +	res = lbs_prepare_and_send_command(priv,
> +			CMD_802_11_SUBSCRIBE_EVENT, CMD_ACT_GET,
> +			CMD_OPTION_WAITFORRSP, 0, events);
>  
> -	if (le16_to_cpu(pcmdptr->command) != CMD_RET(CMD_802_11_SUBSCRIBE_EVENT)) {
> -		lbs_pr_err("command response incorrect!\n");
> -		kfree(response_buf);
> +	if (res) {
> +		kfree(events);
>  		return 0;
>  	}
> -
> -	event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN);
> -	event_bitmap = le16_to_cpu(event->events);
> -	kfree(response_buf);
> -	return event_bitmap;
> +	return le16_to_cpu(events->events);
>  }
>  
> -static ssize_t lbs_lowrssi_write(struct file *file,
> -				    const char __user *userbuf,
> -				    size_t count, loff_t *ppos)
> -{
> -	struct lbs_private *priv = file->private_data;
> -	struct lbs_adapter *adapter = priv->adapter;
> -	ssize_t res, buf_size;
> -	int value, freq, subscribed, cmd_len;
> -	struct cmd_ctrl_node *pcmdnode;
> -	struct cmd_ds_command *pcmdptr;
> -	struct cmd_ds_802_11_subscribe_event *event;
> -	struct mrvlietypes_rssithreshold *rssi_threshold;
> -	void *response_buf;
> -	u16 event_bitmap;
> -	u8 *ptr;
> -	unsigned long addr = get_zeroed_page(GFP_KERNEL);
> -	char *buf = (char *)addr;
> -
> -	buf_size = min(count, len - 1);
> -	if (copy_from_user(buf, userbuf, buf_size)) {
> -		res = -EFAULT;
> -		goto out_unlock;
> -	}
> -	res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
> -	if (res != 3) {
> -		res = -EFAULT;
> -		goto out_unlock;
> -	}
>  
> -	event_bitmap = lbs_get_events_bitmap(priv);
> -
> -	res = lbs_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
> -	if (res < 0)
> -		goto out_unlock;
> -
> -	event = &pcmdptr->params.subscribe_event;
> -	event->action = cpu_to_le16(CMD_ACT_SET);
> -	pcmdptr->size = cpu_to_le16(S_DS_GEN +
> -		sizeof(struct cmd_ds_802_11_subscribe_event) +
> -		sizeof(struct mrvlietypes_rssithreshold));
> -
> -	cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
> -	ptr = (u8*) pcmdptr+cmd_len;
> -	rssi_threshold = (struct mrvlietypes_rssithreshold *)(ptr);
> -	rssi_threshold->header.type = cpu_to_le16(0x0104);
> -	rssi_threshold->header.len = cpu_to_le16(2);
> -	rssi_threshold->rssivalue = value;
> -	rssi_threshold->rssifreq = freq;
> -	event_bitmap |= subscribed ? 0x0001 : 0x0;
> -	event->events = cpu_to_le16(event_bitmap);
> -
> -	lbs_queue_cmd(adapter, pcmdnode, 1);
> -	wake_up_interruptible(&priv->waitq);
> -
> -	/* Sleep until response is generated by FW */
> -	wait_event_interruptible(pcmdnode->cmdwait_q,
> -				 pcmdnode->cmdwaitqwoken);
> -
> -	pcmdptr = response_buf;
> -
> -	if (pcmdptr->result) {
> -		lbs_pr_err("%s: fail, result=%d\n", __func__,
> -			   le16_to_cpu(pcmdptr->result));
> -		kfree(response_buf);
> -		free_page(addr);
> -		return 0;
> -	}
> -
> -	if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
> -		lbs_pr_err("command response incorrect!\n");
> -		kfree(response_buf);
> -		free_page(addr);
> -		return 0;
> -	}
> -
> -	res = count;
> -out_unlock:
> -	free_page(addr);
> -	return res;
> -}
> -
> -static ssize_t lbs_lowsnr_read(struct file *file, char __user *userbuf,
> -				  size_t count, loff_t *ppos)
> +static ssize_t lbs_threshold_read(
> +	u16 tlv_type, u16 event_mask,
> +	struct file *file, char __user *userbuf,
> +	size_t count, loff_t *ppos)
>  {
>  	struct lbs_private *priv = file->private_data;
> -	struct lbs_adapter *adapter = priv->adapter;
> -	struct cmd_ctrl_node *pcmdnode;
> -	struct cmd_ds_command *pcmdptr;
> -	struct cmd_ds_802_11_subscribe_event *event;
> -	void *response_buf;
> -	int res, cmd_len;
> -	ssize_t pos = 0;
> +	ssize_t res = 0;
> +	size_t pos = 0;
>  	unsigned long addr = get_zeroed_page(GFP_KERNEL);
>  	char *buf = (char *)addr;
> +	u8 value;
> +	u8 freq;
>  
> -	res = lbs_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
> -	if (res < 0) {
> -		free_page(addr);
> -		return res;
> -	}
> -
> -	event = &pcmdptr->params.subscribe_event;
> -	event->action = cpu_to_le16(CMD_ACT_GET);
> -	pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
> -	lbs_queue_cmd(adapter, pcmdnode, 1);
> -	wake_up_interruptible(&priv->waitq);
> -
> -	/* Sleep until response is generated by FW */
> -	wait_event_interruptible(pcmdnode->cmdwait_q,
> -				 pcmdnode->cmdwaitqwoken);
> -
> -	pcmdptr = response_buf;
> -
> -	if (pcmdptr->result) {
> -		lbs_pr_err("%s: fail, result=%d\n", __func__,
> -			   le16_to_cpu(pcmdptr->result));
> -		kfree(response_buf);
> -		free_page(addr);
> -		return 0;
> -	}
> +	struct cmd_ds_802_11_subscribe_event *events = kzalloc(
> +		sizeof(struct cmd_ds_802_11_subscribe_event),
> +		GFP_KERNEL);
> +	struct mrvlietypes_thresholds *got;
>  
> -	if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
> -		lbs_pr_err("command response incorrect!\n");
> -		kfree(response_buf);
> -		free_page(addr);
> -		return 0;
> +	res = lbs_prepare_and_send_command(priv,
> +			CMD_802_11_SUBSCRIBE_EVENT, CMD_ACT_GET,
> +			CMD_OPTION_WAITFORRSP, 0, events);
> +	if (res) {
> +		kfree(events);
> +		return res;
>  	}
>  
> -	cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
> -	event = (void *)(response_buf + S_DS_GEN);
> -	while (cmd_len < le16_to_cpu(pcmdptr->size)) {
> -		struct mrvlietypesheader *header = (void *)(response_buf + cmd_len);
> -		switch (header->type) {
> -		struct mrvlietypes_snrthreshold *LowSnr;
> -		case __constant_cpu_to_le16(TLV_TYPE_SNR_LOW):
> -			LowSnr = (void *)(response_buf + cmd_len);
> -			pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
> -					LowSnr->snrvalue,
> -					LowSnr->snrfreq,
> -					(event->events & cpu_to_le16(0x0002))?1:0);
> -		default:
> -			cmd_len += sizeof(struct mrvlietypes_snrthreshold);
> -			break;
> -		}
> +	got = lbs_tlv_find(tlv_type, events->tlv, sizeof(events->tlv));
> +	if (got) {
> +		value = got->value;
> +		freq  = got->freq;
>  	}
> +	kfree(events);
>  
> -	kfree(response_buf);
> +	if (got)
> +		pos += snprintf(buf, len, "%d %d %d\n", value, freq,
> +			!!(le16_to_cpu(events->events) & event_mask));
>  
>  	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
> -	free_page(addr);
> -	return res;
> -}
> -
> -static ssize_t lbs_lowsnr_write(struct file *file,
> -				    const char __user *userbuf,
> -				    size_t count, loff_t *ppos)
> -{
> -	struct lbs_private *priv = file->private_data;
> -	struct lbs_adapter *adapter = priv->adapter;
> -	ssize_t res, buf_size;
> -	int value, freq, subscribed, cmd_len;
> -	struct cmd_ctrl_node *pcmdnode;
> -	struct cmd_ds_command *pcmdptr;
> -	struct cmd_ds_802_11_subscribe_event *event;
> -	struct mrvlietypes_snrthreshold *snr_threshold;
> -	void *response_buf;
> -	u16 event_bitmap;
> -	u8 *ptr;
> -	unsigned long addr = get_zeroed_page(GFP_KERNEL);
> -	char *buf = (char *)addr;
> -
> -	buf_size = min(count, len - 1);
> -	if (copy_from_user(buf, userbuf, buf_size)) {
> -		res = -EFAULT;
> -		goto out_unlock;
> -	}
> -	res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
> -	if (res != 3) {
> -		res = -EFAULT;
> -		goto out_unlock;
> -	}
> -
> -	event_bitmap = lbs_get_events_bitmap(priv);
>  
> -	res = lbs_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
> -	if (res < 0)
> -		goto out_unlock;
> -
> -	event = &pcmdptr->params.subscribe_event;
> -	event->action = cpu_to_le16(CMD_ACT_SET);
> -	pcmdptr->size = cpu_to_le16(S_DS_GEN +
> -		sizeof(struct cmd_ds_802_11_subscribe_event) +
> -		sizeof(struct mrvlietypes_snrthreshold));
> -	cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
> -	ptr = (u8*) pcmdptr+cmd_len;
> -	snr_threshold = (struct mrvlietypes_snrthreshold *)(ptr);
> -	snr_threshold->header.type = cpu_to_le16(TLV_TYPE_SNR_LOW);
> -	snr_threshold->header.len = cpu_to_le16(2);
> -	snr_threshold->snrvalue = value;
> -	snr_threshold->snrfreq = freq;
> -	event_bitmap |= subscribed ? 0x0002 : 0x0;
> -	event->events = cpu_to_le16(event_bitmap);
> -
> -	lbs_queue_cmd(adapter, pcmdnode, 1);
> -	wake_up_interruptible(&priv->waitq);
> -
> -	/* Sleep until response is generated by FW */
> -	wait_event_interruptible(pcmdnode->cmdwait_q,
> -				 pcmdnode->cmdwaitqwoken);
> -
> -	pcmdptr = response_buf;
> -
> -	if (pcmdptr->result) {
> -		lbs_pr_err("%s: fail, result=%d\n", __func__,
> -			   le16_to_cpu(pcmdptr->result));
> -		kfree(response_buf);
> -		free_page(addr);
> -		return 0;
> -	}
> -
> -	if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
> -		lbs_pr_err("command response incorrect!\n");
> -		kfree(response_buf);
> -		free_page(addr);
> -		return 0;
> -	}
> -
> -	res = count;
> -
> -out_unlock:
>  	free_page(addr);
>  	return res;
>  }
>  
> -static ssize_t lbs_failcount_read(struct file *file, char __user *userbuf,
> -				  size_t count, loff_t *ppos)
> -{
> -	struct lbs_private *priv = file->private_data;
> -	struct lbs_adapter *adapter = priv->adapter;
> -	struct cmd_ctrl_node *pcmdnode;
> -	struct cmd_ds_command *pcmdptr;
> -	struct cmd_ds_802_11_subscribe_event *event;
> -	void *response_buf;
> -	int res, cmd_len;
> -	ssize_t pos = 0;
> -	unsigned long addr = get_zeroed_page(GFP_KERNEL);
> -	char *buf = (char *)addr;
> -
> -	res = lbs_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
> -	if (res < 0) {
> -		free_page(addr);
> -		return res;
> -	}
>  
> -	event = &pcmdptr->params.subscribe_event;
> -	event->action = cpu_to_le16(CMD_ACT_GET);
> -	pcmdptr->size =	cpu_to_le16(sizeof(*event) + S_DS_GEN);
> -	lbs_queue_cmd(adapter, pcmdnode, 1);
> -	wake_up_interruptible(&priv->waitq);
> -
> -	/* Sleep until response is generated by FW */
> -	wait_event_interruptible(pcmdnode->cmdwait_q,
> -				 pcmdnode->cmdwaitqwoken);
> -
> -	pcmdptr = response_buf;
> -
> -	if (pcmdptr->result) {
> -		lbs_pr_err("%s: fail, result=%d\n", __func__,
> -			   le16_to_cpu(pcmdptr->result));
> -		kfree(response_buf);
> -		free_page(addr);
> -		return 0;
> -	}
> -
> -	if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
> -		lbs_pr_err("command response incorrect!\n");
> -		kfree(response_buf);
> -		free_page(addr);
> -		return 0;
> -	}
> -
> -	cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
> -	event = (void *)(response_buf + S_DS_GEN);
> -	while (cmd_len < le16_to_cpu(pcmdptr->size)) {
> -		struct mrvlietypesheader *header = (void *)(response_buf + cmd_len);
> -		switch (header->type) {
> -		struct mrvlietypes_failurecount *failcount;
> -		case __constant_cpu_to_le16(TLV_TYPE_FAILCOUNT):
> -			failcount = (void *)(response_buf + cmd_len);
> -			pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
> -					failcount->failvalue,
> -					failcount->Failfreq,
> -					(event->events & cpu_to_le16(0x0004))?1:0);
> -		default:
> -			cmd_len += sizeof(struct mrvlietypes_failurecount);
> -			break;
> -		}
> -	}
> -
> -	kfree(response_buf);
> -	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
> -	free_page(addr);
> -	return res;
> -}
> -
> -static ssize_t lbs_failcount_write(struct file *file,
> -				    const char __user *userbuf,
> -				    size_t count, loff_t *ppos)
> +static ssize_t lbs_threshold_write(
> +	u16 tlv_type, u16 event_mask,
> +	struct file *file,
> +	const char __user *userbuf,
> +	size_t count, loff_t *ppos)
>  {
>  	struct lbs_private *priv = file->private_data;
> -	struct lbs_adapter *adapter = priv->adapter;
>  	ssize_t res, buf_size;
> -	int value, freq, subscribed, cmd_len;
> -	struct cmd_ctrl_node *pcmdnode;
> -	struct cmd_ds_command *pcmdptr;
> -	struct cmd_ds_802_11_subscribe_event *event;
> -	struct mrvlietypes_failurecount *failcount;
> -	void *response_buf;
> -	u16 event_bitmap;
> -	u8 *ptr;
> +	int value, freq, curr_mask, new_mask;
>  	unsigned long addr = get_zeroed_page(GFP_KERNEL);
>  	char *buf = (char *)addr;
> +	struct cmd_ds_802_11_subscribe_event *events;
>  
>  	buf_size = min(count, len - 1);
>  	if (copy_from_user(buf, userbuf, buf_size)) {
>  		res = -EFAULT;
>  		goto out_unlock;
>  	}
> -	res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
> +	res = sscanf(buf, "%d %d %d", &value, &freq, &new_mask);
>  	if (res != 3) {
>  		res = -EFAULT;
>  		goto out_unlock;
>  	}
> +	curr_mask = lbs_get_events_bitmap(priv);
>  
> -	event_bitmap = lbs_get_events_bitmap(priv);
> -
> -	res = lbs_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
> -	if (res < 0)
> -		goto out_unlock;
> -
> -	event = &pcmdptr->params.subscribe_event;
> -	event->action = cpu_to_le16(CMD_ACT_SET);
> -	pcmdptr->size = cpu_to_le16(S_DS_GEN +
> -		sizeof(struct cmd_ds_802_11_subscribe_event) +
> -		sizeof(struct mrvlietypes_failurecount));
> -	cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
> -	ptr = (u8*) pcmdptr+cmd_len;
> -	failcount = (struct mrvlietypes_failurecount *)(ptr);
> -	failcount->header.type = cpu_to_le16(TLV_TYPE_FAILCOUNT);
> -	failcount->header.len = cpu_to_le16(2);
> -	failcount->failvalue = value;
> -	failcount->Failfreq = freq;
> -	event_bitmap |= subscribed ? 0x0004 : 0x0;
> -	event->events = cpu_to_le16(event_bitmap);
> -
> -	lbs_queue_cmd(adapter, pcmdnode, 1);
> -	wake_up_interruptible(&priv->waitq);
> -
> -	/* Sleep until response is generated by FW */
> -	wait_event_interruptible(pcmdnode->cmdwait_q,
> -				 pcmdnode->cmdwaitqwoken);
> -
> -	pcmdptr = (struct cmd_ds_command *)response_buf;
> -
> -	if (pcmdptr->result) {
> -		lbs_pr_err("%s: fail, result=%d\n", __func__,
> -			   le16_to_cpu(pcmdptr->result));
> -		kfree(response_buf);
> -		free_page(addr);
> -		return 0;
> -	}
> +	if (new_mask)
> +		new_mask = curr_mask | event_mask;
> +	else
> +		new_mask = curr_mask & ~event_mask;
>  
> -	if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
> -		lbs_pr_err("command response incorrect!\n");
> -		kfree(response_buf);
> -		free_page(addr);
> -		return 0;
> +	/* Now everything is set and we can send stuff down to the firmware */
> +	events = kzalloc(
> +		sizeof(struct cmd_ds_802_11_subscribe_event),
> +		GFP_KERNEL);
> +	if (events) {
> +		struct mrvlietypes_thresholds *tlv =
> +			(struct mrvlietypes_thresholds *) 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(struct mrvlietypes_thresholds) -
> +			sizeof(struct mrvlietypesheader));
> +		tlv->value = value;
> +		if (tlv_type != TLV_TYPE_BCNMISS)
> +			tlv->freq = freq;
> +		lbs_prepare_and_send_command(priv,
> +			CMD_802_11_SUBSCRIBE_EVENT, CMD_ACT_SET,
> +			CMD_OPTION_WAITFORRSP, 0, events);
> +		kfree(events);
>  	}
>  
>  	res = count;
> @@ -909,457 +547,119 @@ out_unlock:
>  	return res;
>  }
>  
> -static ssize_t lbs_bcnmiss_read(struct file *file, char __user *userbuf,
> -				  size_t count, loff_t *ppos)
> -{
> -	struct lbs_private *priv = file->private_data;
> -	struct lbs_adapter *adapter = priv->adapter;
> -	struct cmd_ctrl_node *pcmdnode;
> -	struct cmd_ds_command *pcmdptr;
> -	struct cmd_ds_802_11_subscribe_event *event;
> -	void *response_buf;
> -	int res, cmd_len;
> -	ssize_t pos = 0;
> -	unsigned long addr = get_zeroed_page(GFP_KERNEL);
> -	char *buf = (char *)addr;
> -
> -	res = lbs_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
> -	if (res < 0) {
> -		free_page(addr);
> -		return res;
> -	}
> -
> -	event = &pcmdptr->params.subscribe_event;
> -	event->action = cpu_to_le16(CMD_ACT_GET);
> -	pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
> -	lbs_queue_cmd(adapter, pcmdnode, 1);
> -	wake_up_interruptible(&priv->waitq);
> -
> -	/* Sleep until response is generated by FW */
> -	wait_event_interruptible(pcmdnode->cmdwait_q,
> -				 pcmdnode->cmdwaitqwoken);
> -
> -	pcmdptr = response_buf;
> -
> -	if (pcmdptr->result) {
> -		lbs_pr_err("%s: fail, result=%d\n", __func__,
> -			   le16_to_cpu(pcmdptr->result));
> -		free_page(addr);
> -		kfree(response_buf);
> -		return 0;
> -	}
> -
> -	if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
> -		lbs_pr_err("command response incorrect!\n");
> -		free_page(addr);
> -		kfree(response_buf);
> -		return 0;
> -	}
> -
> -	cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
> -	event = (void *)(response_buf + S_DS_GEN);
> -	while (cmd_len < le16_to_cpu(pcmdptr->size)) {
> -		struct mrvlietypesheader *header = (void *)(response_buf + cmd_len);
> -		switch (header->type) {
> -		struct mrvlietypes_beaconsmissed *bcnmiss;
> -		case __constant_cpu_to_le16(TLV_TYPE_BCNMISS):
> -			bcnmiss = (void *)(response_buf + cmd_len);
> -			pos += snprintf(buf+pos, len-pos, "%d N/A %d\n",
> -					bcnmiss->beaconmissed,
> -					(event->events & cpu_to_le16(0x0008))?1:0);
> -		default:
> -			cmd_len += sizeof(struct mrvlietypes_beaconsmissed);
> -			break;
> -		}
> -	}
>  
> -	kfree(response_buf);
> -
> -	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
> -	free_page(addr);
> -	return res;
> -}
> -
> -static ssize_t lbs_bcnmiss_write(struct file *file,
> -				    const char __user *userbuf,
> -				    size_t count, loff_t *ppos)
> +static ssize_t lbs_lowrssi_read(
> +	struct file *file, char __user *userbuf,
> +	size_t count, loff_t *ppos)
>  {
> -	struct lbs_private *priv = file->private_data;
> -	struct lbs_adapter *adapter = priv->adapter;
> -	ssize_t res, buf_size;
> -	int value, freq, subscribed, cmd_len;
> -	struct cmd_ctrl_node *pcmdnode;
> -	struct cmd_ds_command *pcmdptr;
> -	struct cmd_ds_802_11_subscribe_event *event;
> -	struct mrvlietypes_beaconsmissed *bcnmiss;
> -	void *response_buf;
> -	u16 event_bitmap;
> -	u8 *ptr;
> -	unsigned long addr = get_zeroed_page(GFP_KERNEL);
> -	char *buf = (char *)addr;
> -
> -	buf_size = min(count, len - 1);
> -	if (copy_from_user(buf, userbuf, buf_size)) {
> -		res = -EFAULT;
> -		goto out_unlock;
> -	}
> -	res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
> -	if (res != 3) {
> -		res = -EFAULT;
> -		goto out_unlock;
> -	}
> -
> -	event_bitmap = lbs_get_events_bitmap(priv);
> -
> -	res = lbs_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
> -	if (res < 0)
> -		goto out_unlock;
> -
> -	event = &pcmdptr->params.subscribe_event;
> -	event->action = cpu_to_le16(CMD_ACT_SET);
> -	pcmdptr->size = cpu_to_le16(S_DS_GEN +
> -		sizeof(struct cmd_ds_802_11_subscribe_event) +
> -		sizeof(struct mrvlietypes_beaconsmissed));
> -	cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
> -	ptr = (u8*) pcmdptr+cmd_len;
> -	bcnmiss = (struct mrvlietypes_beaconsmissed *)(ptr);
> -	bcnmiss->header.type = cpu_to_le16(TLV_TYPE_BCNMISS);
> -	bcnmiss->header.len = cpu_to_le16(2);
> -	bcnmiss->beaconmissed = value;
> -	event_bitmap |= subscribed ? 0x0008 : 0x0;
> -	event->events = cpu_to_le16(event_bitmap);
> -
> -	lbs_queue_cmd(adapter, pcmdnode, 1);
> -	wake_up_interruptible(&priv->waitq);
> -
> -	/* Sleep until response is generated by FW */
> -	wait_event_interruptible(pcmdnode->cmdwait_q,
> -				 pcmdnode->cmdwaitqwoken);
> -
> -	pcmdptr = response_buf;
> -
> -	if (pcmdptr->result) {
> -		lbs_pr_err("%s: fail, result=%d\n", __func__,
> -			   le16_to_cpu(pcmdptr->result));
> -		kfree(response_buf);
> -		free_page(addr);
> -		return 0;
> -	}
> -
> -	if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
> -		lbs_pr_err("command response incorrect!\n");
> -		free_page(addr);
> -		kfree(response_buf);
> -		return 0;
> -	}
> -
> -	res = count;
> -out_unlock:
> -	free_page(addr);
> -	return res;
> +	return lbs_threshold_read(TLV_TYPE_RSSI_LOW, CMD_SUBSCRIBE_RSSI_LOW,
> +		file, userbuf, count, ppos);
>  }
>  
> -static ssize_t lbs_highrssi_read(struct file *file, char __user *userbuf,
> -				  size_t count, loff_t *ppos)
> -{
> -	struct lbs_private *priv = file->private_data;
> -	struct lbs_adapter *adapter = priv->adapter;
> -	struct cmd_ctrl_node *pcmdnode;
> -	struct cmd_ds_command *pcmdptr;
> -	struct cmd_ds_802_11_subscribe_event *event;
> -	void *response_buf;
> -	int res, cmd_len;
> -	ssize_t pos = 0;
> -	unsigned long addr = get_zeroed_page(GFP_KERNEL);
> -	char *buf = (char *)addr;
> -
> -	res = lbs_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
> -	if (res < 0) {
> -		free_page(addr);
> -		return res;
> -	}
> -
> -	event = &pcmdptr->params.subscribe_event;
> -	event->action = cpu_to_le16(CMD_ACT_GET);
> -	pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
> -	lbs_queue_cmd(adapter, pcmdnode, 1);
> -	wake_up_interruptible(&priv->waitq);
> -
> -	/* Sleep until response is generated by FW */
> -	wait_event_interruptible(pcmdnode->cmdwait_q,
> -				 pcmdnode->cmdwaitqwoken);
> -
> -	pcmdptr = response_buf;
> -
> -	if (pcmdptr->result) {
> -		lbs_pr_err("%s: fail, result=%d\n", __func__,
> -			   le16_to_cpu(pcmdptr->result));
> -		kfree(response_buf);
> -		free_page(addr);
> -		return 0;
> -	}
> -
> -	if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
> -		lbs_pr_err("command response incorrect!\n");
> -		kfree(response_buf);
> -		free_page(addr);
> -		return 0;
> -	}
>  
> -	cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
> -	event = (void *)(response_buf + S_DS_GEN);
> -	while (cmd_len < le16_to_cpu(pcmdptr->size)) {
> -		struct mrvlietypesheader *header = (void *)(response_buf + cmd_len);
> -		switch (header->type) {
> -		struct mrvlietypes_rssithreshold  *Highrssi;
> -		case __constant_cpu_to_le16(TLV_TYPE_RSSI_HIGH):
> -			Highrssi = (void *)(response_buf + cmd_len);
> -			pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
> -					Highrssi->rssivalue,
> -					Highrssi->rssifreq,
> -					(event->events & cpu_to_le16(0x0010))?1:0);
> -		default:
> -			cmd_len += sizeof(struct mrvlietypes_snrthreshold);
> -			break;
> -		}
> -	}
> -
> -	kfree(response_buf);
> -
> -	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
> -	free_page(addr);
> -	return res;
> -}
> -
> -static ssize_t lbs_highrssi_write(struct file *file,
> -				    const char __user *userbuf,
> -				    size_t count, loff_t *ppos)
> +static ssize_t lbs_lowrssi_write(
> +	struct file *file, const char __user *userbuf,
> +	size_t count, loff_t *ppos)
>  {
> -	struct lbs_private *priv = file->private_data;
> -	struct lbs_adapter *adapter = priv->adapter;
> -	ssize_t res, buf_size;
> -	int value, freq, subscribed, cmd_len;
> -	struct cmd_ctrl_node *pcmdnode;
> -	struct cmd_ds_command *pcmdptr;
> -	struct cmd_ds_802_11_subscribe_event *event;
> -	struct mrvlietypes_rssithreshold *rssi_threshold;
> -	void *response_buf;
> -	u16 event_bitmap;
> -	u8 *ptr;
> -	unsigned long addr = get_zeroed_page(GFP_KERNEL);
> -	char *buf = (char *)addr;
> -
> -	buf_size = min(count, len - 1);
> -	if (copy_from_user(buf, userbuf, buf_size)) {
> -		res = -EFAULT;
> -		goto out_unlock;
> -	}
> -	res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
> -	if (res != 3) {
> -		res = -EFAULT;
> -		goto out_unlock;
> -	}
> -
> -	event_bitmap = lbs_get_events_bitmap(priv);
> -
> -	res = lbs_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
> -	if (res < 0)
> -		goto out_unlock;
> -
> -	event = &pcmdptr->params.subscribe_event;
> -	event->action = cpu_to_le16(CMD_ACT_SET);
> -	pcmdptr->size = cpu_to_le16(S_DS_GEN +
> -		sizeof(struct cmd_ds_802_11_subscribe_event) +
> -		sizeof(struct mrvlietypes_rssithreshold));
> -	cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
> -	ptr = (u8*) pcmdptr+cmd_len;
> -	rssi_threshold = (struct mrvlietypes_rssithreshold *)(ptr);
> -	rssi_threshold->header.type = cpu_to_le16(TLV_TYPE_RSSI_HIGH);
> -	rssi_threshold->header.len = cpu_to_le16(2);
> -	rssi_threshold->rssivalue = value;
> -	rssi_threshold->rssifreq = freq;
> -	event_bitmap |= subscribed ? 0x0010 : 0x0;
> -	event->events = cpu_to_le16(event_bitmap);
> +	return lbs_threshold_write(TLV_TYPE_RSSI_LOW, CMD_SUBSCRIBE_RSSI_LOW,
> +		file, userbuf, count, ppos);
> +}
>  
> -	lbs_queue_cmd(adapter, pcmdnode, 1);
> -	wake_up_interruptible(&priv->waitq);
>  
> -	/* Sleep until response is generated by FW */
> -	wait_event_interruptible(pcmdnode->cmdwait_q,
> -				 pcmdnode->cmdwaitqwoken);
> +static ssize_t lbs_lowsnr_read(
> +	struct file *file, char __user *userbuf,
> +	size_t count, loff_t *ppos)
> +{
> +	return lbs_threshold_read(TLV_TYPE_SNR_LOW, CMD_SUBSCRIBE_SNR_LOW,
> +		file, userbuf, count, ppos);
> +}
>  
> -	pcmdptr = response_buf;
>  
> -	if (pcmdptr->result) {
> -		lbs_pr_err("%s: fail, result=%d\n", __func__,
> -			   le16_to_cpu(pcmdptr->result));
> -		kfree(response_buf);
> -		return 0;
> -	}
> +static ssize_t lbs_lowsnr_write(
> +	struct file *file, const char __user *userbuf,
> +	size_t count, loff_t *ppos)
> +{
> +	return lbs_threshold_write(TLV_TYPE_SNR_LOW, CMD_SUBSCRIBE_SNR_LOW,
> +		file, userbuf, count, ppos);
> +}
>  
> -	if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
> -		lbs_pr_err("command response incorrect!\n");
> -		kfree(response_buf);
> -		return 0;
> -	}
>  
> -	res = count;
> -out_unlock:
> -	free_page(addr);
> -	return res;
> +static ssize_t lbs_failcount_read(
> +	struct file *file, char __user *userbuf,
> +	size_t count, loff_t *ppos)
> +{
> +	return lbs_threshold_read(TLV_TYPE_FAILCOUNT, CMD_SUBSCRIBE_FAILCOUNT,
> +		file, userbuf, count, ppos);
>  }
>  
> -static ssize_t lbs_highsnr_read(struct file *file, char __user *userbuf,
> -				  size_t count, loff_t *ppos)
> -{
> -	struct lbs_private *priv = file->private_data;
> -	struct lbs_adapter *adapter = priv->adapter;
> -	struct cmd_ctrl_node *pcmdnode;
> -	struct cmd_ds_command *pcmdptr;
> -	struct cmd_ds_802_11_subscribe_event *event;
> -	void *response_buf;
> -	int res, cmd_len;
> -	ssize_t pos = 0;
> -	unsigned long addr = get_zeroed_page(GFP_KERNEL);
> -	char *buf = (char *)addr;
>  
> -	res = lbs_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
> -	if (res < 0) {
> -		free_page(addr);
> -		return res;
> -	}
> +static ssize_t lbs_failcount_write(
> +	struct file *file, const char __user *userbuf,
> +	size_t count, loff_t *ppos)
> +{
> +	return lbs_threshold_write(TLV_TYPE_FAILCOUNT, CMD_SUBSCRIBE_FAILCOUNT,
> +		file, userbuf, count, ppos);
> +}
>  
> -	event = &pcmdptr->params.subscribe_event;
> -	event->action = cpu_to_le16(CMD_ACT_GET);
> -	pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
> -	lbs_queue_cmd(adapter, pcmdnode, 1);
> -	wake_up_interruptible(&priv->waitq);
>  
> -	/* Sleep until response is generated by FW */
> -	wait_event_interruptible(pcmdnode->cmdwait_q,
> -				 pcmdnode->cmdwaitqwoken);
> +static ssize_t lbs_highrssi_read(
> +	struct file *file, char __user *userbuf,
> +	size_t count, loff_t *ppos)
> +{
> +	return lbs_threshold_read(TLV_TYPE_RSSI_HIGH, CMD_SUBSCRIBE_RSSI_HIGH,
> +		file, userbuf, count, ppos);
> +}
>  
> -	pcmdptr = response_buf;
>  
> -	if (pcmdptr->result) {
> -		lbs_pr_err("%s: fail, result=%d\n", __func__,
> -			   le16_to_cpu(pcmdptr->result));
> -		kfree(response_buf);
> -		free_page(addr);
> -		return 0;
> -	}
> +static ssize_t lbs_highrssi_write(
> +	struct file *file, const char __user *userbuf,
> +	size_t count, loff_t *ppos)
> +{
> +	return lbs_threshold_write(TLV_TYPE_RSSI_HIGH, CMD_SUBSCRIBE_RSSI_HIGH,
> +		file, userbuf, count, ppos);
> +}
>  
> -	if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
> -		lbs_pr_err("command response incorrect!\n");
> -		kfree(response_buf);
> -		free_page(addr);
> -		return 0;
> -	}
>  
> -	cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
> -	event = (void *)(response_buf + S_DS_GEN);
> -	while (cmd_len < le16_to_cpu(pcmdptr->size)) {
> -		struct mrvlietypesheader *header = (void *)(response_buf + cmd_len);
> -		switch (header->type) {
> -		struct mrvlietypes_snrthreshold *HighSnr;
> -		case __constant_cpu_to_le16(TLV_TYPE_SNR_HIGH):
> -			HighSnr = (void *)(response_buf + cmd_len);
> -			pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
> -					HighSnr->snrvalue,
> -					HighSnr->snrfreq,
> -					(event->events & cpu_to_le16(0x0020))?1:0);
> -		default:
> -			cmd_len += sizeof(struct mrvlietypes_snrthreshold);
> -			break;
> -		}
> -	}
> +static ssize_t lbs_highsnr_read(
> +	struct file *file, char __user *userbuf,
> +	size_t count, loff_t *ppos)
> +{
> +	return lbs_threshold_read(TLV_TYPE_SNR_HIGH, CMD_SUBSCRIBE_SNR_HIGH,
> +		file, userbuf, count, ppos);
> +}
>  
> -	kfree(response_buf);
>  
> -	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
> -	free_page(addr);
> -	return res;
> +static ssize_t lbs_highsnr_write(
> +	struct file *file, const char __user *userbuf,
> +	size_t count, loff_t *ppos)
> +{
> +	return lbs_threshold_write(TLV_TYPE_SNR_HIGH, CMD_SUBSCRIBE_SNR_HIGH,
> +		file, userbuf, count, ppos);
>  }
>  
> -static ssize_t lbs_highsnr_write(struct file *file,
> -				    const char __user *userbuf,
> -				    size_t count, loff_t *ppos)
> +static ssize_t lbs_bcnmiss_read(
> +	struct file *file, char __user *userbuf,
> +	size_t count, loff_t *ppos)
>  {
> -	struct lbs_private *priv = file->private_data;
> -	struct lbs_adapter *adapter = priv->adapter;
> -	ssize_t res, buf_size;
> -	int value, freq, subscribed, cmd_len;
> -	struct cmd_ctrl_node *pcmdnode;
> -	struct cmd_ds_command *pcmdptr;
> -	struct cmd_ds_802_11_subscribe_event *event;
> -	struct mrvlietypes_snrthreshold *snr_threshold;
> -	void *response_buf;
> -	u16 event_bitmap;
> -	u8 *ptr;
> -	unsigned long addr = get_zeroed_page(GFP_KERNEL);
> -	char *buf = (char *)addr;
> -
> -	buf_size = min(count, len - 1);
> -	if (copy_from_user(buf, userbuf, buf_size)) {
> -		res = -EFAULT;
> -		goto out_unlock;
> -	}
> -	res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
> -	if (res != 3) {
> -		res = -EFAULT;
> -		goto out_unlock;
> -	}
> +	return lbs_threshold_read(TLV_TYPE_BCNMISS, CMD_SUBSCRIBE_BCNMISS,
> +		file, userbuf, count, ppos);
> +}
>  
> -	event_bitmap = lbs_get_events_bitmap(priv);
>  
> -	res = lbs_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
> -	if (res < 0)
> -		goto out_unlock;
> +static ssize_t lbs_bcnmiss_write(
> +	struct file *file, const char __user *userbuf,
> +	size_t count, loff_t *ppos)
> +{
> +	return lbs_threshold_write(TLV_TYPE_BCNMISS, CMD_SUBSCRIBE_BCNMISS,
> +		file, userbuf, count, ppos);
> +}
>  
> -	event = &pcmdptr->params.subscribe_event;
> -	event->action = cpu_to_le16(CMD_ACT_SET);
> -	pcmdptr->size = cpu_to_le16(S_DS_GEN +
> -		sizeof(struct cmd_ds_802_11_subscribe_event) +
> -		sizeof(struct mrvlietypes_snrthreshold));
> -	cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
> -	ptr = (u8*) pcmdptr+cmd_len;
> -	snr_threshold = (struct mrvlietypes_snrthreshold *)(ptr);
> -	snr_threshold->header.type = cpu_to_le16(TLV_TYPE_SNR_HIGH);
> -	snr_threshold->header.len = cpu_to_le16(2);
> -	snr_threshold->snrvalue = value;
> -	snr_threshold->snrfreq = freq;
> -	event_bitmap |= subscribed ? 0x0020 : 0x0;
> -	event->events = cpu_to_le16(event_bitmap);
>  
> -	lbs_queue_cmd(adapter, pcmdnode, 1);
> -	wake_up_interruptible(&priv->waitq);
>  
> -	/* Sleep until response is generated by FW */
> -	wait_event_interruptible(pcmdnode->cmdwait_q,
> -				 pcmdnode->cmdwaitqwoken);
>  
> -	pcmdptr = response_buf;
>  
> -	if (pcmdptr->result) {
> -		lbs_pr_err("%s: fail, result=%d\n", __func__,
> -			   le16_to_cpu(pcmdptr->result));
> -		kfree(response_buf);
> -		free_page(addr);
> -		return 0;
> -	}
>  
> -	if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
> -		lbs_pr_err("command response incorrect!\n");
> -		kfree(response_buf);
> -		free_page(addr);
> -		return 0;
> -	}
>  
> -	res = count;
> -out_unlock:
> -	free_page(addr);
> -	return res;
> -}
>  
>  static ssize_t lbs_rdmac_read(struct file *file, char __user *userbuf,
>  				  size_t count, loff_t *ppos)
> @@ -1910,4 +1210,3 @@ static void lbs_debug_init(struct lbs_pr
>  						  &lbs_debug_fops);
>  }
>  #endif
> -
> Index: wireless-2.6/drivers/net/wireless/libertas/hostcmd.h
> ===================================================================
> --- wireless-2.6.orig/drivers/net/wireless/libertas/hostcmd.h	2007-11-26 10:56:45.000000000 +0100
> +++ wireless-2.6/drivers/net/wireless/libertas/hostcmd.h	2007-11-26 10:58:08.000000000 +0100
> @@ -151,6 +151,13 @@ struct cmd_ds_802_11_reset {
>  struct cmd_ds_802_11_subscribe_event {
>  	__le16 action;
>  	__le16 events;
> +
> +	/* A TLV to the CMD_802_11_SUBSCRIBE_EVENT command can contain a
> +	 * number of TLVs. From the v5.1 manual, those TLVs would add up to
> +	 * 40 bytes. However, future firmware might add additional TLVs, so I
> +	 * bump this up a bit.
> +	 */
> +	u8 tlv[128];
>  };
>  
>  /*
> Index: wireless-2.6/drivers/net/wireless/libertas/host.h
> ===================================================================
> --- wireless-2.6.orig/drivers/net/wireless/libertas/host.h	2007-11-26 10:56:45.000000000 +0100
> +++ wireless-2.6/drivers/net/wireless/libertas/host.h	2007-11-26 10:58:08.000000000 +0100
> @@ -178,6 +178,14 @@
>  #define CMD_TYPE_SHORT_PREAMBLE             0x0002
>  #define CMD_TYPE_LONG_PREAMBLE              0x0003
>  
> +/* Event flags for CMD_802_11_SUBSCRIBE_EVENT */
> +#define CMD_SUBSCRIBE_RSSI_LOW              0x0001
> +#define CMD_SUBSCRIBE_SNR_LOW               0x0002
> +#define CMD_SUBSCRIBE_FAILCOUNT             0x0004
> +#define CMD_SUBSCRIBE_BCNMISS               0x0008
> +#define CMD_SUBSCRIBE_RSSI_HIGH             0x0010
> +#define CMD_SUBSCRIBE_SNR_HIGH              0x0020
> +
>  #define TURN_ON_RF                              0x01
>  #define RADIO_ON                                0x01
>  #define RADIO_OFF                               0x00
> Index: wireless-2.6/drivers/net/wireless/libertas/types.h
> ===================================================================
> --- wireless-2.6.orig/drivers/net/wireless/libertas/types.h	2007-11-26 10:56:45.000000000 +0100
> +++ wireless-2.6/drivers/net/wireless/libertas/types.h	2007-11-26 10:58:08.000000000 +0100
> @@ -201,22 +201,11 @@ struct mrvlietypes_powercapability {
>  	s8 maxpower;
>  } __attribute__ ((packed));
>  
> -struct mrvlietypes_rssithreshold {
> -	struct mrvlietypesheader header;
> -	u8 rssivalue;
> -	u8 rssifreq;
> -} __attribute__ ((packed));
> -
> -struct mrvlietypes_snrthreshold {
> -	struct mrvlietypesheader header;
> -	u8 snrvalue;
> -	u8 snrfreq;
> -} __attribute__ ((packed));
> -
> -struct mrvlietypes_failurecount {
> +/* used in CMD_802_11_SUBSCRIBE_EVENT for SNR, RSSI and Failure */
> +struct mrvlietypes_thresholds {
>  	struct mrvlietypesheader header;
> -	u8 failvalue;
> -	u8 Failfreq;
> +	u8 value;
> +	u8 freq;
>  } __attribute__ ((packed));
>  
>  struct mrvlietypes_beaconsmissed {




More information about the libertas-dev mailing list