📄 hostap_hw.c
字号:
printk(KERN_DEBUG "%s: hfa384x_cmd: command was not " "completed (res=%d, entry=%p, type=%d, cmd=0x%04x, " "param0=0x%04x, EVSTAT=%04x INTEN=%04x)\n", dev->name, res, entry, entry->type, entry->cmd, entry->param0, reg, HFA384X_INW(HFA384X_INTEN_OFF)); if (reg & HFA384X_EV_CMD) { /* Command completion event is pending, but the * interrupt was not delivered - probably an issue * with pcmcia-cs configuration. */ printk(KERN_WARNING "%s: interrupt delivery does not " "seem to work\n", dev->name); } prism2_io_debug_error(dev, 3); res = -ETIMEDOUT; goto done; } if (resp0 != NULL) *resp0 = entry->resp0;#ifndef final_version if (entry->res) { printk(KERN_DEBUG "%s: CMD=0x%04x => res=0x%02x, " "resp0=0x%04x\n", dev->name, cmd, entry->res, entry->resp0); }#endif /* final_version */ res = entry->res; done: hostap_cmd_queue_free(local, entry, 1); return res;}/** * hfa384x_cmd_callback - Issue a Prism2 command; callback when completed * @dev: pointer to net_device * @cmd: Prism2 command code (HFA384X_CMD_CODE_*) * @param0: value for Param0 register * @callback: command completion callback function (%NULL = no callback) * @context: context data to be given to the callback function * * Issue given command (possibly after waiting in command queue) and use * callback function to indicate command completion. This can be called both * from user and interrupt context. The callback function will be called in * hardware IRQ context. It can be %NULL, when no function is called when * command is completed. */static int hfa384x_cmd_callback(struct net_device *dev, u16 cmd, u16 param0, void (*callback)(struct net_device *dev, long context, u16 resp0, u16 status), long context){ struct hostap_interface *iface = dev->priv; local_info_t *local = iface->local; int issue, ret; unsigned long flags; struct hostap_cmd_queue *entry; if (local->cmd_queue_len >= HOSTAP_CMD_QUEUE_MAX_LEN + 2) { printk(KERN_DEBUG "%s: hfa384x_cmd: cmd_queue full\n", dev->name); return -1; } entry = (struct hostap_cmd_queue *) kmalloc(sizeof(*entry), GFP_ATOMIC); if (entry == NULL) { printk(KERN_DEBUG "%s: hfa384x_cmd_callback - kmalloc " "failed\n", dev->name); return -ENOMEM; } memset(entry, 0, sizeof(*entry)); atomic_set(&entry->usecnt, 1); entry->type = CMD_CALLBACK; entry->cmd = cmd; entry->param0 = param0; entry->callback = callback; entry->context = context; spin_lock_irqsave(&local->cmdlock, flags); issue = list_empty(&local->cmd_queue); if (issue) entry->issuing = 1; list_add_tail(&entry->list, &local->cmd_queue); local->cmd_queue_len++; spin_unlock_irqrestore(&local->cmdlock, flags); if (issue && hfa384x_cmd_issue(dev, entry)) ret = -ETIMEDOUT; else ret = 0; hostap_cmd_queue_free(local, entry, ret); return ret;}/** * __hfa384x_cmd_no_wait - Issue a Prism2 command (private) * @dev: pointer to net_device * @cmd: Prism2 command code (HFA384X_CMD_CODE_*) * @param0: value for Param0 register * @io_debug_num: I/O debug error number * * Shared helper function for hfa384x_cmd_wait() and hfa384x_cmd_no_wait(). */static int __hfa384x_cmd_no_wait(struct net_device *dev, u16 cmd, u16 param0, int io_debug_num){ int tries; u16 reg; /* wait until busy bit is clear; this should always be clear since the * commands are serialized */ tries = HFA384X_CMD_BUSY_TIMEOUT; while (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY && tries > 0) { tries--; udelay(1); } if (tries == 0) { reg = HFA384X_INW(HFA384X_CMD_OFF); prism2_io_debug_error(dev, io_debug_num); printk(KERN_DEBUG "%s: __hfa384x_cmd_no_wait(%d) - timeout - " "reg=0x%04x\n", dev->name, io_debug_num, reg); return -ETIMEDOUT; } /* write command */ HFA384X_OUTW(param0, HFA384X_PARAM0_OFF); HFA384X_OUTW(cmd, HFA384X_CMD_OFF); return 0;}/** * hfa384x_cmd_wait - Issue a Prism2 command and busy wait for completion * @dev: pointer to net_device * @cmd: Prism2 command code (HFA384X_CMD_CODE_*) * @param0: value for Param0 register */static int hfa384x_cmd_wait(struct net_device *dev, u16 cmd, u16 param0){ int res, tries; u16 reg; res = __hfa384x_cmd_no_wait(dev, cmd, param0, 4); if (res) return res; /* wait for command completion */ if ((cmd & HFA384X_CMDCODE_MASK) == HFA384X_CMDCODE_DOWNLOAD) tries = HFA384X_DL_COMPL_TIMEOUT; else tries = HFA384X_CMD_COMPL_TIMEOUT; while (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_CMD) && tries > 0) { tries--; udelay(10); } if (tries == 0) { reg = HFA384X_INW(HFA384X_EVSTAT_OFF); prism2_io_debug_error(dev, 5); printk(KERN_DEBUG "%s: hfa384x_cmd_wait - timeout2 - " "reg=0x%04x\n", dev->name, reg); return -ETIMEDOUT; } res = (HFA384X_INW(HFA384X_STATUS_OFF) & (BIT(14) | BIT(13) | BIT(12) | BIT(11) | BIT(10) | BIT(9) | BIT(8))) >> 8;#ifndef final_version if (res) { printk(KERN_DEBUG "%s: CMD=0x%04x => res=0x%02x\n", dev->name, cmd, res); }#endif HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF); return res;}/** * hfa384x_cmd_no_wait - Issue a Prism2 command; do not wait for completion * @dev: pointer to net_device * @cmd: Prism2 command code (HFA384X_CMD_CODE_*) * @param0: value for Param0 register */static inline int hfa384x_cmd_no_wait(struct net_device *dev, u16 cmd, u16 param0){ return __hfa384x_cmd_no_wait(dev, cmd, param0, 6);}/** * prism2_cmd_ev - Prism2 command completion event handler * @dev: pointer to net_device * * Interrupt handler for command completion events. Called by the main * interrupt handler in hardware IRQ context. Read Resp0 and status registers * from the hardware and ACK the event. Depending on the issued command type * either wake up the sleeping process that is waiting for command completion * or call the callback function. Issue the next command, if one is pending. */static void prism2_cmd_ev(struct net_device *dev){ struct hostap_interface *iface = dev->priv; local_info_t *local = iface->local; struct hostap_cmd_queue *entry = NULL; spin_lock(&local->cmdlock); if (!list_empty(&local->cmd_queue)) { entry = list_entry(local->cmd_queue.next, struct hostap_cmd_queue, list); atomic_inc(&entry->usecnt); list_del_init(&entry->list); local->cmd_queue_len--; if (!entry->issued) { printk(KERN_DEBUG "%s: Command completion event, but " "cmd not issued\n", dev->name); __hostap_cmd_queue_free(local, entry, 1); entry = NULL; } } spin_unlock(&local->cmdlock); if (!entry) { HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF); printk(KERN_DEBUG "%s: Command completion event, but no " "pending commands\n", dev->name); return; } entry->resp0 = HFA384X_INW(HFA384X_RESP0_OFF); entry->res = (HFA384X_INW(HFA384X_STATUS_OFF) & (BIT(14) | BIT(13) | BIT(12) | BIT(11) | BIT(10) | BIT(9) | BIT(8))) >> 8; HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF); /* TODO: rest of the CmdEv handling could be moved to tasklet */ if (entry->type == CMD_SLEEP) { entry->type = CMD_COMPLETED; wake_up_interruptible(&entry->compl); } else if (entry->type == CMD_CALLBACK) { if (entry->callback) entry->callback(dev, entry->context, entry->resp0, entry->res); } else { printk(KERN_DEBUG "%s: Invalid command completion type %d\n", dev->name, entry->type); } hostap_cmd_queue_free(local, entry, 1); /* issue next command, if pending */ entry = NULL; spin_lock(&local->cmdlock); if (!list_empty(&local->cmd_queue)) { entry = list_entry(local->cmd_queue.next, struct hostap_cmd_queue, list); if (entry->issuing) { /* hfa384x_cmd() has already started issuing this * command, so do not start here */ entry = NULL; } if (entry) atomic_inc(&entry->usecnt); } spin_unlock(&local->cmdlock); if (entry) { /* issue next command; if command issuing fails, remove the * entry from cmd_queue */ int res = hfa384x_cmd_issue(dev, entry); spin_lock(&local->cmdlock); __hostap_cmd_queue_free(local, entry, res); spin_unlock(&local->cmdlock); }}static inline int hfa384x_wait_offset(struct net_device *dev, u16 o_off){ int tries = HFA384X_BAP_BUSY_TIMEOUT; int res = HFA384X_INW(o_off) & HFA384X_OFFSET_BUSY; while (res && tries > 0) { tries--; udelay(1); res = HFA384X_INW(o_off) & HFA384X_OFFSET_BUSY; } return res;}/* Offset must be even */static int hfa384x_setup_bap(struct net_device *dev, u16 bap, u16 id, int offset){ u16 o_off, s_off; int ret = 0; if (offset % 2 || bap > 1) return -EINVAL; if (bap == BAP1) { o_off = HFA384X_OFFSET1_OFF; s_off = HFA384X_SELECT1_OFF; } else { o_off = HFA384X_OFFSET0_OFF; s_off = HFA384X_SELECT0_OFF; } if (hfa384x_wait_offset(dev, o_off)) { prism2_io_debug_error(dev, 7); printk(KERN_DEBUG "%s: hfa384x_setup_bap - timeout before\n", dev->name); ret = -ETIMEDOUT; goto out; } HFA384X_OUTW(id, s_off); HFA384X_OUTW(offset, o_off); if (hfa384x_wait_offset(dev, o_off)) { prism2_io_debug_error(dev, 8); printk(KERN_DEBUG "%s: hfa384x_setup_bap - timeout after\n", dev->name); ret = -ETIMEDOUT; goto out; }#ifndef final_version if (HFA384X_INW(o_off) & HFA384X_OFFSET_ERR) { prism2_io_debug_error(dev, 9); printk(KERN_DEBUG "%s: hfa384x_setup_bap - offset error " "(%d,0x04%x,%d); reg=0x%04x\n", dev->name, bap, id, offset, HFA384X_INW(o_off)); ret = -EINVAL; }#endif out: return ret;}static int hfa384x_get_rid(struct net_device *dev, u16 rid, void *buf, int len, int exact_len){ struct hostap_interface *iface = dev->priv; local_info_t *local = iface->local; int res, rlen = 0; struct hfa384x_rid_hdr rec; if (local->no_pri) { printk(KERN_DEBUG "%s: cannot get RID %04x (len=%d) - no PRI " "f/w\n", dev->name, rid, len); return -ENOTTY; /* Well.. not really correct, but return * something unique enough.. */ } if ((local->func->card_present && !local->func->card_present(local)) || local->hw_downloading) return -ENODEV; res = down_interruptible(&local->rid_bap_sem); if (res) return res; res = hfa384x_cmd(dev, HFA384X_CMDCODE_ACCESS, rid, NULL, NULL); if (res) { printk(KERN_DEBUG "%s: hfa384x_get_rid: CMDCODE_ACCESS failed " "(res=%d, rid=%04x, len=%d)\n", dev->name, res, rid, len); up(&local->rid_bap_sem); return res; } spin_lock_bh(&local->baplock); res = hfa384x_setup_bap(dev, BAP0, rid, 0); if (!res) res = hfa384x_from_bap(dev, BAP0, &rec, sizeof(rec)); if (le16_to_cpu(rec.len) == 0) { /* RID not available */ res = -ENODATA; } rlen = (le16_to_cpu(rec.len) - 1) * 2; if (!res && exact_len && rlen != len) { printk(KERN_DEBUG "%s: hfa384x_get_rid - RID len mismatch: " "rid=0x%04x, len=%d (expected %d)\n", dev->name, rid, rlen, len); res = -ENODATA; } if (!res) res = hfa384x_from_bap(dev, BAP0, buf, len); spin_unlock_bh(&local->baplock); up(&local->rid_bap_sem); if (res) { if (res != -ENODATA) printk(KERN_DEBUG "%s: hfa384x_get_rid (rid=%04x, " "len=%d) - failed - res=%d\n", dev->name, rid, len, res); if (res == -ETIMEDOUT) prism2_hw_reset(dev); return res; } return rlen;}static int hfa384x_set_rid(struct net_device *dev, u16 rid, void *buf, int len){ struct hostap_interface *iface = dev->priv; local_info_t *local = iface->local; struct hfa384x_rid_hdr rec; int res; if (local->no_pri) { printk(KERN_DEBUG "%s: cannot set RID %04x (len=%d) - no PRI " "f/w\n", dev->name, rid, len); return -ENOTTY; /* Well.. not really correct, but return * something unique enough.. */ } if ((local->func->card_present && !local->func->card_present(local)) || local->hw_downloading) return -ENODEV; rec.rid = cpu_to_le16(rid); /* RID len in words and +1 for rec.rid */ rec.len = cpu_to_le16(len / 2 + len % 2 + 1); res = down_interruptible(&local->rid_bap_sem); if (res) return res; spin_lock_bh(&local->baplock); res = hfa384x_setup_bap(dev, BAP0, rid, 0); if (!res) res = hfa384x_to_bap(dev, BAP0, &rec, sizeof(rec)); if (!res) res = hfa384x_to_bap(dev, BAP0, buf, len); spin_unlock_bh(&local->baplock); if (res) { printk(KERN_DEBUG "%s: hfa384x_set_rid (rid=%04x, len=%d) - " "failed - res=%d\n", dev->name, rid, len, res); up(&local->rid_bap_sem);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -