📄 ipw2200.c
字号:
u32 dif_len = addr - aligned_addr; u32 i; IPW_DEBUG_IO("addr = %i, buf = %p, num = %i\n", addr, buf, num); if (num <= 0) { return; } /* Write the first dword (or portion) byte by byte */ if (unlikely(dif_len)) { _ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr); /* Start writing at aligned_addr + dif_len */ for (i = dif_len; ((i < 4) && (num > 0)); i++, num--, buf++) _ipw_write8(priv, IPW_INDIRECT_DATA + i, *buf); aligned_addr += 4; } /* Write all of the middle dwords as dwords, with auto-increment */ _ipw_write32(priv, IPW_AUTOINC_ADDR, aligned_addr); for (; num >= 4; buf += 4, aligned_addr += 4, num -= 4) _ipw_write32(priv, IPW_AUTOINC_DATA, *(u32 *) buf); /* Write the last dword (or portion) byte by byte */ if (unlikely(num)) { _ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr); for (i = 0; num > 0; i++, num--, buf++) _ipw_write8(priv, IPW_INDIRECT_DATA + i, *buf); }}/* General purpose, no alignment requirement, iterative (multi-byte) write, *//* for 1st 4K of SRAM/regs space */static void ipw_write_direct(struct ipw_priv *priv, u32 addr, void *buf, int num){ memcpy_toio((priv->hw_base + addr), buf, num);}/* Set bit(s) in low 4K of SRAM/regs */static inline void ipw_set_bit(struct ipw_priv *priv, u32 reg, u32 mask){ ipw_write32(priv, reg, ipw_read32(priv, reg) | mask);}/* Clear bit(s) in low 4K of SRAM/regs */static inline void ipw_clear_bit(struct ipw_priv *priv, u32 reg, u32 mask){ ipw_write32(priv, reg, ipw_read32(priv, reg) & ~mask);}static inline void __ipw_enable_interrupts(struct ipw_priv *priv){ if (priv->status & STATUS_INT_ENABLED) return; priv->status |= STATUS_INT_ENABLED; ipw_write32(priv, IPW_INTA_MASK_R, IPW_INTA_MASK_ALL);}static inline void __ipw_disable_interrupts(struct ipw_priv *priv){ if (!(priv->status & STATUS_INT_ENABLED)) return; priv->status &= ~STATUS_INT_ENABLED; ipw_write32(priv, IPW_INTA_MASK_R, ~IPW_INTA_MASK_ALL);}static inline void ipw_enable_interrupts(struct ipw_priv *priv){ unsigned long flags; spin_lock_irqsave(&priv->irq_lock, flags); __ipw_enable_interrupts(priv); spin_unlock_irqrestore(&priv->irq_lock, flags);}static inline void ipw_disable_interrupts(struct ipw_priv *priv){ unsigned long flags; spin_lock_irqsave(&priv->irq_lock, flags); __ipw_disable_interrupts(priv); spin_unlock_irqrestore(&priv->irq_lock, flags);}static char *ipw_error_desc(u32 val){ switch (val) { case IPW_FW_ERROR_OK: return "ERROR_OK"; case IPW_FW_ERROR_FAIL: return "ERROR_FAIL"; case IPW_FW_ERROR_MEMORY_UNDERFLOW: return "MEMORY_UNDERFLOW"; case IPW_FW_ERROR_MEMORY_OVERFLOW: return "MEMORY_OVERFLOW"; case IPW_FW_ERROR_BAD_PARAM: return "BAD_PARAM"; case IPW_FW_ERROR_BAD_CHECKSUM: return "BAD_CHECKSUM"; case IPW_FW_ERROR_NMI_INTERRUPT: return "NMI_INTERRUPT"; case IPW_FW_ERROR_BAD_DATABASE: return "BAD_DATABASE"; case IPW_FW_ERROR_ALLOC_FAIL: return "ALLOC_FAIL"; case IPW_FW_ERROR_DMA_UNDERRUN: return "DMA_UNDERRUN"; case IPW_FW_ERROR_DMA_STATUS: return "DMA_STATUS"; case IPW_FW_ERROR_DINO_ERROR: return "DINO_ERROR"; case IPW_FW_ERROR_EEPROM_ERROR: return "EEPROM_ERROR"; case IPW_FW_ERROR_SYSASSERT: return "SYSASSERT"; case IPW_FW_ERROR_FATAL_ERROR: return "FATAL_ERROR"; default: return "UNKNOWN_ERROR"; }}static void ipw_dump_error_log(struct ipw_priv *priv, struct ipw_fw_error *error){ u32 i; if (!error) { IPW_ERROR("Error allocating and capturing error log. " "Nothing to dump.\n"); return; } IPW_ERROR("Start IPW Error Log Dump:\n"); IPW_ERROR("Status: 0x%08X, Config: %08X\n", error->status, error->config); for (i = 0; i < error->elem_len; i++) IPW_ERROR("%s %i 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", ipw_error_desc(error->elem[i].desc), error->elem[i].time, error->elem[i].blink1, error->elem[i].blink2, error->elem[i].link1, error->elem[i].link2, error->elem[i].data); for (i = 0; i < error->log_len; i++) IPW_ERROR("%i\t0x%08x\t%i\n", error->log[i].time, error->log[i].data, error->log[i].event);}static inline int ipw_is_init(struct ipw_priv *priv){ return (priv->status & STATUS_INIT) ? 1 : 0;}#include "compat.c"static int ipw_get_ordinal(struct ipw_priv *priv, u32 ord, void *val, u32 * len){ u32 addr, field_info, field_len, field_count, total_len; IPW_DEBUG_ORD("ordinal = %i\n", ord); if (!priv || !val || !len) { IPW_DEBUG_ORD("Invalid argument\n"); return -EINVAL; } /* verify device ordinal tables have been initialized */ if (!priv->table0_addr || !priv->table1_addr || !priv->table2_addr) { IPW_DEBUG_ORD("Access ordinals before initialization\n"); return -EINVAL; } switch (IPW_ORD_TABLE_ID_MASK & ord) { case IPW_ORD_TABLE_0_MASK: /* * TABLE 0: Direct access to a table of 32 bit values * * This is a very simple table with the data directly * read from the table */ /* remove the table id from the ordinal */ ord &= IPW_ORD_TABLE_VALUE_MASK; /* boundary check */ if (ord > priv->table0_len) { IPW_DEBUG_ORD("ordinal value (%i) longer then " "max (%i)\n", ord, priv->table0_len); return -EINVAL; } /* verify we have enough room to store the value */ if (*len < sizeof(u32)) { IPW_DEBUG_ORD("ordinal buffer length too small, " "need %zd\n", sizeof(u32)); return -EINVAL; } IPW_DEBUG_ORD("Reading TABLE0[%i] from offset 0x%08x\n", ord, priv->table0_addr + (ord << 2)); *len = sizeof(u32); ord <<= 2; *((u32 *) val) = ipw_read32(priv, priv->table0_addr + ord); break; case IPW_ORD_TABLE_1_MASK: /* * TABLE 1: Indirect access to a table of 32 bit values * * This is a fairly large table of u32 values each * representing starting addr for the data (which is * also a u32) */ /* remove the table id from the ordinal */ ord &= IPW_ORD_TABLE_VALUE_MASK; /* boundary check */ if (ord > priv->table1_len) { IPW_DEBUG_ORD("ordinal value too long\n"); return -EINVAL; } /* verify we have enough room to store the value */ if (*len < sizeof(u32)) { IPW_DEBUG_ORD("ordinal buffer length too small, " "need %zd\n", sizeof(u32)); return -EINVAL; } *((u32 *) val) = ipw_read_reg32(priv, (priv->table1_addr + (ord << 2))); *len = sizeof(u32); break; case IPW_ORD_TABLE_2_MASK: /* * TABLE 2: Indirect access to a table of variable sized values * * This table consist of six values, each containing * - dword containing the starting offset of the data * - dword containing the lengh in the first 16bits * and the count in the second 16bits */ /* remove the table id from the ordinal */ ord &= IPW_ORD_TABLE_VALUE_MASK; /* boundary check */ if (ord > priv->table2_len) { IPW_DEBUG_ORD("ordinal value too long\n"); return -EINVAL; } /* get the address of statistic */ addr = ipw_read_reg32(priv, priv->table2_addr + (ord << 3)); /* get the second DW of statistics ; * two 16-bit words - first is length, second is count */ field_info = ipw_read_reg32(priv, priv->table2_addr + (ord << 3) + sizeof(u32)); /* get each entry length */ field_len = *((u16 *) & field_info); /* get number of entries */ field_count = *(((u16 *) & field_info) + 1); /* abort if not enought memory */ total_len = field_len * field_count; if (total_len > *len) { *len = total_len; return -EINVAL; } *len = total_len; if (!total_len) return 0; IPW_DEBUG_ORD("addr = 0x%08x, total_len = %i, " "field_info = 0x%08x\n", addr, total_len, field_info); ipw_read_indirect(priv, addr, val, total_len); break; default: IPW_DEBUG_ORD("Invalid ordinal!\n"); return -EINVAL; } return 0;}static void ipw_init_ordinals(struct ipw_priv *priv){ priv->table0_addr = IPW_ORDINALS_TABLE_LOWER; priv->table0_len = ipw_read32(priv, priv->table0_addr); IPW_DEBUG_ORD("table 0 offset at 0x%08x, len = %i\n", priv->table0_addr, priv->table0_len); priv->table1_addr = ipw_read32(priv, IPW_ORDINALS_TABLE_1); priv->table1_len = ipw_read_reg32(priv, priv->table1_addr); IPW_DEBUG_ORD("table 1 offset at 0x%08x, len = %i\n", priv->table1_addr, priv->table1_len); priv->table2_addr = ipw_read32(priv, IPW_ORDINALS_TABLE_2); priv->table2_len = ipw_read_reg32(priv, priv->table2_addr); priv->table2_len &= 0x0000ffff; /* use first two bytes */ IPW_DEBUG_ORD("table 2 offset at 0x%08x, len = %i\n", priv->table2_addr, priv->table2_len);}static u32 ipw_register_toggle(u32 reg){ reg &= ~IPW_START_STANDBY; if (reg & IPW_GATE_ODMA) reg &= ~IPW_GATE_ODMA; if (reg & IPW_GATE_IDMA) reg &= ~IPW_GATE_IDMA; if (reg & IPW_GATE_ADMA) reg &= ~IPW_GATE_ADMA; return reg;}/* * LED behavior: * - On radio ON, turn on any LEDs that require to be on during start * - On initialization, start unassociated blink * - On association, disable unassociated blink * - On disassociation, start unassociated blink * - On radio OFF, turn off any LEDs started during radio on * */#define LD_TIME_LINK_ON msecs_to_jiffies(300)#define LD_TIME_LINK_OFF msecs_to_jiffies(2700)#define LD_TIME_ACT_ON msecs_to_jiffies(250)static void ipw_led_link_on(struct ipw_priv *priv){ unsigned long flags; u32 led; /* If configured to not use LEDs, or nic_type is 1, * then we don't toggle a LINK led */ if (priv->config & CFG_NO_LED || priv->nic_type == EEPROM_NIC_TYPE_1) return; spin_lock_irqsave(&priv->lock, flags); if (!(priv->status & STATUS_RF_KILL_MASK) && !(priv->status & STATUS_LED_LINK_ON)) { IPW_DEBUG_LED("Link LED On\n"); led = ipw_read_reg32(priv, IPW_EVENT_REG); led |= priv->led_association_on; led = ipw_register_toggle(led); IPW_DEBUG_LED("Reg: 0x%08X\n", led); ipw_write_reg32(priv, IPW_EVENT_REG, led); priv->status |= STATUS_LED_LINK_ON; /* If we aren't associated, schedule turning the LED off */ if (!(priv->status & STATUS_ASSOCIATED)) queue_delayed_work(priv->workqueue, &priv->led_link_off, LD_TIME_LINK_ON); } spin_unlock_irqrestore(&priv->lock, flags);}static void ipw_bg_led_link_on(void *data){ struct ipw_priv *priv = data; mutex_lock(&priv->mutex); ipw_led_link_on(data); mutex_unlock(&priv->mutex);}static void ipw_led_link_off(struct ipw_priv *priv){ unsigned long flags; u32 led; /* If configured not to use LEDs, or nic type is 1, * then we don't goggle the LINK led. */ if (priv->config & CFG_NO_LED || priv->nic_type == EEPROM_NIC_TYPE_1) return; spin_lock_irqsave(&priv->lock, flags); if (priv->status & STATUS_LED_LINK_ON) { led = ipw_read_reg32(priv, IPW_EVENT_REG); led &= priv->led_association_off; led = ipw_register_toggle(led); IPW_DEBUG_LED("Reg: 0x%08X\n", led); ipw_write_reg32(priv, IPW_EVENT_REG, led); IPW_DEBUG_LED("Link LED Off\n"); priv->status &= ~STATUS_LED_LINK_ON; /* If we aren't associated and the radio is on, schedule * turning the LED on (blink while unassociated) */ if (!(priv->status & STATUS_RF_KILL_MASK) && !(priv->status & STATUS_ASSOCIATED)) queue_delayed_work(priv->workqueue, &priv->led_link_on, LD_TIME_LINK_OFF); } spin_unlock_irqrestore(&priv->lock, flags);}static void ipw_bg_led_link_off(void *data){ struct ipw_priv *priv = data; mutex_lock(&priv->mutex); ipw_led_link_off(data); mutex_unlock(&priv->mutex);}static void __ipw_led_activity_on(struct ipw_priv *priv){ u32 led; if (priv->config & CFG_NO_LED) return; if (priv->status & STATUS_RF_KILL_MASK) return; if (!(priv->status & STATUS_LED_ACT_ON)) { led = ipw_read_reg32(priv, IPW_EVENT_REG); led |= priv->led_activity_on; led = ipw_register_toggle(led); IPW_DEBUG_LED("Reg: 0x%08X\n", led); ipw_write_reg32(priv, IPW_EVENT_REG, led); IPW_DEBUG_LED("Activity LED On\n"); priv->status |= STATUS_LED_ACT_ON; cancel_delayed_work(&priv->led_act_off); queue_delayed_work(priv->workqueue, &priv->led_act_off, LD_TIME_ACT_ON); } else { /* Reschedule LED off for full time period */ cancel_delayed_work(&priv->led_act_off); queue_delayed_work(priv->workqueue, &priv->led_act_off, LD_TIME_ACT_ON); }}#if 0void ipw_led_activity_on(struct ipw_priv *priv){ unsigned long flags; spin_lock_irqsave(&priv->lock, flags); __ipw_led_activity_on(priv); spin_unlock_irqrestore(&priv->lock, flags);}#endif /* 0 */static void ipw_led_activity_off(struct ipw_priv *priv){ unsigned long flags; u32 led;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -