summaryrefslogtreecommitdiff
path: root/sys/dev/pcmcia
diff options
context:
space:
mode:
authorMarcus Glocker <mglocker@cvs.openbsd.org>2007-05-25 05:33:52 +0000
committerMarcus Glocker <mglocker@cvs.openbsd.org>2007-05-25 05:33:52 +0000
commitaf616b9cc39f0ab0a299bba062425b861834344b (patch)
treecb4c83eb332b9ae92e3a2e1da277587c2f577e44 /sys/dev/pcmcia
parentc07b718dd1c51a12f60549c721a117b000eb5833 (diff)
Initial driver stub for the Marvell 88W8385 PCMCIA (CF) device.
Loads firmware, sends first FW command, establish interrupts.
Diffstat (limited to 'sys/dev/pcmcia')
-rw-r--r--sys/dev/pcmcia/files.pcmcia6
-rw-r--r--sys/dev/pcmcia/if_malo.c665
-rw-r--r--sys/dev/pcmcia/if_maloreg.h44
-rw-r--r--sys/dev/pcmcia/if_malovar.h74
4 files changed, 788 insertions, 1 deletions
diff --git a/sys/dev/pcmcia/files.pcmcia b/sys/dev/pcmcia/files.pcmcia
index 7dae5f395f6..5190c0f366b 100644
--- a/sys/dev/pcmcia/files.pcmcia
+++ b/sys/dev/pcmcia/files.pcmcia
@@ -1,4 +1,4 @@
-# $OpenBSD: files.pcmcia,v 1.40 2006/11/28 12:01:27 miod Exp $
+# $OpenBSD: files.pcmcia,v 1.41 2007/05/25 05:33:51 mglocker Exp $
# $NetBSD: files.pcmcia,v 1.9 1998/06/21 18:45:41 christos Exp $
#
# Config.new file and device description for machine-independent PCMCIA code.
@@ -73,6 +73,10 @@ file dev/pcmcia/if_cnw.c cnw
attach wi at pcmcia with wi_pcmcia
file dev/pcmcia/if_wi_pcmcia.c wi_pcmcia
+# Marvell 88W8385
+attach malo at pcmcia with malo_pcmcia
+file dev/pcmcia/if_malo.c malo_pcmcia
+
# AMD 79c930-based 802.11 cards (including BayStack 650 FH card).
device awi: ether, ifnet
attach awi at pcmcia with awi_pcmcia
diff --git a/sys/dev/pcmcia/if_malo.c b/sys/dev/pcmcia/if_malo.c
new file mode 100644
index 00000000000..95412e56603
--- /dev/null
+++ b/sys/dev/pcmcia/if_malo.c
@@ -0,0 +1,665 @@
+/* $OpenBSD: if_malo.c,v 1.1 2007/05/25 05:33:51 mglocker Exp $ */
+
+/*
+ * Copyright (c) 2007 Marcus Glocker <mglocker@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/timeout.h>
+#include <sys/socket.h>
+#include <sys/tree.h>
+#include <sys/malloc.h>
+#include <sys/sockio.h>
+
+#include <net/if.h>
+#include <net/if_media.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/if_ether.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <machine/bus.h>
+
+#include <dev/pcmcia/pcmciareg.h>
+#include <dev/pcmcia/pcmciavar.h>
+#include <dev/pcmcia/pcmciadevs.h>
+
+#include <dev/pcmcia/if_malovar.h>
+#include <dev/pcmcia/if_maloreg.h>
+
+/*
+ * Driver for the Marvell 88W8385 CF chip.
+ */
+
+#ifdef CMALO_DEBUG
+int cmalo_d = 1;
+#define DPRINTF(l, x...) do { if ((l) <= cmalo_d) printf(x); } while (0)
+#else
+#define DPRINTF(l, x...)
+#endif
+
+int malo_pcmcia_match(struct device *, void *, void *);
+void malo_pcmcia_attach(struct device *, struct device *, void *);
+int malo_pcmcia_detach(struct device *, int);
+int malo_pcmcia_activate(struct device *, enum devact);
+
+void cmalo_attach(void *);
+int cmalo_ioctl(struct ifnet *, u_long, caddr_t);
+int cmalo_fw_load_helper(struct malo_softc *);
+int cmalo_fw_load_main(struct malo_softc *);
+int cmalo_init(struct ifnet *);
+void cmalo_stop(struct malo_softc *);
+int cmalo_detach(void *);
+int cmalo_intr(void *);
+void cmalo_intr_mask(struct malo_softc *sc, int);
+
+void cmalo_hexdump(void *, int);
+int cmalo_cmd_get_hwspec(struct malo_softc *);
+int cmalo_cmd_rsp_hwspec(struct malo_softc *);
+int cmalo_cmd_response(struct malo_softc *);
+
+/*
+ * PCMCIA bus.
+ */
+struct malo_pcmcia_softc {
+ struct malo_softc sc_malo;
+
+ struct pcmcia_function *sc_pf;
+ struct pcmcia_io_handle sc_pcioh;
+ int sc_io_window;
+ void *sc_ih;
+};
+
+struct cfattach malo_pcmcia_ca = {
+ sizeof(struct malo_pcmcia_softc),
+ malo_pcmcia_match,
+ malo_pcmcia_attach,
+ malo_pcmcia_detach,
+ malo_pcmcia_activate
+};
+
+int
+malo_pcmcia_match(struct device *parent, void *match, void *aux)
+{
+ struct pcmcia_attach_args *pa = aux;
+
+ if (pa->manufacturer == PCMCIA_VENDOR_AMBICOM &&
+ pa->product == PCMCIA_PRODUCT_AMBICOM_WL54CF)
+ return (1);
+
+ return (0);
+}
+
+void
+malo_pcmcia_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct malo_pcmcia_softc *psc = (struct malo_pcmcia_softc *)self;
+ struct malo_softc *sc = &psc->sc_malo;
+ struct pcmcia_attach_args *pa = aux;
+ struct pcmcia_config_entry *cfe;
+ const char *intrstr = NULL;
+
+ psc->sc_pf = pa->pf;
+ cfe = SIMPLEQ_FIRST(&pa->pf->cfe_head);
+
+ /* enable card */
+ pcmcia_function_init(psc->sc_pf, cfe);
+ if (pcmcia_function_enable(psc->sc_pf)) {
+ printf(": can't enable function!\n");
+ return;
+ }
+
+ /* allocate I/O space */
+ if (pcmcia_io_alloc(psc->sc_pf, 0,
+ cfe->iospace[0].length, cfe->iospace[0].length, &psc->sc_pcioh)) {
+ printf(": can't allocate i/o space!\n");
+ pcmcia_function_disable(psc->sc_pf);
+ return;
+ }
+
+ /* map I/O space */
+ if (pcmcia_io_map(psc->sc_pf, PCMCIA_WIDTH_IO16, 0,
+ cfe->iospace[0].length, &psc->sc_pcioh, &psc->sc_io_window)) {
+ printf(": can't map i/o space!\n");
+ pcmcia_io_free(psc->sc_pf, &psc->sc_pcioh);
+ pcmcia_function_disable(psc->sc_pf);
+ return;
+ }
+ sc->sc_iot = psc->sc_pcioh.iot;
+ sc->sc_ioh = psc->sc_pcioh.ioh;
+
+ printf(" port 0x%x/%d", psc->sc_pcioh.addr, psc->sc_pcioh.size);
+
+ /* establish interrupt */
+ psc->sc_ih = pcmcia_intr_establish(psc->sc_pf, IPL_NET, cmalo_intr, sc,
+ sc->sc_dev.dv_xname);
+ if (psc->sc_ih == NULL) {
+ printf(": can't establish interrupt!\n");
+ return;
+ }
+ intrstr = pcmcia_intr_string(psc->sc_pf, psc->sc_ih);
+ if (intrstr != NULL) {
+ if (*intrstr != NULL)
+ printf(", %s", intrstr);
+ }
+ printf("\n");
+
+ /* attach device */
+ if (rootvp == NULL)
+ mountroothook_establish(cmalo_attach, sc);
+ else
+ cmalo_attach(sc);
+}
+
+int
+malo_pcmcia_detach(struct device *dev, int flags)
+{
+ struct malo_pcmcia_softc *psc = (struct malo_pcmcia_softc *)dev;
+ struct malo_softc *sc = &psc->sc_malo;
+ int error;
+
+ if ((error = cmalo_detach(sc)))
+ return (error);
+
+ pcmcia_io_unmap(psc->sc_pf, psc->sc_io_window);
+ pcmcia_io_free(psc->sc_pf, &psc->sc_pcioh);
+
+ return (0);
+}
+
+int
+malo_pcmcia_activate(struct device *dev, enum devact act)
+{
+ struct malo_pcmcia_softc *psc = (struct malo_pcmcia_softc *)dev;
+ struct malo_softc *sc = &psc->sc_malo;
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ifnet *ifp = &ic->ic_if;
+ int s;
+
+ s = splnet();
+ switch (act) {
+ case DVACT_ACTIVATE:
+ pcmcia_function_enable(psc->sc_pf);
+ psc->sc_ih = pcmcia_intr_establish(psc->sc_pf, IPL_NET,
+ cmalo_intr, sc, sc->sc_dev.dv_xname);
+ cmalo_init(ifp);
+ break;
+ case DVACT_DEACTIVATE:
+ ifp->if_timer = 0;
+ if (ifp->if_flags & IFF_RUNNING)
+ cmalo_stop(sc);
+ pcmcia_intr_disestablish(psc->sc_pf, psc->sc_ih);
+ pcmcia_function_disable(psc->sc_pf);
+ break;
+ }
+ splx(s);
+
+ return (0);
+}
+
+/*
+ * Driver.
+ */
+void
+cmalo_attach(void *arg)
+{
+ struct malo_softc *sc = arg;
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ifnet *ifp = &sc->sc_ic.ic_if;
+ int i;
+
+ /* disable interrupts */
+ cmalo_intr_mask(sc, 0);
+
+ /* load firmware */
+ if (cmalo_fw_load_helper(sc) != 0)
+ return;
+ if (cmalo_fw_load_main(sc) != 0)
+ return;
+
+ /* enable interrupts */
+ cmalo_intr_mask(sc, 1);
+
+ /* allocate command buffer */
+ sc->sc_cmd = malloc(CMD_BUFFER_SIZE, M_USBDEV, M_WAITOK);
+
+ /* get hardware specs */
+ cmalo_cmd_get_hwspec(sc);
+ delay(1000); /* XXX */
+
+ /* setup interface */
+ ifp->if_softc = sc;
+ ifp->if_ioctl = cmalo_ioctl;
+ ifp->if_init = cmalo_init;
+ //ifp->if_start = cmalo_start;
+ //ifp->if_watchdog = cmalo_watchdog;
+ ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST;
+ strlcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ);
+
+ ic->ic_opmode = IEEE80211_M_STA;
+ ic->ic_state = IEEE80211_S_INIT;
+ ic->ic_caps =
+ IEEE80211_C_IBSS |
+ IEEE80211_C_WEP;
+
+ ic->ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b;
+ ic->ic_sup_rates[IEEE80211_MODE_11G] = ieee80211_std_rateset_11g;
+
+ for (i = 0; i <= 14; i++) {
+ ic->ic_channels[i].ic_freq =
+ ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ);
+ ic->ic_channels[i].ic_flags =
+ IEEE80211_CHAN_B |
+ IEEE80211_CHAN_G;
+ }
+
+ /* attach interface */
+ if_attach(ifp);
+ ieee80211_ifattach(ifp);
+
+ ieee80211_media_init(ifp, ieee80211_media_change,
+ ieee80211_media_status);
+
+ /* second attach line */
+ printf("%s: address %s\n",
+ sc->sc_dev.dv_xname, ether_sprintf(ic->ic_myaddr));
+}
+
+int
+cmalo_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
+{
+ struct malo_softc *sc = ifp->if_softc;
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ifaddr *ifa;
+ int s, error = 0;
+
+ s = splnet();
+
+ switch (cmd) {
+ case SIOCSIFADDR:
+ ifa = (struct ifaddr *)data;
+ ifp->if_flags |= IFF_UP;
+#ifdef INET
+ if (ifa->ifa_addr->sa_family == AF_INET)
+ arp_ifinit(&ic->ic_ac, ifa);
+#endif
+ /* FALLTHROUGH */
+ case SIOCSIFFLAGS:
+ if ((ifp->if_flags & IFF_UP)) {
+ if (!(ifp->if_flags & IFF_RUNNING))
+ cmalo_init(ifp);
+ } else {
+ if ((ifp->if_flags & IFF_RUNNING))
+ cmalo_stop(sc);
+ }
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+
+ splx(s);
+
+ return (error);
+}
+
+int
+cmalo_fw_load_helper(struct malo_softc *sc)
+{
+ const char *name = "mrv8385-h.fw";
+ size_t usize;
+ uint8_t *ucode, val8;
+ int offset, error, bsize, i;
+
+ /* verify if the card is ready for firmware download */
+ val8 = MALO_READ_1(sc, MALO_REG_SCRATCH);
+ if (val8 == MALO_VAL_SCRATCH_FW_LOADED)
+ /* firmware already loaded */
+ return (0);
+ if (val8 != MALO_VAL_SCRATCH_READY) {
+ /* bad register value */
+ printf("%s: device not ready for FW download!\n",
+ sc->sc_dev.dv_xname);
+ return (EIO);
+ }
+
+ /* read helper firmware image */
+ if ((error = loadfirmware(name, &ucode, &usize)) != 0) {
+ printf("%s: can't read microcode %s (error %d)!\n",
+ sc->sc_dev.dv_xname, name, error);
+ return (EIO);
+ }
+
+ /* download the helper firmware */
+ for (offset = 0; offset < usize; offset += bsize) {
+ if (usize - offset >= FW_HELPER_BSIZE)
+ bsize = FW_HELPER_BSIZE;
+ else
+ bsize = usize - offset;
+
+ /* send a block in words and confirm it */
+ DPRINTF(2, "%s: download helper FW block (%d bytes, %d off)\n",
+ sc->sc_dev.dv_xname, bsize, offset);
+ MALO_WRITE_2(sc, MALO_REG_CMD_WRITE_LEN, bsize);
+ MALO_WRITE_MULTI_2(sc, MALO_REG_CMD_WRITE, (ucode + offset),
+ bsize / 2);
+ MALO_WRITE_1(sc, MALO_REG_HOST_STATUS, MALO_VAL_DNLD_OVER);
+ MALO_WRITE_2(sc, MALO_REG_CARD_INTR_CAUSE, MALO_VAL_DNLD_OVER);
+
+ /* poll for an acknowledgement */
+ for (i = 0; i < 50; i++) {
+ if (MALO_READ_1(sc, MALO_REG_CARD_STATUS) ==
+ MALO_VAL_DNLD_OVER)
+ break;
+ delay(1000);
+ }
+ if (i == 50) {
+ printf("%s: timeout while helper FW block download!\n",
+ sc->sc_dev.dv_xname);
+ free(ucode, M_DEVBUF);
+ return (EIO);
+ }
+ }
+ free(ucode, M_DEVBUF);
+
+ /* helper firmware download done */
+ MALO_WRITE_2(sc, MALO_REG_CMD_WRITE_LEN, 0);
+ MALO_WRITE_1(sc, MALO_REG_HOST_STATUS, MALO_VAL_DNLD_OVER);
+ MALO_WRITE_2(sc, MALO_REG_CARD_INTR_CAUSE, MALO_VAL_DNLD_OVER);
+ DPRINTF(1, "%s: helper FW downloaded\n", sc->sc_dev.dv_xname);
+
+ return (0);
+}
+
+int
+cmalo_fw_load_main(struct malo_softc *sc)
+{
+ const char *name = "mrv8385-m.fw";
+ size_t usize;
+ uint8_t *ucode;
+ uint16_t val16;
+ int offset, error, bsize, retry, i;
+
+ /* read main firmware image */
+ if ((error = loadfirmware(name, &ucode, &usize)) != 0) {
+ printf("%s: can't read microcode %s (error %d)!\n",
+ sc->sc_dev.dv_xname, name, error);
+ return (EIO);
+ }
+
+ /* verify if the helper firmware has been loaded correctly */
+ for (i = 0; i < 10; i++) {
+ if (MALO_READ_1(sc, MALO_REG_RBAL) == FW_HELPER_OK)
+ break;
+ delay(1000);
+ }
+ if (i == 10) {
+ printf("%s: helper FW not loaded!\n", sc->sc_dev.dv_xname);
+ free(ucode, M_DEVBUF);
+ return (EIO);
+ }
+ DPRINTF(1, "%s: helper FW loaded successfully\n", sc->sc_dev.dv_xname);
+
+ /* download the main firmware */
+ for (offset = 0; offset < usize; offset += bsize) {
+ val16 = MALO_READ_2(sc, MALO_REG_RBAL);
+ /*
+ * If the helper firmware serves us an odd integer then
+ * something went wrong and we retry to download the last
+ * block until we receive a good integer again, or give up.
+ */
+ if (val16 & 0x0001) {
+ if (retry > FW_MAIN_MAX_RETRY) {
+ printf("%s: main FW download failed!\n",
+ sc->sc_dev.dv_xname);
+ free(ucode, M_DEVBUF);
+ return (EIO);
+ }
+ retry++;
+ offset -= bsize;
+ } else {
+ retry = 0;
+ bsize = val16;
+ }
+
+ /* send a block in words and confirm it */
+ DPRINTF(2, "%s: download main FW block (%d bytes, %d off)\n",
+ sc->sc_dev.dv_xname, bsize, offset);
+ MALO_WRITE_2(sc, MALO_REG_CMD_WRITE_LEN, bsize);
+ MALO_WRITE_MULTI_2(sc, MALO_REG_CMD_WRITE, (ucode + offset),
+ bsize / 2);
+ MALO_WRITE_1(sc, MALO_REG_HOST_STATUS, MALO_VAL_DNLD_OVER);
+ MALO_WRITE_2(sc, MALO_REG_CARD_INTR_CAUSE, MALO_VAL_DNLD_OVER);
+
+ /* poll for an acknowledgement */
+ for (i = 0; i < 5000; i++) {
+ if (MALO_READ_1(sc, MALO_REG_CARD_STATUS) ==
+ MALO_VAL_DNLD_OVER)
+ break;
+ }
+ if (i == 5000) {
+ printf("%s: timeout while main FW block download!\n",
+ sc->sc_dev.dv_xname);
+ free(ucode, M_DEVBUF);
+ return (EIO);
+ }
+ }
+ free(ucode, M_DEVBUF);
+
+ DPRINTF(1, "%s: main FW downloaded\n", sc->sc_dev.dv_xname);
+
+ /* verify if the main firmware has been loaded correctly */
+ for (i = 0; i < 50; i++) {
+ if (MALO_READ_1(sc, MALO_REG_SCRATCH) ==
+ MALO_VAL_SCRATCH_FW_LOADED)
+ break;
+ delay(1000);
+ }
+ if (i == 50) {
+ printf("%s: main FW not loaded!\n", sc->sc_dev.dv_xname);
+ return (EIO);
+ }
+
+ DPRINTF(1, "%s: main FW loaded successfully\n", sc->sc_dev.dv_xname);
+
+ return (0);
+}
+
+int
+cmalo_init(struct ifnet *ifp)
+{
+ //struct malo_softc *sc = ifp->if_softc;
+
+ return (0);
+}
+
+void
+cmalo_stop(struct malo_softc *sc)
+{
+
+}
+
+int
+cmalo_detach(void *arg)
+{
+ struct malo_softc *sc = arg;
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ifnet *ifp = &ic->ic_if;
+
+ /* free command buffer */
+ free(sc->sc_cmd, M_DEVBUF);
+
+ /* detach inferface */
+ ieee80211_ifdetach(ifp);
+ if_detach(ifp);
+
+ return (0);
+}
+
+int
+cmalo_intr(void *arg)
+{
+ struct malo_softc *sc = arg;
+ uint16_t intr;
+
+ intr = MALO_READ_2(sc, MALO_REG_HOST_INTR_CAUSE);
+
+ DPRINTF(2, "%s: interrupt handler called (intr = 0x%04x)\n",
+ sc->sc_dev.dv_xname, intr);
+
+ if (intr == 0) {
+ /* interrupt not for us */
+ return (0);
+ }
+ if (intr == 0xffff) {
+ /* card has been detached */
+ return (0);
+ }
+
+ if (intr & MALO_VAL_HOST_INTR_CMD) {
+ /* command response */
+ cmalo_cmd_response(sc);
+ }
+
+ /* acknowledge interrupt */
+ intr &= MALO_VAL_HOST_INTR_MASK_ON;
+ MALO_WRITE_2(sc, MALO_REG_HOST_INTR_CAUSE, intr);
+
+ return (1);
+}
+
+void
+cmalo_intr_mask(struct malo_softc *sc, int enable)
+{
+ uint16_t val16;
+
+ val16 = MALO_READ_2(sc, MALO_REG_HOST_INTR_MASK);
+
+ DPRINTF(1, "%s: intr mask changed from 0x%04x ",
+ sc->sc_dev.dv_xname, val16);
+
+ if (enable)
+ MALO_WRITE_2(sc, MALO_REG_HOST_INTR_MASK,
+ val16 & ~MALO_VAL_HOST_INTR_MASK_ON);
+ else
+ MALO_WRITE_2(sc, MALO_REG_HOST_INTR_MASK,
+ val16 | MALO_VAL_HOST_INTR_MASK_ON);
+
+ val16 = MALO_READ_2(sc, MALO_REG_HOST_INTR_MASK);
+
+ DPRINTF(1, "to 0x%04x\n", val16);
+}
+
+void
+cmalo_hexdump(void *buf, int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++) {
+ if (i % 16 == 0)
+ printf("%s%4i:", i ? "\n" : "", i);
+ if (i % 4 == 0)
+ printf(" ");
+ printf("%02x", (int)*((u_char *)buf + i));
+ }
+
+ printf("\n");
+}
+
+int
+cmalo_cmd_get_hwspec(struct malo_softc *sc)
+{
+ struct malo_cmd_header *hdr = sc->sc_cmd;
+ struct malo_cmd_body_spec *body;
+
+ bzero(sc->sc_cmd, CMD_BUFFER_SIZE);
+
+ hdr->cmd = htole16(MALO_VAL_CMD_HWSPEC);
+ hdr->size = htole16(sizeof(*hdr) + sizeof(*body));
+ hdr->seqnum = htole16(1);
+ hdr->result = 0;
+ body = (struct malo_cmd_body_spec *)(hdr + 1);
+
+ /* set all bits for MAC address, otherwise we won't get one back */
+ memset(body->macaddr, 0xff, ETHER_ADDR_LEN);
+
+ cmalo_hexdump(sc->sc_cmd, hdr->size);
+
+ /* send command request */
+ MALO_WRITE_2(sc, MALO_REG_CMD_WRITE_LEN, hdr->size);
+ MALO_WRITE_MULTI_2(sc, MALO_REG_CMD_WRITE, hdr, hdr->size / 2);
+ MALO_WRITE_1(sc, MALO_REG_HOST_STATUS, MALO_VAL_DNLD_OVER);
+ MALO_WRITE_2(sc, MALO_REG_CARD_INTR_CAUSE, MALO_VAL_DNLD_OVER);
+
+ return (0);
+}
+
+int
+cmalo_cmd_rsp_hwspec(struct malo_softc *sc)
+{
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct malo_cmd_header *hdr = sc->sc_cmd;
+ struct malo_cmd_body_spec *body;
+ int i;
+
+ body = (struct malo_cmd_body_spec *)(hdr + 1);
+
+ /* get our MAC address */
+ for (i = 0; i < ETHER_ADDR_LEN; i++)
+ ic->ic_myaddr[i] = body->macaddr[i];
+
+ return (0);
+}
+
+int
+cmalo_cmd_response(struct malo_softc *sc)
+{
+ struct malo_cmd_header *hdr = sc->sc_cmd;
+ int len;
+
+ bzero(sc->sc_cmd, CMD_BUFFER_SIZE);
+
+ /* read the whole command answer */
+ len = MALO_READ_2(sc, MALO_REG_CMD_READ_LEN);
+ MALO_READ_MULTI_2(sc, MALO_REG_CMD_READ, sc->sc_cmd, len / 2);
+
+ cmalo_hexdump(sc->sc_cmd, len);
+
+ /* check for a valid command response */
+ if (!(hdr->cmd & MALO_VAL_CMD_RESP)) {
+ printf("%s: got invalid command response (0x%04x)!\n",
+ sc->sc_dev.dv_xname, hdr->cmd);
+ return (EIO);
+ }
+ hdr->cmd &= ~MALO_VAL_CMD_RESP;
+
+ /* to which command does the response belong */
+ switch (hdr->cmd) {
+ case MALO_VAL_CMD_HWSPEC:
+ cmalo_cmd_rsp_hwspec(sc);
+ break;
+ default:
+ printf("%s: got unknown command response (0x%04x)!\n",
+ sc->sc_dev.dv_xname, hdr->cmd);
+ break;
+ }
+
+ return (0);
+}
diff --git a/sys/dev/pcmcia/if_maloreg.h b/sys/dev/pcmcia/if_maloreg.h
new file mode 100644
index 00000000000..b5202ad4563
--- /dev/null
+++ b/sys/dev/pcmcia/if_maloreg.h
@@ -0,0 +1,44 @@
+/* $OpenBSD: if_maloreg.h,v 1.1 2007/05/25 05:33:51 mglocker Exp $ */
+
+/*
+ * Copyright (c) 2007 Marcus Glocker <mglocker@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* I/O registers */
+#define MALO_REG_HOST_STATUS 0x00
+#define MALO_REG_CARD_INTR_CAUSE 0x02
+#define MALO_REG_HOST_INTR_MASK 0x04
+#define MALO_REG_CMD_READ 0x12
+#define MALO_REG_CMD_WRITE_LEN 0x18
+#define MALO_REG_CMD_WRITE 0x1a
+#define MALO_REG_CARD_STATUS 0x20
+#define MALO_REG_HOST_INTR_CAUSE 0x22
+#define MALO_REG_RBAL 0x28
+#define MALO_REG_CMD_READ_LEN 0x30
+#define MALO_REG_SCRATCH 0x3f
+#define MALO_REG_CARD_INTR_MASK 0x44
+
+/* register values */
+#define MALO_VAL_SCRATCH_READY 0x00
+#define MALO_VAL_SCRATCH_FW_LOADED 0x5a
+#define MALO_VAL_HOST_INTR_MASK_ON 0x001f
+#define MALO_VAL_DNLD_OVER (1 << 2)
+
+/* interrupt reasons */
+#define MALO_VAL_HOST_INTR_CMD (1 << 3)
+
+/* FW commands */
+#define MALO_VAL_CMD_RESP 0x8000
+#define MALO_VAL_CMD_HWSPEC 0x0003
diff --git a/sys/dev/pcmcia/if_malovar.h b/sys/dev/pcmcia/if_malovar.h
new file mode 100644
index 00000000000..5e79ea41483
--- /dev/null
+++ b/sys/dev/pcmcia/if_malovar.h
@@ -0,0 +1,74 @@
+/* $OpenBSD: if_malovar.h,v 1.1 2007/05/25 05:33:51 mglocker Exp $ */
+
+/*
+ * Copyright (c) 2007 Marcus Glocker <mglocker@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* simplify bus space access */
+#define MALO_READ_1(sc, reg) \
+ bus_space_read_1((sc)->sc_iot, (sc)->sc_ioh, (reg))
+#define MALO_READ_2(sc, reg) \
+ bus_space_read_2((sc)->sc_iot, (sc)->sc_ioh, (reg))
+#define MALO_READ_MULTI_2(sc, reg, off, size) \
+ bus_space_read_multi_2((sc)->sc_iot, (sc)->sc_ioh, (reg), (off), \
+ (size))
+#define MALO_WRITE_1(sc, reg, val) \
+ bus_space_write_1((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
+#define MALO_WRITE_2(sc, reg, val) \
+ bus_space_write_2((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
+#define MALO_WRITE_MULTI_2(sc, reg, off, size) \
+ bus_space_write_multi_2((sc)->sc_iot, (sc)->sc_ioh, (reg), (off), \
+ (size))
+
+/* miscellaneous */
+#define FW_HELPER_BSIZE 256 /* helper FW block size */
+#define FW_HELPER_OK 0x10 /* helper FW loaded */
+#define FW_MAIN_MAX_RETRY 20 /* main FW block resend max retry */
+#define CMD_BUFFER_SIZE 256 /* cmd buffer */
+
+/* FW command header */
+struct malo_cmd_header {
+ uint16_t cmd;
+ uint16_t size;
+ uint16_t seqnum;
+ uint16_t result;
+};
+
+/* FW command bodies */
+struct malo_cmd_body_spec {
+ uint16_t hw_if_version;
+ uint16_t hw_version;
+ uint16_t num_of_wcb;
+ uint16_t num_of_mcast;
+ uint8_t macaddr[ETHER_ADDR_LEN];
+ uint16_t regioncode;
+ uint16_t num_of_antenna;
+ uint32_t fw_version;
+ uint32_t wcbbase;
+ uint32_t rxpdrdptr;
+ uint32_t rxpdwrptr;
+ uint32_t fw_capinfo;
+};
+
+struct malo_softc {
+ struct device sc_dev;
+
+ struct ieee80211com sc_ic;
+
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_ioh;
+
+ void *sc_cmd;
+};