📄 ueagle-atm.c
字号:
} return 0;}static int request_dsp(struct uea_softc *sc){ int ret; char *dsp_name; if (UEA_CHIP_VERSION(sc) == ADI930) { if (IS_ISDN(sc)) dsp_name = FW_DIR "DSP9i.bin"; else dsp_name = FW_DIR "DSP9p.bin"; } else { if (IS_ISDN(sc)) dsp_name = FW_DIR "DSPei.bin"; else dsp_name = FW_DIR "DSPep.bin"; } ret = request_firmware(&sc->dsp_firm, dsp_name, &sc->usb_dev->dev); if (ret < 0) { uea_err(INS_TO_USBDEV(sc), "requesting firmware %s failed with error %d\n", dsp_name, ret); return ret; } if (check_dsp(sc->dsp_firm->data, sc->dsp_firm->size)) { uea_err(INS_TO_USBDEV(sc), "firmware %s is corrupted\n", dsp_name); release_firmware(sc->dsp_firm); sc->dsp_firm = NULL; return -EILSEQ; } return 0;}/* * The uea_load_page() function must be called within a process context */static void uea_load_page(void *xsc){ struct uea_softc *sc = xsc; u16 pageno = sc->pageno; u16 ovl = sc->ovl; struct block_info bi; u8 *p; u8 pagecount, blockcount; u16 blockaddr, blocksize; u32 pageoffset; int i; /* reload firmware when reboot start and it's loaded already */ if (ovl == 0 && pageno == 0 && sc->dsp_firm) { release_firmware(sc->dsp_firm); sc->dsp_firm = NULL; } if (sc->dsp_firm == NULL && request_dsp(sc) < 0) return; p = sc->dsp_firm->data; pagecount = FW_GET_BYTE(p); p += 1; if (pageno >= pagecount) goto bad1; p += 4 * pageno; pageoffset = FW_GET_LONG(p); if (pageoffset == 0) goto bad1; p = sc->dsp_firm->data + pageoffset; blockcount = FW_GET_BYTE(p); p += 1; uea_dbg(INS_TO_USBDEV(sc), "sending %u blocks for DSP page %u\n", blockcount, pageno); bi.wHdr = cpu_to_le16(UEA_BIHDR); bi.wOvl = cpu_to_le16(ovl); bi.wOvlOffset = cpu_to_le16(ovl | 0x8000); for (i = 0; i < blockcount; i++) { blockaddr = FW_GET_WORD(p); p += 2; blocksize = FW_GET_WORD(p); p += 2; bi.wSize = cpu_to_le16(blocksize); bi.wAddress = cpu_to_le16(blockaddr); bi.wLast = cpu_to_le16((i == blockcount - 1) ? 1 : 0); /* send block info through the IDMA pipe */ if (uea_idma_write(sc, &bi, BLOCK_INFO_SIZE)) goto bad2; /* send block data through the IDMA pipe */ if (uea_idma_write(sc, p, blocksize)) goto bad2; p += blocksize; } return;bad2: uea_err(INS_TO_USBDEV(sc), "sending DSP block %u failed\n", i); return;bad1: uea_err(INS_TO_USBDEV(sc), "invalid DSP page %u requested\n",pageno);}static inline void wake_up_cmv_ack(struct uea_softc *sc){ sc->cmv_ack = 1; wake_up(&sc->cmv_ack_wait);}static inline int wait_cmv_ack(struct uea_softc *sc){ int ret = wait_event_timeout(sc->cmv_ack_wait, sc->cmv_ack, ACK_TIMEOUT); sc->cmv_ack = 0; if (ret < 0) return ret; return (ret == 0) ? -ETIMEDOUT : 0;}#define UCDC_SEND_ENCAPSULATED_COMMAND 0x00static int uea_request(struct uea_softc *sc, u16 value, u16 index, u16 size, void *data){ u8 *xfer_buff; int ret = -ENOMEM; xfer_buff = kmalloc(size, GFP_KERNEL); if (!xfer_buff) { uea_err(INS_TO_USBDEV(sc), "can't allocate xfer_buff\n"); return ret; } memcpy(xfer_buff, data, size); ret = usb_control_msg(sc->usb_dev, usb_sndctrlpipe(sc->usb_dev, 0), UCDC_SEND_ENCAPSULATED_COMMAND, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, value, index, xfer_buff, size, CTRL_TIMEOUT); kfree(xfer_buff); if (ret < 0) { uea_err(INS_TO_USBDEV(sc), "usb_control_msg error %d\n", ret); return ret; } if (ret != size) { uea_err(INS_TO_USBDEV(sc), "usb_control_msg send only %d bytes (instead of %d)\n", ret, size); return -EIO; } return 0;}static int uea_cmv(struct uea_softc *sc, u8 function, u32 address, u16 offset, u32 data){ struct cmv cmv; int ret; /* we send a request, but we expect a reply */ sc->cmv_function = function | 0x2; sc->cmv_idx++; sc->cmv_address = address; sc->cmv_offset = offset; cmv.wPreamble = cpu_to_le16(PREAMBLE); cmv.bDirection = HOSTTOMODEM; cmv.bFunction = function; cmv.wIndex = cpu_to_le16(sc->cmv_idx); put_unaligned(cpu_to_le32(address), &cmv.dwSymbolicAddress); cmv.wOffsetAddress = cpu_to_le16(offset); put_unaligned(cpu_to_le32(data >> 16 | data << 16), &cmv.dwData); ret = uea_request(sc, UEA_SET_BLOCK, UEA_MPTX_START, CMV_SIZE, &cmv); if (ret < 0) return ret; return wait_cmv_ack(sc);}static inline int uea_read_cmv(struct uea_softc *sc, u32 address, u16 offset, u32 *data){ int ret = uea_cmv(sc, MAKEFUNCTION(MEMACCESS, REQUESTREAD), address, offset, 0); if (ret < 0) uea_err(INS_TO_USBDEV(sc), "reading cmv failed with error %d\n", ret); else *data = sc->data; return ret;}static inline int uea_write_cmv(struct uea_softc *sc, u32 address, u16 offset, u32 data){ int ret = uea_cmv(sc, MAKEFUNCTION(MEMACCESS, REQUESTWRITE), address, offset, data); if (ret < 0) uea_err(INS_TO_USBDEV(sc), "writing cmv failed with error %d\n", ret); return ret;}/* * Monitor the modem and update the stat * return 0 if everything is ok * return < 0 if an error occurs (-EAGAIN reboot needed) */static int uea_stat(struct uea_softc *sc){ u32 data; int ret; uea_enters(INS_TO_USBDEV(sc)); data = sc->stats.phy.state; ret = uea_read_cmv(sc, SA_STAT, 0, &sc->stats.phy.state); if (ret < 0) return ret; switch (GET_STATUS(sc->stats.phy.state)) { case 0: /* not yet synchronized */ uea_dbg(INS_TO_USBDEV(sc), "modem not yet synchronized\n"); return 0; case 1: /* initialization */ uea_dbg(INS_TO_USBDEV(sc), "modem initializing\n"); return 0; case 2: /* operational */ uea_vdbg(INS_TO_USBDEV(sc), "modem operational\n"); break; case 3: /* fail ... */ uea_info(INS_TO_USBDEV(sc), "modem synchronization failed\n"); return -EAGAIN; case 4 ... 6: /* test state */ uea_warn(INS_TO_USBDEV(sc), "modem in test mode - not supported\n"); return -EAGAIN; case 7: /* fast-retain ... */ uea_info(INS_TO_USBDEV(sc), "modem in fast-retain mode\n"); return 0; default: uea_err(INS_TO_USBDEV(sc), "modem invalid SW mode %d\n", GET_STATUS(sc->stats.phy.state)); return -EAGAIN; } if (GET_STATUS(data) != 2) { uea_request(sc, UEA_SET_MODE, UEA_LOOPBACK_OFF, 0, NULL); uea_info(INS_TO_USBDEV(sc), "modem operational\n"); /* release the dsp firmware as it is not needed until * the next failure */ if (sc->dsp_firm) { release_firmware(sc->dsp_firm); sc->dsp_firm = NULL; } ret = uea_read_cmv(sc, SA_INFO, 10, &sc->stats.phy.firmid); if (ret < 0) return ret; uea_info(INS_TO_USBDEV(sc), "ATU-R firmware version : %x\n", sc->stats.phy.firmid); } /* always update it as atm layer could not be init when we switch to * operational state */ UPDATE_ATM_STAT(signal, ATM_PHY_SIG_FOUND); /* wake up processes waiting for synchronization */ wake_up(&sc->sync_q); ret = uea_read_cmv(sc, SA_DIAG, 2, &sc->stats.phy.flags); if (ret < 0) return ret; sc->stats.phy.mflags |= sc->stats.phy.flags; /* in case of a flags ( for example delineation LOSS (& 0x10)), * we check the status again in order to detect the failure earlier */ if (sc->stats.phy.flags) { uea_dbg(INS_TO_USBDEV(sc), "Stat flag = %d\n", sc->stats.phy.flags); return 0; } ret = uea_read_cmv(sc, SA_RATE, 0, &data); if (ret < 0) return ret; /* in bulk mode the modem have problem with high rate * changing internal timing could improve things, but the * value is misterious. * ADI930 don't support it (-EPIPE error). */ if (UEA_CHIP_VERSION(sc) != ADI930 && !use_iso[sc->modem_index] && sc->stats.phy.dsrate != (data >> 16) * 32) { /* Original timming from ADI(used in windows driver) * 0x20ffff>>16 * 32 = 32 * 32 = 1Mbits */ u16 timeout = (data <= 0x20ffff) ? 0 : 1; ret = uea_request(sc, UEA_SET_TIMEOUT, timeout, 0, NULL); uea_info(INS_TO_USBDEV(sc), "setting new timeout %d%s\n", timeout, ret < 0?" failed":""); } sc->stats.phy.dsrate = (data >> 16) * 32; sc->stats.phy.usrate = (data & 0xffff) * 32; UPDATE_ATM_STAT(link_rate, sc->stats.phy.dsrate * 1000 / 424); ret = uea_read_cmv(sc, SA_DIAG, 23, &data); if (ret < 0) return ret; sc->stats.phy.dsattenuation = (data & 0xff) / 2; ret = uea_read_cmv(sc, SA_DIAG, 47, &data); if (ret < 0) return ret; sc->stats.phy.usattenuation = (data & 0xff) / 2; ret = uea_read_cmv(sc, SA_DIAG, 25, &sc->stats.phy.dsmargin); if (ret < 0) return ret; ret = uea_read_cmv(sc, SA_DIAG, 49, &sc->stats.phy.usmargin); if (ret < 0) return ret; ret = uea_read_cmv(sc, SA_DIAG, 51, &sc->stats.phy.rxflow); if (ret < 0) return ret; ret = uea_read_cmv(sc, SA_DIAG, 52, &sc->stats.phy.txflow); if (ret < 0) return ret; ret = uea_read_cmv(sc, SA_DIAG, 54, &sc->stats.phy.dsunc); if (ret < 0) return ret; /* only for atu-c */ ret = uea_read_cmv(sc, SA_DIAG, 58, &sc->stats.phy.usunc); if (ret < 0) return ret; ret = uea_read_cmv(sc, SA_DIAG, 53, &sc->stats.phy.dscorr); if (ret < 0) return ret; /* only for atu-c */ ret = uea_read_cmv(sc, SA_DIAG, 57, &sc->stats.phy.uscorr); if (ret < 0) return ret; ret = uea_read_cmv(sc, SA_INFO, 8, &sc->stats.phy.vidco); if (ret < 0) return ret; ret = uea_read_cmv(sc, SA_INFO, 13, &sc->stats.phy.vidcpe); if (ret < 0) return ret; return 0;}static int request_cmvs(struct uea_softc *sc, struct uea_cmvs **cmvs, const struct firmware **fw){ int ret, size; u8 *data; char *file; char cmv_name[FIRMWARE_NAME_MAX]; /* 30 bytes stack variable */ if (cmv_file[sc->modem_index] == NULL) { if (UEA_CHIP_VERSION(sc) == ADI930) file = (IS_ISDN(sc)) ? "CMV9i.bin" : "CMV9p.bin"; else file = (IS_ISDN(sc)) ? "CMVei.bin" : "CMVep.bin"; } else file = cmv_file[sc->modem_index]; strcpy(cmv_name, FW_DIR); strlcat(cmv_name, file, sizeof(cmv_name)); ret = request_firmware(fw, cmv_name, &sc->usb_dev->dev); if (ret < 0) { uea_err(INS_TO_USBDEV(sc), "requesting firmware %s failed with error %d\n", cmv_name, ret); return ret; } data = (u8 *) (*fw)->data; size = *data * sizeof(struct uea_cmvs) + 1; if (size != (*fw)->size) { uea_err(INS_TO_USBDEV(sc), "firmware %s is corrupted\n", cmv_name); release_firmware(*fw); return -EILSEQ; } *cmvs = (struct uea_cmvs *)(data + 1); return *data;}/* Start boot post firmware modem: * - send reset commands through usb control pipe * - start workqueue for DSP loading * - send CMV options to modem */static int uea_start_reset(struct uea_softc *sc){ u16 zero = 0; /* ;-) */ int i, len, ret; struct uea_cmvs *cmvs; const struct firmware *cmvs_fw; uea_enters(INS_TO_USBDEV(sc)); uea_info(INS_TO_USBDEV(sc), "(re)booting started\n"); sc->booting = 1; UPDATE_ATM_STAT(signal, ATM_PHY_SIG_LOST); /* reset statistics */ memset(&sc->stats, 0, sizeof(struct uea_stats)); /* tell the modem that we want to boot in IDMA mode */ uea_request(sc, UEA_SET_MODE, UEA_LOOPBACK_ON, 0, NULL); uea_request(sc, UEA_SET_MODE, UEA_BOOT_IDMA, 0, NULL); /* enter reset mode */ uea_request(sc, UEA_SET_MODE, UEA_START_RESET, 0, NULL); /* original driver use 200ms, but windows driver use 100ms */ msleep(100); /* leave reset mode */ uea_request(sc, UEA_SET_MODE, UEA_END_RESET, 0, NULL); /* clear tx and rx mailboxes */ uea_request(sc, UEA_SET_2183_DATA, UEA_MPTX_MAILBOX, 2, &zero); uea_request(sc, UEA_SET_2183_DATA, UEA_MPRX_MAILBOX, 2, &zero); uea_request(sc, UEA_SET_2183_DATA, UEA_SWAP_MAILBOX, 2, &zero); msleep(1000); sc->cmv_function = MAKEFUNCTION(ADSLDIRECTIVE, MODEMREADY); sc->booting = 0; /* start loading DSP */ sc->pageno = 0; sc->ovl = 0; schedule_work(&sc->task); /* wait for modem ready CMV */ ret = wait_cmv_ack(sc); if (ret < 0) return ret; /* Enter in R-IDLE (cmv) until instructed otherwise */ ret = uea_write_cmv(sc, SA_CNTL, 0, 1); if (ret < 0) return ret; /* get options */ ret = len = request_cmvs(sc, &cmvs, &cmvs_fw); if (ret < 0) return ret; /* send options */ for (i = 0; i < len; i++) { ret = uea_write_cmv(sc, FW_GET_LONG(&cmvs[i].address), FW_GET_WORD(&cmvs[i].offset), FW_GET_LONG(&cmvs[i].data)); if (ret < 0) goto out; } /* Enter in R-ACT-REQ */ ret = uea_write_cmv(sc, SA_CNTL, 0, 2);out: release_firmware(cmvs_fw); sc->reset = 0; uea_leaves(INS_TO_USBDEV(sc)); return ret;}/* * In case of an error wait 1s before rebooting the modem * if the modem don't request reboot (-EAGAIN). * Monitor the modem every 1s. */static int uea_kthread(void *data){ struct uea_softc *sc = data; int ret = -EAGAIN; uea_enters(INS_TO_USBDEV(sc)); while (!kthread_should_stop()) { if (ret < 0 || sc->reset) ret = uea_start_reset(sc); if (!ret) ret = uea_stat(sc); if (ret != -EAGAIN) msleep(1000); } uea_leaves(INS_TO_USBDEV(sc)); return ret;}/* Load second usb firmware for ADI930 chip */static int load_XILINX_firmware(struct uea_softc *sc){ const struct firmware *fw_entry; int ret, size, u, ln; u8 *pfw, value; char *fw_name = FW_DIR "930-fpga.bin"; uea_enters(INS_TO_USBDEV(sc)); ret = request_firmware(&fw_entry, fw_name, &sc->usb_dev->dev); if (ret) { uea_err(INS_TO_USBDEV(sc), "firmware %s is not available\n", fw_name); goto err0; } pfw = fw_entry->data; size = fw_entry->size; if (size != 0x577B) { uea_err(INS_TO_USBDEV(sc), "firmware %s is corrupted\n", fw_name); ret = -EILSEQ; goto err1; } for (u = 0; u < size; u += ln) { ln = min(size - u, 64); ret = uea_request(sc, 0xe, 0, ln, pfw + u); if (ret < 0) { uea_err(INS_TO_USBDEV(sc), "elsa download data failed (%d)\n", ret); goto err1; } } /* finish to send the fpga */ ret = uea_request(sc, 0xe, 1, 0, NULL); if (ret < 0) { uea_err(INS_TO_USBDEV(sc), "elsa download data failed (%d)\n", ret); goto err1; } /* Tell the modem we finish : de-assert reset */ value = 0; ret = uea_send_modem_cmd(sc->usb_dev, 0xe, 1, &value); if (ret < 0) uea_err(sc->usb_dev, "elsa de-assert failed with error %d\n", ret);err1: release_firmware(fw_entry);err0: uea_leaves(INS_TO_USBDEV(sc)); return ret;}/* The modem send us an ack. First with check if it right */static void uea_dispatch_cmv(struct uea_softc *sc, struct cmv* cmv){ uea_enters(INS_TO_USBDEV(sc)); if (le16_to_cpu(cmv->wPreamble) != PREAMBLE) goto bad1; if (cmv->bDirection != MODEMTOHOST) goto bad1; /* FIXME : ADI930 reply wrong preambule (func = 2, sub = 2) to * the first MEMACESS cmv. Ignore it... */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -