📄 ueagle-atm.c
字号:
/*- * Copyright (c) 2003, 2004 * Damien Bergamini <damien.bergamini@free.fr>. All rights reserved. * * Copyright (c) 2005 Matthieu Castet <castet.matthieu@free.fr> * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU * General Public License (GPL) Version 2, available from the file * COPYING in the main directory of this source tree, or the * BSD license below: * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice unmodified, this list of conditions, and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * GPL license : * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * HISTORY : some part of the code was base on ueagle 1.3 BSD driver, * Damien Bergamini agree to put his code under a DUAL GPL/BSD license. * * The rest of the code was was rewritten from scratch. */#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/init.h>#include <linux/crc32.h>#include <linux/usb.h>#include <linux/firmware.h>#include <linux/ctype.h>#include <linux/kthread.h>#include <linux/version.h>#include <linux/mutex.h>#include <asm/unaligned.h>#include "usbatm.h"#define EAGLEUSBVERSION "ueagle 1.3"/* * Debug macros */#define uea_dbg(usb_dev, format, args...) \ do { \ if (debug >= 1) \ dev_dbg(&(usb_dev)->dev, \ "[ueagle-atm dbg] %s: " format, \ __FUNCTION__, ##args); \ } while (0)#define uea_vdbg(usb_dev, format, args...) \ do { \ if (debug >= 2) \ dev_dbg(&(usb_dev)->dev, \ "[ueagle-atm vdbg] " format, ##args); \ } while (0)#define uea_enters(usb_dev) \ uea_vdbg(usb_dev, "entering %s\n", __FUNCTION__)#define uea_leaves(usb_dev) \ uea_vdbg(usb_dev, "leaving %s\n", __FUNCTION__)#define uea_err(usb_dev, format,args...) \ dev_err(&(usb_dev)->dev ,"[UEAGLE-ATM] " format , ##args)#define uea_warn(usb_dev, format,args...) \ dev_warn(&(usb_dev)->dev ,"[Ueagle-atm] " format, ##args)#define uea_info(usb_dev, format,args...) \ dev_info(&(usb_dev)->dev ,"[ueagle-atm] " format, ##args)struct uea_cmvs { u32 address; u16 offset; u32 data;} __attribute__ ((packed));struct uea_softc { struct usb_device *usb_dev; struct usbatm_data *usbatm; int modem_index; unsigned int driver_info; int booting; int reset; wait_queue_head_t sync_q; struct task_struct *kthread; u32 data; wait_queue_head_t cmv_ack_wait; int cmv_ack; struct work_struct task; u16 pageno; u16 ovl; const struct firmware *dsp_firm; struct urb *urb_int; u8 cmv_function; u16 cmv_idx; u32 cmv_address; u16 cmv_offset; /* keep in sync with eaglectl */ struct uea_stats { struct { u32 state; u32 flags; u32 mflags; u32 vidcpe; u32 vidco; u32 dsrate; u32 usrate; u32 dsunc; u32 usunc; u32 dscorr; u32 uscorr; u32 txflow; u32 rxflow; u32 usattenuation; u32 dsattenuation; u32 dsmargin; u32 usmargin; u32 firmid; } phy; } stats;};/* * Elsa IDs */#define ELSA_VID 0x05CC#define ELSA_PID_PSTFIRM 0x3350#define ELSA_PID_PREFIRM 0x3351/* * Sagem USB IDs */#define EAGLE_VID 0x1110#define EAGLE_I_PID_PREFIRM 0x9010 /* Eagle I */#define EAGLE_I_PID_PSTFIRM 0x900F /* Eagle I */#define EAGLE_IIC_PID_PREFIRM 0x9024 /* Eagle IIC */#define EAGLE_IIC_PID_PSTFIRM 0x9023 /* Eagle IIC */#define EAGLE_II_PID_PREFIRM 0x9022 /* Eagle II */#define EAGLE_II_PID_PSTFIRM 0x9021 /* Eagle II *//* * Eagle III Pid */#define EAGLE_III_PID_PREFIRM 0x9032 /* Eagle III */#define EAGLE_III_PID_PSTFIRM 0x9031 /* Eagle III *//* * USR USB IDs */#define USR_VID 0x0BAF#define MILLER_A_PID_PREFIRM 0x00F2#define MILLER_A_PID_PSTFIRM 0x00F1#define MILLER_B_PID_PREFIRM 0x00FA#define MILLER_B_PID_PSTFIRM 0x00F9#define HEINEKEN_A_PID_PREFIRM 0x00F6#define HEINEKEN_A_PID_PSTFIRM 0x00F5#define HEINEKEN_B_PID_PREFIRM 0x00F8#define HEINEKEN_B_PID_PSTFIRM 0x00F7#define PREFIRM 0#define PSTFIRM (1<<7)enum { ADI930 = 0, EAGLE_I, EAGLE_II, EAGLE_III};/* macros for both struct usb_device_id and struct uea_softc */#define UEA_IS_PREFIRM(x) \ (!((x)->driver_info & PSTFIRM))#define UEA_CHIP_VERSION(x) \ ((x)->driver_info & 0xf)#define IS_ISDN(sc) \ (le16_to_cpu(sc->usb_dev->descriptor.bcdDevice) & 0x80)#define INS_TO_USBDEV(ins) ins->usb_dev#define GET_STATUS(data) \ ((data >> 8) & 0xf)#define IS_OPERATIONAL(sc) \ (GET_STATUS(sc->stats.phy.state) == 2)/* * Set of macros to handle unaligned data in the firmware blob. * The FW_GET_BYTE() macro is provided only for consistency. */#define FW_GET_BYTE(p) *((__u8 *) (p))#define FW_GET_WORD(p) le16_to_cpu(get_unaligned((__le16 *) (p)))#define FW_GET_LONG(p) le32_to_cpu(get_unaligned((__le32 *) (p)))#define FW_DIR "ueagle-atm/"#define NB_MODEM 4#define BULK_TIMEOUT 300#define CTRL_TIMEOUT 1000#define ACK_TIMEOUT msecs_to_jiffies(3000)#define UEA_INTR_IFACE_NO 0#define UEA_US_IFACE_NO 1#define UEA_DS_IFACE_NO 2#define FASTEST_ISO_INTF 8#define UEA_BULK_DATA_PIPE 0x02#define UEA_IDMA_PIPE 0x04#define UEA_INTR_PIPE 0x04#define UEA_ISO_DATA_PIPE 0x08#define UEA_SET_BLOCK 0x0001#define UEA_SET_MODE 0x0003#define UEA_SET_2183_DATA 0x0004#define UEA_SET_TIMEOUT 0x0011#define UEA_LOOPBACK_OFF 0x0002#define UEA_LOOPBACK_ON 0x0003#define UEA_BOOT_IDMA 0x0006#define UEA_START_RESET 0x0007#define UEA_END_RESET 0x0008#define UEA_SWAP_MAILBOX (0x3fcd | 0x4000)#define UEA_MPTX_START (0x3fce | 0x4000)#define UEA_MPTX_MAILBOX (0x3fd6 | 0x4000)#define UEA_MPRX_MAILBOX (0x3fdf | 0x4000)/* structure describing a block within a DSP page */struct block_info { __le16 wHdr;#define UEA_BIHDR 0xabcd __le16 wAddress; __le16 wSize; __le16 wOvlOffset; __le16 wOvl; /* overlay */ __le16 wLast;} __attribute__ ((packed));#define BLOCK_INFO_SIZE 12/* structure representing a CMV (Configuration and Management Variable) */struct cmv { __le16 wPreamble;#define PREAMBLE 0x535c __u8 bDirection;#define MODEMTOHOST 0x01#define HOSTTOMODEM 0x10 __u8 bFunction;#define FUNCTION_TYPE(f) ((f) >> 4)#define MEMACCESS 0x1#define ADSLDIRECTIVE 0x7#define FUNCTION_SUBTYPE(f) ((f) & 0x0f)/* for MEMACCESS */#define REQUESTREAD 0x0#define REQUESTWRITE 0x1#define REPLYREAD 0x2#define REPLYWRITE 0x3/* for ADSLDIRECTIVE */#define KERNELREADY 0x0#define MODEMREADY 0x1#define MAKEFUNCTION(t, s) (((t) & 0xf) << 4 | ((s) & 0xf)) __le16 wIndex; __le32 dwSymbolicAddress;#define MAKESA(a, b, c, d) \ (((c) & 0xff) << 24 | \ ((d) & 0xff) << 16 | \ ((a) & 0xff) << 8 | \ ((b) & 0xff))#define GETSA1(a) ((a >> 8) & 0xff)#define GETSA2(a) (a & 0xff)#define GETSA3(a) ((a >> 24) & 0xff)#define GETSA4(a) ((a >> 16) & 0xff)#define SA_CNTL MAKESA('C', 'N', 'T', 'L')#define SA_DIAG MAKESA('D', 'I', 'A', 'G')#define SA_INFO MAKESA('I', 'N', 'F', 'O')#define SA_OPTN MAKESA('O', 'P', 'T', 'N')#define SA_RATE MAKESA('R', 'A', 'T', 'E')#define SA_STAT MAKESA('S', 'T', 'A', 'T') __le16 wOffsetAddress; __le32 dwData;} __attribute__ ((packed));#define CMV_SIZE 16/* structure representing swap information */struct swap_info { __u8 bSwapPageNo; __u8 bOvl; /* overlay */} __attribute__ ((packed));/* structure representing interrupt data */struct intr_pkt { __u8 bType; __u8 bNotification; __le16 wValue; __le16 wIndex; __le16 wLength; __le16 wInterrupt;#define INT_LOADSWAPPAGE 0x0001#define INT_INCOMINGCMV 0x0002 union { struct { struct swap_info swapinfo; __le16 wDataSize; } __attribute__ ((packed)) s1; struct { struct cmv cmv; __le16 wDataSize; } __attribute__ ((packed)) s2; } __attribute__ ((packed)) u;#define bSwapPageNo u.s1.swapinfo.bSwapPageNo#define bOvl u.s1.swapinfo.bOvl} __attribute__ ((packed));#define INTR_PKT_SIZE 28static struct usb_driver uea_driver;static DEFINE_MUTEX(uea_mutex);static const char *chip_name[] = {"ADI930", "Eagle I", "Eagle II", "Eagle III"};static int modem_index;static unsigned int debug;static int use_iso[NB_MODEM] = {[0 ... (NB_MODEM - 1)] = 1};static int sync_wait[NB_MODEM];static char *cmv_file[NB_MODEM];module_param(debug, uint, 0644);MODULE_PARM_DESC(debug, "module debug level (0=off,1=on,2=verbose)");module_param_array(use_iso, bool, NULL, 0644);MODULE_PARM_DESC(use_iso, "use isochronous usb pipe for incoming traffic");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");#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 = kmalloc(size, GFP_KERNEL); if (xfer_buff) { memcpy(xfer_buff, buff, size); 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 "
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -