⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ueagle-atm.c

📁 linux2.6.16版本
💻 C
📖 第 1 页 / 共 3 页
字号:
	}	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 + -