static int dbus_usb_resetcfg(usb_info_t *usbinfo) { void *osinfo; bootrom_id_t id; uint16 wait = 0, wait_time; DBUSTRACE(("%s\n", __FUNCTION__)); if (usbinfo == NULL) return DBUS_ERR; osinfo = usbinfo->usbosl_info; ASSERT(osinfo); /* Give dongle chance to boot */ wait_time = USB_SFLASH_DLIMAGE_SPINWAIT; while (wait < USB_SFLASH_DLIMAGE_LIMIT) { dbus_usbos_wait(osinfo, wait_time); wait += wait_time; id.chip = 0xDEAD; /* Get the ID */ dbus_usbos_dl_cmd(osinfo, DL_GETVER, &id, sizeof(bootrom_id_t)); id.chip = ltoh32(id.chip); if (id.chip == POSTBOOT_ID) break; } if (id.chip == POSTBOOT_ID) { DBUSERR(("%s: download done %d ms postboot chip 0x%x/rev 0x%x\n", __FUNCTION__, wait, id.chip, id.chiprev)); dbus_usbos_dl_cmd(osinfo, DL_RESETCFG, &id, sizeof(bootrom_id_t)); dbus_usbos_wait(osinfo, USB_RESETCFG_SPINWAIT); return DBUS_OK; } else { DBUSERR(("%s: Cannot talk to Dongle. Firmware is not UP, %d ms \n", __FUNCTION__, wait)); return DBUS_ERR; } return DBUS_OK; }
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_dldr_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { int access_ok = 1, err = 0; unsigned int size; void *val = NULL; uint8 *buf = (uint8 *) arg; void *parms; char *name; int len = 0; size = _IOC_SIZE(cmd); if (_IOC_DIR(cmd) & _IOC_READ) access_ok = access_ok(VERIFY_WRITE, (void*) arg, size); else if (_IOC_DIR(cmd) & _IOC_WRITE) access_ok = access_ok(VERIFY_READ, (void*) arg, size); if (!access_ok) return -EFAULT; down(&g_probe_info.dlsem); switch (cmd) { case DBUS_GET_VAR: name = (char *)arg; parms = buf + strlen(buf) + 1; err = probe_iovar((const char *)name, parms, 0, (void *) arg, 0 /* len */, FALSE, &val, &len); if (val != NULL) { if (copy_to_user((void *)arg, val, len)) err = -EFAULT; } break; case DBUS_SET_VAR: name = (char *)arg; parms = buf + strlen(buf) + 1; err = probe_iovar((const char *)name, parms, 0, (void *) arg, 0 /* len */, TRUE, NULL, NULL); break; default: DBUSERR(("Unhandled char ioctl: %d\n", cmd)); err = -EINVAL; break; } if (err) err = -EFAULT; up(&g_probe_info.dlsem); return err; }
static bool dbus_usb_update_chipinfo(usb_info_t *usbinfo, uint32 chip) { bool retval = TRUE; /* based on the CHIP Id, store the ram size which is needed for NVRAM download. */ switch (chip) { case 0x4319: usbinfo->rdlram_size = RDL_RAM_SIZE_4319; usbinfo->rdlram_base_addr = RDL_RAM_BASE_4319; break; case 0x4329: usbinfo->rdlram_size = RDL_RAM_SIZE_4329; usbinfo->rdlram_base_addr = RDL_RAM_BASE_4329; break; case 43234: case 43235: case 43236: usbinfo->rdlram_size = RDL_RAM_SIZE_43236; usbinfo->rdlram_base_addr = RDL_RAM_BASE_43236; break; case 0x4328: usbinfo->rdlram_size = RDL_RAM_SIZE_4328; usbinfo->rdlram_base_addr = RDL_RAM_BASE_4328; break; case 0x4322: usbinfo->rdlram_size = RDL_RAM_SIZE_4322; usbinfo->rdlram_base_addr = RDL_RAM_BASE_4322; break; case POSTBOOT_ID: break; default: DBUSERR(("%s: Chip 0x%x Ram size is not known\n", __FUNCTION__, chip)); retval = FALSE; break; } return retval; }
int dbus_bus_osl_register(int vid, int pid, probe_cb_t prcb, disconnect_cb_t discb, void *prarg, dbus_intf_t **intf, void *param1, void *param2) { probe_info_t *pinfo = &g_probe_info; int err; probe_cb = prcb; disconnect_cb = discb; probe_arg = prarg; *intf = &dbus_sdos_intf; bzero(pinfo, sizeof(probe_info_t)); #ifdef CDEV_IOC_IF /* To support async probe callback when an image is downloadeda, * we need access to the driver before net interface is brought up. * Under Linux, we can create a download channel using char dev node interface. */ if (register_chrdev(CHARDEV_MAJOR, CHARDEV_NAME CHARDEV_SUFFIX, &dbus_dldr_fops)) DBUSERR(("register_chrdev failed\n")); else init_MUTEX(&g_probe_info.dlsem); #endif g_probe_info.dpc_pid = -1; err = bcmsdh_register(&sdh_driver); if (err == 0) err = DBUS_OK; else err = DBUS_ERR; if (delay_eth != 0) { sema_init(&g_probe_info.sem, 0); init_completion(&g_probe_info.dpc_exited); g_probe_info.dpc_pid = kernel_thread(dhd_probe_thread, &g_probe_info, 0); } else { g_probe_info.dpc_pid = -1; } return err; }
static int dbus_usb_rdl_dwnld_state(usb_info_t *usbinfo) { void *osinfo = usbinfo->usbosl_info; rdl_state_t state; int err = DBUS_OK; /* 1) Prepare USB boot loader for runtime image */ dbus_usbos_dl_cmd(osinfo, DL_START, &state, sizeof(rdl_state_t)); state.state = ltoh32(state.state); state.bytes = ltoh32(state.bytes); /* 2) Check we are in the Waiting state */ if (state.state != DL_WAITING) { DBUSERR(("%s: Failed to DL_START\n", __FUNCTION__)); err = DBUS_ERR; goto fail; } fail: 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; }