📄 ueagle-atm.c
字号:
"with error %d\n", ret); goto err; } pfw += len + 3; } if (size != 0) goto err_fw_corrupted; /* * Tell the modem we finish : de-assert reset */ value = 0; ret = uea_send_modem_cmd(usb, F8051_USBCS, 1, &value); if (ret < 0) uea_err(usb, "modem de-assert failed with error %d\n", ret); else uea_info(usb, "firmware uploaded\n"); uea_leaves(usb); return;err_fw_corrupted: uea_err(usb, "firmware is corrupted\n");err: uea_leaves(usb);}/** * uea_load_firmware - Load usb firmware for pre-firmware devices. */static int uea_load_firmware(struct usb_device *usb, unsigned int ver){ int ret; char *fw_name = FW_DIR "eagle.fw"; uea_enters(usb); uea_info(usb, "pre-firmware device, uploading firmware\n"); switch (ver) { case ADI930: fw_name = FW_DIR "adi930.fw"; break; case EAGLE_I: fw_name = FW_DIR "eagleI.fw"; break; case EAGLE_II: fw_name = FW_DIR "eagleII.fw"; break; case EAGLE_III: fw_name = FW_DIR "eagleIII.fw"; break; } ret = request_firmware_nowait(THIS_MODULE, 1, fw_name, &usb->dev, usb, uea_upload_pre_firmware); if (ret) uea_err(usb, "firmware %s is not available\n", fw_name); else uea_info(usb, "loading firmware %s\n", fw_name); uea_leaves(usb); return ret;}/* modem management : dsp firmware, send/read CMV, monitoring statistic *//* * Make sure that the DSP code provided is safe to use. */static int check_dsp(u8 *dsp, unsigned int len){ u8 pagecount, blockcount; u16 blocksize; u32 pageoffset; unsigned int i, j, p, pp; pagecount = FW_GET_BYTE(dsp); p = 1; /* enough space for page offsets? */ if (p + 4 * pagecount > len) return 1; for (i = 0; i < pagecount; i++) { pageoffset = FW_GET_LONG(dsp + p); p += 4; if (pageoffset == 0) continue; /* enough space for blockcount? */ if (pageoffset >= len) return 1; pp = pageoffset; blockcount = FW_GET_BYTE(dsp + pp); pp += 1; for (j = 0; j < blockcount; j++) { /* enough space for block header? */ if (pp + 4 > len) return 1; pp += 2; /* skip blockaddr */ blocksize = FW_GET_WORD(dsp + pp); pp += 2; /* enough space for block data? */ if (pp + blocksize > len) return 1; pp += blocksize; } } return 0;}/* * send data to the idma pipe * */static int uea_idma_write(struct uea_softc *sc, void *data, u32 size){ int ret = -ENOMEM; u8 *xfer_buff; int bytes_read; 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_bulk_msg(sc->usb_dev, usb_sndbulkpipe(sc->usb_dev, UEA_IDMA_PIPE), xfer_buff, size, &bytes_read, BULK_TIMEOUT); kfree(xfer_buff); if (ret < 0) return ret; if (size != bytes_read) { uea_err(INS_TO_USBDEV(sc), "size != bytes_read %d %d\n", size, bytes_read); return -EIO; } 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){ BUG_ON(sc->cmv_ack); 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; uea_dbg(INS_TO_USBDEV(sc), "wait_event_timeout : %d ms\n", jiffies_to_msecs(ret)); 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; uea_enters(INS_TO_USBDEV(sc)); uea_vdbg(INS_TO_USBDEV(sc), "Function : %d-%d, Address : %c%c%c%c, " "offset : 0x%04x, data : 0x%08x\n", FUNCTION_TYPE(function), FUNCTION_SUBTYPE(function), GETSA1(address), GETSA2(address), GETSA3(address), GETSA4(address), offset, data); /* 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; ret = wait_cmv_ack(sc); uea_leaves(INS_TO_USBDEV(sc)); return ret;}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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -