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

📄 ueagle-atm.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	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 = (*fw)->size;	if (size < 1)		goto err_fw_corrupted;	if (size != *data * sizeof(struct uea_cmvs_v1) + 1)		goto err_fw_corrupted;	*cmvs = (void *)(data + 1);	return *data;err_fw_corrupted:	uea_err(INS_TO_USBDEV(sc), "firmware %s is corrupted\n", cmv_name);	release_firmware(*fw);	return -EILSEQ;}static int request_cmvs(struct uea_softc *sc,		 void **cmvs, const struct firmware **fw, int *ver){	int ret, size;	u32 crc;	u8 *data;	char cmv_name[FIRMWARE_NAME_MAX]; /* 30 bytes stack variable */	cmvs_file_name(sc, cmv_name, 2);	ret = request_firmware(fw, cmv_name, &sc->usb_dev->dev);	if (ret < 0) {		/* if caller can handle old version, try to provide it */		if (*ver == 1) {			uea_warn(INS_TO_USBDEV(sc), "requesting firmware %s failed, "				"try to get older cmvs\n", cmv_name);			return request_cmvs_old(sc, cmvs, fw);		}		uea_err(INS_TO_USBDEV(sc),		       "requesting firmware %s failed with error %d\n",		       cmv_name, ret);		return ret;	}	size = (*fw)->size;	data = (u8 *) (*fw)->data;	if (size < 4 || strncmp(data, "cmv2", 4) != 0) {		if (*ver == 1) {			uea_warn(INS_TO_USBDEV(sc), "firmware %s is corrupted, "				"try to get older cmvs\n", cmv_name);			release_firmware(*fw);			return request_cmvs_old(sc, cmvs, fw);		}		goto err_fw_corrupted;	}	*ver = 2;	data += 4;	size -= 4;	if (size < 5)		goto err_fw_corrupted;	crc = FW_GET_LONG(data);	data += 4;	size -= 4;	if (crc32_be(0, data, size) != crc)		goto err_fw_corrupted;	if (size != *data * sizeof(struct uea_cmvs_v2) + 1)		goto err_fw_corrupted;	*cmvs = (void *) (data + 1);	return *data;err_fw_corrupted:	uea_err(INS_TO_USBDEV(sc), "firmware %s is corrupted\n", cmv_name);	release_firmware(*fw);	return -EILSEQ;}static int uea_send_cmvs_e1(struct uea_softc *sc){	int i, ret, len;	void *cmvs_ptr;	const struct firmware *cmvs_fw;	int ver = 1; // we can handle v1 cmv firmware version;	/* Enter in R-IDLE (cmv) until instructed otherwise */	ret = uea_write_cmv_e1(sc, E1_SA_CNTL, 0, 1);	if (ret < 0)		return ret;	/* Dump firmware version */	ret = uea_read_cmv_e1(sc, E1_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);	/* get options */ 	ret = len = request_cmvs(sc, &cmvs_ptr, &cmvs_fw, &ver);	if (ret < 0)		return ret;	/* send options */	if (ver == 1) {		struct uea_cmvs_v1 *cmvs_v1 = cmvs_ptr;		uea_warn(INS_TO_USBDEV(sc), "use deprecated cmvs version, "			"please update your firmware\n");		for (i = 0; i < len; i++) {			ret = uea_write_cmv_e1(sc, FW_GET_LONG(&cmvs_v1[i].address),						FW_GET_WORD(&cmvs_v1[i].offset),						FW_GET_LONG(&cmvs_v1[i].data));			if (ret < 0)				goto out;		}	} else if (ver == 2) {		struct uea_cmvs_v2 *cmvs_v2 = cmvs_ptr;		for (i = 0; i < len; i++) {			ret = uea_write_cmv_e1(sc, FW_GET_LONG(&cmvs_v2[i].address),						(u16) FW_GET_LONG(&cmvs_v2[i].offset),						FW_GET_LONG(&cmvs_v2[i].data));			if (ret < 0)				goto out;		}	} else {		/* This realy should not happen */		uea_err(INS_TO_USBDEV(sc), "bad cmvs version %d\n", ver);		goto out;	}	/* Enter in R-ACT-REQ */	ret = uea_write_cmv_e1(sc, E1_SA_CNTL, 0, 2);	uea_vdbg(INS_TO_USBDEV(sc), "Entering in R-ACT-REQ state\n");	uea_info(INS_TO_USBDEV(sc), "modem started, waiting synchronization...\n");out:	release_firmware(cmvs_fw);	return ret;}static int uea_send_cmvs_e4(struct uea_softc *sc){	int i, ret, len;	void *cmvs_ptr;	const struct firmware *cmvs_fw;	int ver = 2; // we can only handle v2 cmv firmware version;	/* Enter in R-IDLE (cmv) until instructed otherwise */	ret = uea_write_cmv_e4(sc, 1, E4_SA_CNTL, 0, 0, 1);	if (ret < 0)		return ret;	/* Dump firmware version */	/* XXX don't read the 3th byte as it is always 6 */	ret = uea_read_cmv_e4(sc, 2, E4_SA_INFO, 55, 0, &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);	/* get options */ 	ret = len = request_cmvs(sc, &cmvs_ptr, &cmvs_fw, &ver);	if (ret < 0)		return ret;	/* send options */	if (ver == 2) {		struct uea_cmvs_v2 *cmvs_v2 = cmvs_ptr;		for (i = 0; i < len; i++) {			ret = uea_write_cmv_e4(sc, 1,						FW_GET_LONG(&cmvs_v2[i].group),						FW_GET_LONG(&cmvs_v2[i].address),						FW_GET_LONG(&cmvs_v2[i].offset),						FW_GET_LONG(&cmvs_v2[i].data));			if (ret < 0)				goto out;		}	} else {		/* This realy should not happen */		uea_err(INS_TO_USBDEV(sc), "bad cmvs version %d\n", ver);		goto out;	}	/* Enter in R-ACT-REQ */	ret = uea_write_cmv_e4(sc, 1, E4_SA_CNTL, 0, 0, 2);	uea_vdbg(INS_TO_USBDEV(sc), "Entering in R-ACT-REQ state\n");	uea_info(INS_TO_USBDEV(sc), "modem started, waiting synchronization...\n");out:	release_firmware(cmvs_fw);	return ret;}/* 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 ret;	uea_enters(INS_TO_USBDEV(sc));	uea_info(INS_TO_USBDEV(sc), "(re)booting started\n");	/* mask interrupt */	sc->booting = 1;	/* We need to set this here because, a ack timeout could have occured,	 * but before we start the reboot, the ack occurs and set this to 1.	 * So we will failed to wait Ready CMV.	 */	sc->cmv_ack = 0;	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 */	ret = uea_wait(sc, 0, msecs_to_jiffies(100));	if (ret < 0)		return ret;	/* leave reset mode */	uea_request(sc, UEA_SET_MODE, UEA_END_RESET, 0, NULL);	if (UEA_CHIP_VERSION(sc) != EAGLE_IV) { 		/* 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);	}	ret = uea_wait(sc, 0, msecs_to_jiffies(1000));	if (ret < 0)		return ret;	if (UEA_CHIP_VERSION(sc) == EAGLE_IV)		sc->cmv_dsc.e4.function = E4_MAKEFUNCTION(E4_ADSLDIRECTIVE, E4_MODEMREADY, 1);	else		sc->cmv_dsc.e1.function = E1_MAKEFUNCTION(E1_ADSLDIRECTIVE, E1_MODEMREADY);	/* demask interrupt */	sc->booting = 0;	/* start loading DSP */	sc->pageno = 0;	sc->ovl = 0;	queue_work(sc->work_q, &sc->task);	/* wait for modem ready CMV */	ret = wait_cmv_ack(sc);	if (ret < 0)		return ret;	uea_vdbg(INS_TO_USBDEV(sc), "Ready CMV received\n");	ret = sc->send_cmvs(sc);	if (ret < 0)		return ret;	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;	set_freezable();	uea_enters(INS_TO_USBDEV(sc));	while (!kthread_should_stop()) {		if (ret < 0 || sc->reset)			ret = uea_start_reset(sc);		if (!ret)			ret = sc->stat(sc);		if (ret != -EAGAIN)			uea_wait(sc, 0, msecs_to_jiffies(1000));		try_to_freeze();	}	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_e1(struct uea_softc *sc, struct intr_pkt *intr){	struct cmv_dsc_e1 *dsc = &sc->cmv_dsc.e1;	struct cmv_e1 *cmv = &intr->u.e1.s2.cmv;	uea_enters(INS_TO_USBDEV(sc));	if (le16_to_cpu(cmv->wPreamble) != E1_PREAMBLE)		goto bad1;	if (cmv->bDirection != E1_MODEMTOHOST)		goto bad1;	/* FIXME : ADI930 reply wrong preambule (func = 2, sub = 2) to	 * the first MEMACESS cmv. Ignore it...	 */	if (cmv->bFunction != dsc->function) {		if (UEA_CHIP_VERSION(sc) == ADI930				&& cmv->bFunction ==  E1_MAKEFUNCTION(2, 2)) {			cmv->wIndex = cpu_to_le16(dsc->idx);			put_unaligned(cpu_to_le32(dsc->address), &cmv->dwSymbolicAddress);			cmv->wOffsetAddress = cpu_to_le16(dsc->offset);		} else			goto bad2;	}	if (cmv->bFunction == E1_MAKEFUNCTION(E1_ADSLDIRECTIVE, E1_MODEMREADY)) {		wake_up_cmv_ack(sc);		uea_leaves(INS_TO_USBDEV(sc));		return;	}	/* in case of MEMACCESS */	if (le16_to_cpu(cmv->wIndex) != dsc->idx ||	    le32_to_cpu(get_unaligned(&cmv->dwSymbolicAddress)) != dsc->address ||	    le16_to_cpu(cmv->wOffsetAddress) != dsc->offset)		goto bad2;	sc->data = le32_to_cpu(get_unaligned(&cmv->dwData));	sc->data = sc->data << 16 | sc->data >> 16;	wake_up_cmv_ack(sc);	uea_leaves(INS_TO_USBDEV(sc));	return;bad2:	uea_err(INS_TO_USBDEV(sc), "unexpected cmv received,"			"Function : %d, Subfunction : %d\n",			E1_FUNCTION_TYPE(cmv->bFunction),			E1_FUNCTION_SUBTYPE(cmv->bFunction));	uea_leaves(INS_TO_USBDEV(sc));	return;bad1:	uea_err(INS_TO_USBDEV(sc), "invalid cmv received, "			"wPreamble %d, bDirection %d\n",			le16_to_cpu(cmv->wPreamble), cmv->bDirection);	uea_leaves(INS_TO_USBDEV(sc));}/* The modem send us an ack. First with check if it right */static void uea_dispatch_cmv_e4(struct uea_softc *sc, struct intr_pkt *intr){	struct cmv_dsc_e4 *dsc = &sc->cmv_dsc.e4;	struct cmv_e4 *cmv = &intr->u.e4.s2.cmv;	uea_enters(INS_TO_USBDEV(sc));	uea_dbg(INS_TO_USBDEV(sc), "cmv %x %x %x %x %x %x\n",		be16_to_cpu(cmv->wGroup), be16_to_cpu(cmv->wFunction),		be16_to_cpu(cmv->wOffset), be16_to_cpu(cmv->wAddress),		be32_to_cpu(cmv->dwData[0]), be32_to_cpu(cmv->dwData[1]));	if (be16_to_cpu(cmv->wFunction) != dsc->function)		goto bad2;	if (be16_to_cpu(cmv->wFunction) == E4_MAKEFUNCTION(E4_ADSLDIRECTIVE, E4_MODEMREADY, 1)) {		wake_up_cmv_ack(sc);		uea_leaves(INS_TO_USBDEV(sc));		return;	}	/* in case of MEMACCESS */	if (be16_to_cpu(cmv->wOffset) != dsc->offset ||	    be16_to_cpu(cmv->wGroup) != dsc->group ||	    be16_to_cpu(cmv->wAddress) != dsc->address)		goto bad2;	sc->data = be32_to_cpu(cmv->dwData[0]);	sc->data1 = be32_to_cpu(cmv->dwData[1]);	wake_up_cmv_ack(sc);	uea_leaves(INS_TO_USBDEV(sc));	return;bad2:	uea_err(INS_TO_USBDEV(sc), "unexpected cmv received,"			"Function : %d, Subfunction : %d\n",			E4_FUNCTION_TYPE(cmv->wFunction),			E4_FUNCTION_SUBTYPE(cmv->wFunction));	uea_leaves(INS_TO_USBDEV(sc));	return;}static void uea_schedule_load_page_e1(struct uea_softc *sc, struct intr_pkt *intr){	sc->pageno = intr->e1_bSwapPageNo;	sc->ovl = intr->e1_bOvl >> 4 | intr->e1_bOvl << 4;	queue_work(sc->work_q, &sc->task);}static void uea_schedule_load_page_e4(struct uea_softc *sc, struct intr_pkt *intr){	sc->pageno = intr->e4_bSwapPageNo;	queue_work(sc->work_q, &sc->task);}/* * interrupt handler */static void uea_intr(struct urb *urb){	struct uea_softc *sc = urb->context;	struct intr_pkt *intr = urb->transfer_buffer;	int status = urb->status;	uea_enters(INS_TO_USBDEV(sc));	if (unlikely(status < 0)) {		uea_err(INS_TO_USBDEV(sc), "uea_intr() failed with %d\n",		       status);		return;	}	/* device-to-host interrupt */	if (intr->bType != 0x08 || sc->booting) {		uea_err(INS_TO_USBDEV(sc), "wrong interrupt\n");		goto resubmit;	}	switch (le16_to_cpu(intr->wInterrupt)) {	case INT_LOADSWAPPAGE:		sc->schedule_load_page(sc, intr);		break;	case INT_INCOMINGCMV:		sc->dispatch_cmv(sc, intr);		break;	default:		uea_err(INS_TO_USBDEV(sc), "unknown interrupt %u\n",		       le16_to_cpu(intr->wInterrupt));	}resubmit:	usb_submit_urb(sc->urb_int, GFP_ATOMIC);}/* * Start the modem : init the data and start kernel thread */static int uea_boot(struct uea_softc *sc){	int ret, size;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -