r3752 - trunk/src/host/qemu-neo1973/hw
andrew at sita.openmoko.org
andrew at sita.openmoko.org
Sat Dec 29 03:11:34 CET 2007
Author: andrew
Date: 2007-12-29 03:11:33 +0100 (Sat, 29 Dec 2007)
New Revision: 3752
Modified:
trunk/src/host/qemu-neo1973/hw/ar6000.c
Log:
Add Atheros WMI events framework - we get a correct MAC addr now.
Modified: trunk/src/host/qemu-neo1973/hw/ar6000.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/ar6000.c 2007-12-28 20:50:54 UTC (rev 3751)
+++ trunk/src/host/qemu-neo1973/hw/ar6000.c 2007-12-29 02:11:33 UTC (rev 3752)
@@ -1,5 +1,5 @@
/*
- * Atheros AR600X Wireless Ethernet SDIO cards. Firmware 1.3.
+ * ROCm Atheros AR600X Wireless Ethernet SDIO cards. Firmware 1.3.
*
* Copyright (c) 2007 OpenMoko, Inc.
* Author: Andrzej Zaborowski <andrew at openedhand.com>
@@ -942,6 +942,115 @@
return &s->card;
}
+/* WMI (Wireless Module Interface) */
+
+struct wmi_s {
+ NICInfo *nd;
+
+ void (*send)(void *opaque, const uint8_t *buffer, int len);
+ void *opaque;
+
+ QEMUTimer *alive;
+};
+
+#define WMI_MSG __attribute__((packed))
+
+struct wmi_msg_s {
+ uint16_t id;
+ uint8_t data[128];
+} WMI_MSG;
+
+static void wmi_make_event(struct wmi_s *s, uint16_t id,
+ uint8_t *data, int len)
+{
+ struct wmi_msg_s msg;
+
+ msg.id = id;
+ memcpy(msg.data, data, len);
+
+ s->send(s->opaque, (void *) &msg, sizeof(msg.id) + len);
+}
+
+enum {
+ WMI_READY_EVENTID = 0x1001,
+ WMI_CONNECT_EVENTID,
+ WMI_DISCONNECT_EVENTID,
+ WMI_BSSINFO_EVENTID,
+ WMI_CMDERROR_EVENTID,
+ WMI_REGDOMAIN_EVENTID,
+ WMI_PSTREAM_TIMEOUT_EVENTID,
+ WMI_NEIGHBOR_REPORT_EVENTID,
+ WMI_TKIP_MICERR_EVENTID,
+ WMI_SCAN_COMPLETE_EVENTID,
+ WMI_REPORT_STATISTICS_EVENTID,
+ WMI_RSSI_THRESHOLD_EVENTID,
+ WMI_ERROR_REPORT_EVENTID,
+ WMI_OPT_RX_FRAME_EVENTID,
+ WMI_REPORT_ROAM_TBL_EVENTID,
+ WMI_EXTENSION_EVENTID,
+ WMI_CAC_EVENTID,
+ WMI_SNR_THRESHOLD_EVENTID,
+ WMI_LQ_THRESHOLD_EVENTID,
+ WMI_TX_RETRY_ERR_EVENTID,
+ WMI_REPORT_ROAM_DATA_EVENTID,
+};
+
+enum {
+ WMI_11A_CAPABILITY = 1,
+ WMI_11G_CAPABILITY = 2,
+ WMI_11AG_CAPABILITY = 3,
+};
+
+struct wmi_ready_event_s {
+ uint8_t macaddr[6];
+ uint8_t phy_capability;
+} WMI_MSG;
+
+static void wmi_ready_event(struct wmi_s *s)
+{
+ struct wmi_ready_event_s ev;
+
+ memcpy(ev.macaddr, s->nd->macaddr, 6);
+ ev.phy_capability = WMI_11AG_CAPABILITY;
+
+ /* TODO: request buf, fill in, submit */
+ wmi_make_event(s, WMI_READY_EVENTID, (void *) &ev, sizeof(ev));
+}
+
+/* The interface is alive */
+static void wmi_alive_tick(void *opaque)
+{
+ struct wmi_s *s = (void *) opaque;
+
+ qemu_free_timer(s->alive);
+
+ /* Send the initial event */
+ wmi_ready_event(s);
+}
+
+static __attribute__((malloc)) struct wmi_s *wmi_init(NICInfo *nd,
+ void *opaque,
+ void (*send)(void *opaque, const uint8_t *buffer, int len))
+{
+ struct wmi_s *s = qemu_mallocz(sizeof(*s));
+
+ s->nd = nd;
+ s->opaque = opaque;
+ s->send = send;
+
+ s->alive = qemu_new_timer(vm_clock, wmi_alive_tick, s);
+ qemu_mod_timer(s->alive, qemu_get_clock(vm_clock) + (ticks_per_sec << 1));
+
+ return s;
+}
+
+static void wmi_done(struct wmi_s *wmi)
+{
+ free(wmi);
+}
+
+/* Atheros AR600x */
+
struct ar6k_s {
struct sdio_s sd;
NICInfo *nd;
@@ -953,7 +1062,7 @@
uint8_t counter_int_stat;
uint8_t mbox_frame;
uint8_t rx_la_valid;
- uint8_t rx_la[4];
+ uint32_t rx_la[4];
uint8_t int_stat_ena;
uint8_t cpu_int_stat_ena;
uint8_t err_int_stat_ena;
@@ -970,6 +1079,8 @@
int done;
} bmi;
+ struct wmi_s *wmi;
+
QEMUTimer *cnt_irq_update;
uint8_t cis[0];
@@ -1033,10 +1144,17 @@
ar6k_hif_counter_intr_update(s);
}
+/* Atheros BMI (Bootloader Messaging Interface) */
+
static void ar6k_bmi_reset(struct ar6k_s *s)
{
int i;
+ if (s->wmi) {
+ wmi_done(s->wmi);
+ s->wmi = 0;
+ }
+
for (i = 0; i < 4; i ++) {
s->hif.cnt[i] = 0x00;
s->hif.cnt_tx[i] = 0xff;
@@ -1122,6 +1240,15 @@
s->hif.cnt[0] = rlen;
}
+/* Atheros HTC/HIF */
+
+enum {
+ WMI_CONTROL_MBOX = 0,
+ WMI_BEST_EFFORT_MBOX,
+ WMI_LOW_PRIORITY_MBOX,
+ WMI_HIGH_PRIORITY_MBOX,
+};
+
static void ar6k_hif_txcredit_reset(struct ar6k_s *s, int mbox)
{
s->hif.cnt_tx[mbox] = 0;
@@ -1140,6 +1267,33 @@
}
}
+#define AR6K_HTC_HEADER_LEN 2
+
+static void ar6k_hif_wmi_event(void *opaque, const uint8_t *buffer, int len)
+{
+ struct ar6k_s *s = (void *) opaque;
+
+ int mbox = WMI_CONTROL_MBOX;
+ uint16_t *datap;
+
+ s->hif.rx_la[mbox] = len;
+ s->hif.rx_la_valid |= 1 << mbox;
+
+ datap = (void *) s->hif.mbox + ((mbox + 1) << 11) -
+ (len + AR6K_HTC_HEADER_LEN);
+
+ /* Prepend the HTC frame header */
+ cpu_to_le16wu(datap ++, len);
+
+ memcpy(datap, buffer, len);
+
+ if (!(s->hif.host_int_stat & (1 << mbox))) { /* STATUS_MBOX_DATA */
+ s->hif.host_int_stat |= 1 << mbox; /* STATUS_MBOX_DATA */
+
+ ar6k_hif_intr_update(s);
+ }
+}
+
#define AR6K_HOST_INT_STAT 0x400
#define AR6K_CPU_INT_STAT 0x401
#define AR6K_ERROR_INT_STAT 0x402
@@ -1206,24 +1360,11 @@
ar6k_hif_counter_intr_update(s);
}
break;
+
case AR6K_MBOX_FRAME:
s->hif.mbox_frame = value;
break;
- case AR6K_RX_LOOKAHEAD_VALID:
- s->hif.rx_la_valid = value;
- break;
- case AR6K_RX_LOOKAHEAD0:
- s->hif.rx_la[0] = value;
- break;
- case AR6K_RX_LOOKAHEAD1:
- s->hif.rx_la[1] = value;
- break;
- case AR6K_RX_LOOKAHEAD2:
- s->hif.rx_la[2] = value;
- break;
- case AR6K_RX_LOOKAHEAD3:
- s->hif.rx_la[3] = value;
- break;
+
case AR6K_INT_STAT_ENABLE:
if (s->hif.int_stat_ena ^ value) {
s->hif.int_stat_ena = value;
@@ -1248,9 +1389,11 @@
ar6k_hif_counter_intr_sched(s);
}
break;
+
case AR6K_SCRATCH ... (AR6K_SCRATCH + 7):
s->hif.scratch[addr - AR6K_SCRATCH] = value;
break;
+
case AR6K_FIFO_TIMEOUT:
case AR6K_FIFO_TIMEOUT_ENABLE:
case AR6K_DISABLE_SLEEP:
@@ -1260,8 +1403,10 @@
case AR6K_INT_WLAN:
s->hif.wlan_int = value;
- if (value)
- fprintf(stderr, "%s: WLAN interrupt\n", __FUNCTION__);
+ if (value && !s->wmi) {
+ /* Initialisation sequence is complete (?). */
+ s->wmi = wmi_init(s->nd, s, ar6k_hif_wmi_event);
+ }
break;
case AR6K_WINDOW_DATA:
@@ -1313,15 +1458,18 @@
case AR6K_RX_LOOKAHEAD_VALID:
return s->hif.rx_la_valid;
- case AR6K_RX_LOOKAHEAD0:
- return s->hif.rx_la[0];
- case AR6K_RX_LOOKAHEAD1:
- return s->hif.rx_la[1];
- case AR6K_RX_LOOKAHEAD2:
- return s->hif.rx_la[2];
- case AR6K_RX_LOOKAHEAD3:
- return s->hif.rx_la[3];
+ case AR6K_RX_LOOKAHEAD3 ... (AR6K_RX_LOOKAHEAD3 + 3): mbox ++;
+ case AR6K_RX_LOOKAHEAD2 ... (AR6K_RX_LOOKAHEAD2 + 3): mbox ++;
+ case AR6K_RX_LOOKAHEAD1 ... (AR6K_RX_LOOKAHEAD1 + 3): mbox ++;
+ case AR6K_RX_LOOKAHEAD0 ... (AR6K_RX_LOOKAHEAD0 + 3):
+ /* XXX when is the bit reset? */
+ s->hif.rx_la_valid &= ~(1 << mbox);
+ /* XXX when is the bit reset? */
+ s->hif.host_int_stat &= ~(1 << mbox); /* STATUS_MBOX_DATA */
+ ar6k_hif_intr_update(s);
+ return (s->hif.rx_la[mbox] >> ((addr & 3) << 3)) & 0xff;
+
case AR6K_INT_STAT_ENABLE:
return s->hif.int_stat_ena;
case AR6K_CPU_INT_STAT_ENABLE:
@@ -1394,7 +1542,6 @@
{
struct ar6k_s *s = (void *) sd;
- fprintf(stderr, "%s: writing %i bytes at %x\n", __FUNCTION__, len, addr);
for (; len; len --, addr += sd->transfer.step)
ar6k_hif_write(s, addr, *data ++);
}
@@ -1404,7 +1551,6 @@
{
struct ar6k_s *s = (void *) sd;
- fprintf(stderr, "%s: reading %i bytes at %x\n", __FUNCTION__, len, addr);
for (; len; len --, addr += sd->transfer.step)
*data ++ = ar6k_hif_read(s, addr);
}
More information about the commitlog
mailing list