static bool dbus_usb_dlneeded(void *bus) { usb_info_t *usbinfo = BUS_INFO(bus, usb_info_t); void *osinfo; bootrom_id_t id; bool dl_needed = TRUE; DBUSTRACE(("%s\n", __FUNCTION__)); if (usbinfo == NULL) return FALSE; osinfo = usbinfo->usbosl_info; ASSERT(osinfo); /* Check if firmware downloaded already by querying runtime ID */ id.chip = 0xDEAD; dbus_usbos_dl_cmd(osinfo, DL_GETVER, &id, sizeof(bootrom_id_t)); id.chip = ltoh32(id.chip); id.chiprev = ltoh32(id.chiprev); if (FALSE == dbus_usb_update_chipinfo(usbinfo, id.chip)) { dl_needed = FALSE; goto exit; } DBUSERR(("%s: chip 0x%x rev 0x%x\n", __FUNCTION__, id.chip, id.chiprev)); if (id.chip == POSTBOOT_ID) { /* This code is needed to support two enumerations on USB1.1 scenario */ DBUSERR(("%s: Firmware already downloaded\n", __FUNCTION__)); dbus_usbos_dl_cmd(osinfo, DL_RESETCFG, &id, sizeof(bootrom_id_t)); dl_needed = FALSE; if (usbinfo->pub->busstate == DBUS_STATE_DL_PENDING) usbinfo->pub->busstate = DBUS_STATE_DL_DONE; } else { usbinfo->pub->attrib.devid = id.chip; usbinfo->pub->attrib.chiprev = id.chiprev; } exit: return dl_needed; }
static int dbus_usb_dlrun(void *bus) { usb_info_t *usbinfo = BUS_INFO(bus, usb_info_t); void *osinfo; rdl_state_t state; int err = DBUS_OK; DBUSTRACE(("%s\n", __FUNCTION__)); if (usbinfo == NULL) return DBUS_ERR; if (USB_DEV_ISBAD(usbinfo)) return DBUS_ERR; osinfo = usbinfo->usbosl_info; ASSERT(osinfo); /* Check we are runnable */ dbus_usbos_dl_cmd(osinfo, DL_GETSTATE, &state, sizeof(rdl_state_t)); state.state = ltoh32(state.state); state.bytes = ltoh32(state.bytes); /* Start the image */ if (state.state == DL_RUNNABLE) { DBUSERR(("%s: Issue DL_GO\n", __FUNCTION__)); dbus_usbos_dl_cmd(osinfo, DL_GO, &state, sizeof(rdl_state_t)); /* FIX: Need this for 4326 for some reason * Same issue under both Linux/Windows */ if (usbinfo->pub->attrib.devid == TEST_CHIP) dbus_usbos_wait(osinfo, USB_DLGO_SPINWAIT); err = dbus_usb_resetcfg(usbinfo); } else { DBUSERR(("%s: Dongle not runnable\n", __FUNCTION__)); err = DBUS_ERR; } return err; }
static int dbus_usb_dlstart(void *bus, uint8 *fw, int len) { usb_info_t *usbinfo = BUS_INFO(bus, usb_info_t); int err; DBUSTRACE(("%s\n", __FUNCTION__)); if (usbinfo == NULL) return DBUS_ERR; if (USB_DEV_ISBAD(usbinfo)) return DBUS_ERR; err = dbus_usb_dl_writeimage(usbinfo, fw, len); if (err == DBUS_OK) usbinfo->pub->busstate = DBUS_STATE_DL_DONE; else usbinfo->pub->busstate = DBUS_STATE_DL_PENDING; return err; }
static int dbus_usb_dl_writeimage(usb_info_t *usbinfo, uint8 *fw, int fwlen) { osl_t *osh = usbinfo->pub->osh; void *osinfo = usbinfo->usbosl_info; unsigned int sendlen, sent, dllen; char *bulkchunk = NULL, *dlpos; rdl_state_t state; int err = DBUS_OK; bootrom_id_t id; uint16 wait, wait_time; bulkchunk = MALLOC(osh, RDL_CHUNK); if (bulkchunk == NULL) { err = DBUS_ERR; goto fail; } sent = 0; dlpos = fw; dllen = fwlen; /* Get chip id and rev */ id.chip = usbinfo->pub->attrib.devid; id.chiprev = usbinfo->pub->attrib.chiprev; DBUSTRACE(("enter %s: fwlen=%d\n", __FUNCTION__, fwlen)); dbus_usbos_dl_cmd(osinfo, DL_GETSTATE, &state, sizeof(rdl_state_t)); /* 3) Load the image */ while ((sent < dllen)) { /* Wait until the usb device reports it received all the bytes we sent */ if (sent < dllen) { if ((dllen-sent) < RDL_CHUNK) sendlen = dllen-sent; else sendlen = RDL_CHUNK; /* simply avoid having to send a ZLP by ensuring we never have an even * multiple of 64 */ if (!(sendlen % 64)) sendlen -= 4; /* send data */ memcpy(bulkchunk, dlpos, sendlen); if (!dbus_usbos_dl_send_bulk(osinfo, bulkchunk, sendlen)) { err = DBUS_ERR; goto fail; } dlpos += sendlen; sent += sendlen; DBUSTRACE(("%s: sendlen %d\n", __FUNCTION__, sendlen)); } /* 43236a0 bootloader runs from sflash, which is slower than rom * Wait for downloaded image crc check to complete in the dongle */ wait = 0; wait_time = USB_SFLASH_DLIMAGE_SPINWAIT; while (!dbus_usbos_dl_cmd(osinfo, DL_GETSTATE, &state, sizeof(rdl_state_t))) { if ((id.chip == 43236) && (id.chiprev == 0)) { DBUSERR(("%s: 43236a0 SFlash delay, waiting for dongle crc check " "completion!!!\n", __FUNCTION__)); dbus_usbos_wait(osinfo, wait_time); wait += wait_time; if (wait >= USB_SFLASH_DLIMAGE_LIMIT) { DBUSERR(("%s: DL_GETSTATE Failed xxxx\n", __FUNCTION__)); err = DBUS_ERR; goto fail; break; } } else { DBUSERR(("%s: DL_GETSTATE Failed xxxx\n", __FUNCTION__)); err = DBUS_ERR; goto fail; } } state.state = ltoh32(state.state); state.bytes = ltoh32(state.bytes); /* restart if an error is reported */ if ((state.state == DL_BAD_HDR) || (state.state == DL_BAD_CRC)) { DBUSERR(("%s: Bad Hdr or Bad CRC state %d\n", __FUNCTION__, state.state)); err = DBUS_ERR; goto fail; } } fail: if (bulkchunk) MFREE(osh, bulkchunk, RDL_CHUNK); return err; }
static int dbus_usb_doiovar(usb_info_t *bus, const bcm_iovar_t *vi, uint32 actionid, const char *name, void *params, int plen, void *arg, int len, int val_size) { int bcmerror = 0; int32 int_val = 0; bool bool_val = 0; DBUSTRACE(("%s: Enter, action %d name %s params %p plen %d arg %p len %d val_size %d\n", __FUNCTION__, actionid, name, params, plen, arg, len, val_size)); if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0) goto exit; if (plen >= (int)sizeof(int_val)) bcopy(params, &int_val, sizeof(int_val)); bool_val = (int_val != 0) ? TRUE : FALSE; switch (actionid) { case IOV_SVAL(IOV_MEMBYTES): case IOV_GVAL(IOV_MEMBYTES): { uint32 address; uint size, dsize; uint8 *data; bool set = (actionid == IOV_SVAL(IOV_MEMBYTES)); ASSERT(plen >= 2*sizeof(int)); address = (uint32)int_val; bcopy((char *)params + sizeof(int_val), &int_val, sizeof(int_val)); size = (uint)int_val; /* Do some validation */ dsize = set ? plen - (2 * sizeof(int)) : len; if (dsize < size) { DBUSTRACE(("%s: error on %s membytes, addr 0x%08x size %d dsize %d\n", __FUNCTION__, (set ? "set" : "get"), address, size, dsize)); bcmerror = BCME_BADARG; break; } DBUSTRACE(("%s: Request to %s %d bytes at address 0x%08x\n", __FUNCTION__, (set ? "write" : "read"), size, address)); /* Generate the actual data pointer */ data = set ? (uint8*)params + 2 * sizeof(int): (uint8*)arg; /* Call to do the transfer */ bcmerror = dbus_usb_dl_writeimage(BUS_INFO(bus, usb_info_t), data, size); } break; case IOV_SVAL(IOV_SET_DOWNLOAD_STATE): if (bool_val == TRUE) { bcmerror = dbus_usb_dlneeded(bus); dbus_usb_rdl_dwnld_state(BUS_INFO(bus, usb_info_t)); } else { usb_info_t *usbinfo = BUS_INFO(bus, usb_info_t); bcmerror = dbus_usb_dlrun(bus); usbinfo->pub->busstate = DBUS_STATE_DL_DONE; } break; case IOV_GVAL(IOV_HSIC_SLEEP): bool_val = dbus_usb_sleep_resume_state(BUS_INFO(bus, usb_info_t)); bcopy(&bool_val, arg, val_size); break; case IOV_SVAL(IOV_HSIC_SLEEP): bcmerror = dbus_usb_sleep(BUS_INFO(bus, usb_info_t), bool_val); break; case IOV_GVAL(IOV_HSIC_AUTOSLEEP): bool_val = dbus_usb_autosleep_state(BUS_INFO(bus, usb_info_t)); bcopy(&bool_val, arg, val_size); break; case IOV_SVAL(IOV_HSIC_AUTOSLEEP): bcmerror = dbus_usb_autosleep(BUS_INFO(bus, usb_info_t), bool_val); break; case IOV_SVAL(IOV_VARS): bcmerror = dhdusb_downloadvars(BUS_INFO(bus, usb_info_t), arg, len); break; default: bcmerror = BCME_UNSUPPORTED; break; } exit: return bcmerror; }