[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