diff options
Diffstat (limited to 'drivers/net/wireless/libertas')
-rw-r--r-- | drivers/net/wireless/libertas/assoc.c | 57 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/debugfs.c | 28 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/if_cs.c | 39 |
3 files changed, 91 insertions, 33 deletions
diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index 81f86ef2699..dd8732611ba 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -34,7 +34,8 @@ static const u8 bssid_off[ETH_ALEN] __attribute__ ((aligned (2))) = * * @param priv A pointer to struct lbs_private structure * @param rates the buffer which keeps input and output - * @param rates_size the size of rate1 buffer; new size of buffer on return + * @param rates_size the size of rates buffer; new size of buffer on return, + * which will be less than or equal to original rates_size * * @return 0 on success, or -1 on error */ @@ -42,48 +43,42 @@ static int get_common_rates(struct lbs_private *priv, u8 *rates, u16 *rates_size) { - u8 *card_rates = lbs_bg_rates; - size_t num_card_rates = sizeof(lbs_bg_rates); - int ret = 0, i, j; - u8 *tmp; - size_t tmp_size = 0; - - tmp = kzalloc((ARRAY_SIZE(lbs_bg_rates) - 1) * (*rates_size - 1), - GFP_KERNEL); - if (!tmp) - return -1; - - /* For each rate in card_rates that exists in rate1, copy to tmp */ - for (i = 0; card_rates[i] && (i < num_card_rates); i++) { - for (j = 0; rates[j] && (j < *rates_size); j++) { - if (rates[j] == card_rates[i]) - tmp[tmp_size++] = card_rates[i]; + int i, j; + u8 intersection[MAX_RATES]; + u16 intersection_size; + u16 num_rates = 0; + + intersection_size = min_t(u16, *rates_size, ARRAY_SIZE(intersection)); + + /* Allow each rate from 'rates' that is supported by the hardware */ + for (i = 0; i < ARRAY_SIZE(lbs_bg_rates) && lbs_bg_rates[i]; i++) { + for (j = 0; j < intersection_size && rates[j]; j++) { + if (rates[j] == lbs_bg_rates[i]) + intersection[num_rates++] = rates[j]; } } lbs_deb_hex(LBS_DEB_JOIN, "AP rates ", rates, *rates_size); - lbs_deb_hex(LBS_DEB_JOIN, "card rates ", card_rates, num_card_rates); - lbs_deb_hex(LBS_DEB_JOIN, "common rates", tmp, tmp_size); + lbs_deb_hex(LBS_DEB_JOIN, "card rates ", lbs_bg_rates, + ARRAY_SIZE(lbs_bg_rates)); + lbs_deb_hex(LBS_DEB_JOIN, "common rates", intersection, num_rates); lbs_deb_join("TX data rate 0x%02x\n", priv->cur_rate); if (!priv->enablehwauto) { - for (i = 0; i < tmp_size; i++) { - if (tmp[i] == priv->cur_rate) + for (i = 0; i < num_rates; i++) { + if (intersection[i] == priv->cur_rate) goto done; } lbs_pr_alert("Previously set fixed data rate %#x isn't " "compatible with the network.\n", priv->cur_rate); - ret = -1; - goto done; + return -1; } - ret = 0; done: memset(rates, 0, *rates_size); - *rates_size = min_t(int, tmp_size, *rates_size); - memcpy(rates, tmp, *rates_size); - kfree(tmp); - return ret; + *rates_size = num_rates; + memcpy(rates, intersection, num_rates); + return 0; } @@ -325,8 +320,8 @@ static int lbs_associate(struct lbs_private *priv, rates = (struct mrvl_ie_rates_param_set *) pos; rates->header.type = cpu_to_le16(TLV_TYPE_RATES); - memcpy(&rates->rates, &bss->rates, MAX_RATES); - tmplen = MAX_RATES; + tmplen = min_t(u16, ARRAY_SIZE(bss->rates), MAX_RATES); + memcpy(&rates->rates, &bss->rates, tmplen); if (get_common_rates(priv, rates->rates, &tmplen)) { ret = -1; goto done; @@ -600,7 +595,7 @@ static int lbs_adhoc_join(struct lbs_private *priv, /* Copy Data rates from the rates recorded in scan response */ memset(cmd.bss.rates, 0, sizeof(cmd.bss.rates)); - ratesize = min_t(u16, sizeof(cmd.bss.rates), MAX_RATES); + ratesize = min_t(u16, ARRAY_SIZE(cmd.bss.rates), ARRAY_SIZE (bss->rates)); memcpy(cmd.bss.rates, bss->rates, ratesize); if (get_common_rates(priv, cmd.bss.rates, &ratesize)) { lbs_deb_join("ADHOC_JOIN: get_common_rates returned error.\n"); diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c index 811ffc3ef41..893a55ca344 100644 --- a/drivers/net/wireless/libertas/debugfs.c +++ b/drivers/net/wireless/libertas/debugfs.c @@ -45,6 +45,8 @@ static ssize_t lbs_dev_info(struct file *file, char __user *userbuf, unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf = (char *)addr; ssize_t res; + if (!buf) + return -ENOMEM; pos += snprintf(buf+pos, len-pos, "state = %s\n", szStates[priv->connect_status]); @@ -68,6 +70,8 @@ static ssize_t lbs_getscantable(struct file *file, char __user *userbuf, char *buf = (char *)addr; DECLARE_SSID_BUF(ssid); struct bss_descriptor * iter_bss; + if (!buf) + return -ENOMEM; pos += snprintf(buf+pos, len-pos, "# | ch | rssi | bssid | cap | Qual | SSID \n"); @@ -110,6 +114,8 @@ static ssize_t lbs_sleepparams_write(struct file *file, int p1, p2, p3, p4, p5, p6; unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf = (char *)addr; + if (!buf) + return -ENOMEM; buf_size = min(count, len - 1); if (copy_from_user(buf, user_buf, buf_size)) { @@ -148,6 +154,8 @@ static ssize_t lbs_sleepparams_read(struct file *file, char __user *userbuf, struct sleep_params sp; unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf = (char *)addr; + if (!buf) + return -ENOMEM; ret = lbs_cmd_802_11_sleep_params(priv, CMD_ACT_GET, &sp); if (ret) @@ -433,6 +441,8 @@ static ssize_t lbs_rdmac_read(struct file *file, char __user *userbuf, int ret; unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf = (char *)addr; + if (!buf) + return -ENOMEM; offval.offset = priv->mac_offset; offval.value = 0; @@ -457,6 +467,8 @@ static ssize_t lbs_rdmac_write(struct file *file, ssize_t res, buf_size; unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf = (char *)addr; + if (!buf) + return -ENOMEM; buf_size = min(count, len - 1); if (copy_from_user(buf, userbuf, buf_size)) { @@ -481,6 +493,8 @@ static ssize_t lbs_wrmac_write(struct file *file, struct lbs_offset_value offval; unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf = (char *)addr; + if (!buf) + return -ENOMEM; buf_size = min(count, len - 1); if (copy_from_user(buf, userbuf, buf_size)) { @@ -515,6 +529,8 @@ static ssize_t lbs_rdbbp_read(struct file *file, char __user *userbuf, int ret; unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf = (char *)addr; + if (!buf) + return -ENOMEM; offval.offset = priv->bbp_offset; offval.value = 0; @@ -540,6 +556,8 @@ static ssize_t lbs_rdbbp_write(struct file *file, ssize_t res, buf_size; unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf = (char *)addr; + if (!buf) + return -ENOMEM; buf_size = min(count, len - 1); if (copy_from_user(buf, userbuf, buf_size)) { @@ -564,6 +582,8 @@ static ssize_t lbs_wrbbp_write(struct file *file, struct lbs_offset_value offval; unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf = (char *)addr; + if (!buf) + return -ENOMEM; buf_size = min(count, len - 1); if (copy_from_user(buf, userbuf, buf_size)) { @@ -598,6 +618,8 @@ static ssize_t lbs_rdrf_read(struct file *file, char __user *userbuf, int ret; unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf = (char *)addr; + if (!buf) + return -ENOMEM; offval.offset = priv->rf_offset; offval.value = 0; @@ -623,6 +645,8 @@ static ssize_t lbs_rdrf_write(struct file *file, ssize_t res, buf_size; unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf = (char *)addr; + if (!buf) + return -ENOMEM; buf_size = min(count, len - 1); if (copy_from_user(buf, userbuf, buf_size)) { @@ -647,6 +671,8 @@ static ssize_t lbs_wrrf_write(struct file *file, struct lbs_offset_value offval; unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf = (char *)addr; + if (!buf) + return -ENOMEM; buf_size = min(count, len - 1); if (copy_from_user(buf, userbuf, buf_size)) { @@ -853,6 +879,8 @@ static ssize_t lbs_debugfs_read(struct file *file, char __user *userbuf, struct debug_data *d; unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf = (char *)addr; + if (!buf) + return -ENOMEM; p = buf; diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c index f658fd6a2c0..62381768f2d 100644 --- a/drivers/net/wireless/libertas/if_cs.c +++ b/drivers/net/wireless/libertas/if_cs.c @@ -59,6 +59,7 @@ struct if_cs_card { struct pcmcia_device *p_dev; struct lbs_private *priv; void __iomem *iobase; + bool align_regs; }; @@ -274,16 +275,25 @@ static int if_cs_poll_while_fw_download(struct if_cs_card *card, uint addr, u8 r #define IF_CS_PRODUCT_ID 0x0000001C #define IF_CS_CF8385_B1_REV 0x12 #define IF_CS_CF8381_B3_REV 0x04 +#define IF_CS_CF8305_B1_REV 0x03 /* * Used to detect other cards than CF8385 since their revisions of silicon * doesn't match those from CF8385, eg. CF8381 B3 works with this driver. */ +#define CF8305_MANFID 0x02db +#define CF8305_CARDID 0x8103 #define CF8381_MANFID 0x02db #define CF8381_CARDID 0x6064 #define CF8385_MANFID 0x02df #define CF8385_CARDID 0x8103 +static inline int if_cs_hw_is_cf8305(struct pcmcia_device *p_dev) +{ + return (p_dev->manf_id == CF8305_MANFID && + p_dev->card_id == CF8305_CARDID); +} + static inline int if_cs_hw_is_cf8381(struct pcmcia_device *p_dev) { return (p_dev->manf_id == CF8381_MANFID && @@ -556,7 +566,15 @@ static int if_cs_prog_helper(struct if_cs_card *card) lbs_deb_enter(LBS_DEB_CS); - scratch = if_cs_read8(card, IF_CS_SCRATCH); + /* + * This is the only place where an unaligned register access happens on + * the CF8305 card, therefore for the sake of speed of the driver, we do + * the alignment correction here. + */ + if (card->align_regs) + scratch = if_cs_read16(card, IF_CS_SCRATCH) >> 8; + else + scratch = if_cs_read8(card, IF_CS_SCRATCH); /* "If the value is 0x5a, the firmware is already * downloaded successfully" @@ -880,8 +898,24 @@ static int if_cs_probe(struct pcmcia_device *p_dev) p_dev->irq.AssignedIRQ, p_dev->io.BasePort1, p_dev->io.BasePort1 + p_dev->io.NumPorts1 - 1); + /* + * Most of the libertas cards can do unaligned register access, but some + * weird ones can not. That's especially true for the CF8305 card. + */ + card->align_regs = 0; + /* Check if we have a current silicon */ prod_id = if_cs_read8(card, IF_CS_PRODUCT_ID); + if (if_cs_hw_is_cf8305(p_dev)) { + card->align_regs = 1; + if (prod_id < IF_CS_CF8305_B1_REV) { + lbs_pr_err("old chips like 8305 rev B3 " + "aren't supported\n"); + ret = -ENODEV; + goto out2; + } + } + if (if_cs_hw_is_cf8381(p_dev) && prod_id < IF_CS_CF8381_B3_REV) { lbs_pr_err("old chips like 8381 rev B3 aren't supported\n"); ret = -ENODEV; @@ -896,7 +930,7 @@ static int if_cs_probe(struct pcmcia_device *p_dev) /* Load the firmware early, before calling into libertas.ko */ ret = if_cs_prog_helper(card); - if (ret == 0) + if (ret == 0 && !if_cs_hw_is_cf8305(p_dev)) ret = if_cs_prog_real(card); if (ret) goto out2; @@ -976,6 +1010,7 @@ static void if_cs_detach(struct pcmcia_device *p_dev) /********************************************************************/ static struct pcmcia_device_id if_cs_ids[] = { + PCMCIA_DEVICE_MANF_CARD(CF8305_MANFID, CF8305_CARDID), PCMCIA_DEVICE_MANF_CARD(CF8381_MANFID, CF8381_CARDID), PCMCIA_DEVICE_MANF_CARD(CF8385_MANFID, CF8385_CARDID), PCMCIA_DEVICE_NULL, |