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

📄 ueagle-atm.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
		union intr_data_e1 e1;		union intr_data_e4 e4;	} u;} __attribute__ ((packed));#define E1_INTR_PKT_SIZE 28#define E4_INTR_PKT_SIZE 64static struct usb_driver uea_driver;static DEFINE_MUTEX(uea_mutex);static const char *chip_name[] = {"ADI930", "Eagle I", "Eagle II", "Eagle III", "Eagle IV"};static int modem_index;static unsigned int debug;static unsigned int altsetting[NB_MODEM] = {[0 ... (NB_MODEM - 1)] = FASTEST_ISO_INTF};static int sync_wait[NB_MODEM];static char *cmv_file[NB_MODEM];static int annex[NB_MODEM];module_param(debug, uint, 0644);MODULE_PARM_DESC(debug, "module debug level (0=off,1=on,2=verbose)");module_param_array(altsetting, uint, NULL, 0644);MODULE_PARM_DESC(altsetting, "alternate setting for incoming traffic: 0=bulk, "			     "1=isoc slowest, ... , 8=isoc fastest (default)");module_param_array(sync_wait, bool, NULL, 0644);MODULE_PARM_DESC(sync_wait, "wait the synchronisation before starting ATM");module_param_array(cmv_file, charp, NULL, 0644);MODULE_PARM_DESC(cmv_file,		"file name with configuration and management variables");module_param_array(annex, uint, NULL, 0644);MODULE_PARM_DESC(annex,                 "manually set annex a/b (0=auto, 1=annex a, 2=annex b)");#define uea_wait(sc, cond, timeo) \({ \	int _r = wait_event_interruptible_timeout(sc->sync_q, \			(cond) || kthread_should_stop(), timeo); \	if (kthread_should_stop()) \		_r = -ENODEV; \	_r; \})#define UPDATE_ATM_STAT(type, val) \	do { \		if (sc->usbatm->atm_dev) \			sc->usbatm->atm_dev->type = val; \	} while (0)/* Firmware loading */#define LOAD_INTERNAL     0xA0#define F8051_USBCS       0x7f92/** * uea_send_modem_cmd - Send a command for pre-firmware devices. */static int uea_send_modem_cmd(struct usb_device *usb,		u16 addr, u16 size, u8 * buff){	int ret = -ENOMEM;	u8 *xfer_buff;	xfer_buff = kmemdup(buff, size, GFP_KERNEL);	if (xfer_buff) {		ret = usb_control_msg(usb,				      usb_sndctrlpipe(usb, 0),				      LOAD_INTERNAL,				      USB_DIR_OUT | USB_TYPE_VENDOR |				      USB_RECIP_DEVICE, addr, 0, xfer_buff,				      size, CTRL_TIMEOUT);		kfree(xfer_buff);	}	if (ret < 0)		return ret;	return (ret == size) ? 0 : -EIO;}static void uea_upload_pre_firmware(const struct firmware *fw_entry, void *context){	struct usb_device *usb = context;	u8 *pfw, value;	u32 crc = 0;	int ret, size;	uea_enters(usb);	if (!fw_entry) {		uea_err(usb, "firmware is not available\n");		goto err;	}	pfw = fw_entry->data;	size = fw_entry->size;	if (size < 4)		goto err_fw_corrupted;	crc = FW_GET_LONG(pfw);	pfw += 4;	size -= 4;	if (crc32_be(0, pfw, size) != crc)		goto err_fw_corrupted;	/*	 * Start to upload formware : send reset	 */	value = 1;	ret = uea_send_modem_cmd(usb, F8051_USBCS, sizeof(value), &value);	if (ret < 0) {		uea_err(usb, "modem reset failed with error %d\n", ret);		goto err;	}	while (size > 3) {		u8 len = FW_GET_BYTE(pfw);		u16 add = FW_GET_WORD(pfw + 1);		size -= len + 3;		if (size < 0)			goto err_fw_corrupted;		ret = uea_send_modem_cmd(usb, add, len, pfw + 3);		if (ret < 0) {			uea_err(usb, "uploading firmware data failed "					"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;	case EAGLE_IV:		fw_name = FW_DIR "eagleIV.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_e1(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;}static int check_dsp_e4(u8 *dsp, int len){	int i;	struct l1_code *p = (struct l1_code *) dsp;	unsigned int sum = p->code - dsp;	if (len < sum)		return 1;	if (strcmp("STRATIPHY ANEXA", p->string_header) != 0 &&	    strcmp("STRATIPHY ANEXB", p->string_header) != 0)		return 1;	for (i = 0; i < E4_MAX_PAGE_NUMBER; i++) {		struct block_index *blockidx;		u8 blockno = p->page_number_to_block_index[i];		if (blockno >= E4_NO_SWAPPAGE_HEADERS)			continue;		do {			u64 l;			if (blockno >= E4_NO_SWAPPAGE_HEADERS)				return 1;			blockidx = &p->page_header[blockno++];			if ((u8 *)(blockidx + 1) - dsp  >= len)				return 1;			if (le16_to_cpu(blockidx->PageNumber) != i)				return 1;			l = E4_PAGE_BYTES(blockidx->PageSize);			sum += l;			l += le32_to_cpu(blockidx->PageOffset);			if (l > len)				return 1;		/* zero is zero regardless endianes */		} while (blockidx->NotLastBlock);	}	return (sum == len) ? 0 : 1;}/* * 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 = kmemdup(data, size, GFP_KERNEL);	if (!xfer_buff) {		uea_err(INS_TO_USBDEV(sc), "can't allocate xfer_buff\n");		return ret;	}	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) == EAGLE_IV) {		if (IS_ISDN(sc))			dsp_name = FW_DIR "DSP4i.bin";		else			dsp_name = FW_DIR "DSP4p.bin";	} else 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 (UEA_CHIP_VERSION(sc) == EAGLE_IV)		ret = check_dsp_e4(sc->dsp_firm->data, sc->dsp_firm->size);	else		ret = check_dsp_e1(sc->dsp_firm->data, sc->dsp_firm->size);	if (ret) {		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_e1(struct work_struct *work){	struct uea_softc *sc = container_of(work, struct uea_softc, task);	u16 pageno = sc->pageno;	u16 ovl = sc->ovl;	struct block_info_e1 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, E1_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 void __uea_load_page_e4(struct uea_softc *sc, u8 pageno, int boot){	struct block_info_e4 bi;	struct block_index *blockidx;	struct l1_code *p = (struct l1_code *) sc->dsp_firm->data;	u8 blockno = p->page_number_to_block_index[pageno];	bi.wHdr = cpu_to_be16(UEA_BIHDR);	bi.bBootPage = boot;	bi.bPageNumber = pageno;	bi.wReserved = cpu_to_be16(UEA_RESERVED);	do {		u8 *blockoffset;		unsigned int blocksize;		blockidx = &p->page_header[blockno];		blocksize = E4_PAGE_BYTES(blockidx->PageSize);		blockoffset = sc->dsp_firm->data + le32_to_cpu(blockidx->PageOffset);		bi.dwSize = cpu_to_be32(blocksize);		bi.dwAddress = swab32(blockidx->PageAddress);		uea_dbg(INS_TO_USBDEV(sc),		       "sending block %u for DSP page %u size %u adress %x\n",		       blockno, pageno, blocksize, le32_to_cpu(blockidx->PageAddress));		/* send block info through the IDMA pipe */		if (uea_idma_write(sc, &bi, E4_BLOCK_INFO_SIZE))			goto bad;		/* send block data through the IDMA pipe */		if (uea_idma_write(sc, blockoffset, blocksize))			goto bad;		blockno++;	} while (blockidx->NotLastBlock);	return;bad:	uea_err(INS_TO_USBDEV(sc), "sending DSP block %u failed\n", blockno);	return;}static void uea_load_page_e4(struct work_struct *work){	struct uea_softc *sc = container_of(work, struct uea_softc, task);	u8 pageno = sc->pageno;	int i;	struct block_info_e4 bi;	struct l1_code *p;	uea_dbg(INS_TO_USBDEV(sc), "sending DSP page %u\n", pageno);	/* reload firmware when reboot start and it's loaded already */	if (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 = (struct l1_code *) sc->dsp_firm->data;	if (pageno >= p->page_header[0].PageNumber) {		uea_err(INS_TO_USBDEV(sc), "invalid DSP page %u requested\n", pageno);		return;	}	if (pageno != 0) {		__uea_load_page_e4(sc, pageno, 0);		return;	}	uea_dbg(INS_TO_USBDEV(sc),	       "sending Main DSP page %u\n", p->page_header[0].PageNumber);

⌨️ 快捷键说明

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