// SPDX-License-Identifier: (GPL-2.0+ OR BSD-2-Clause) /* * Copyright (c) 2003, 2004 * Damien Bergamini <damien.bergamini@free.fr>. All rights reserved. * * Copyright (c) 2005-2007 Matthieu Castet <castet.matthieu@free.fr> * Copyright (c) 2005-2007 Stanislaw Gruszka <stf_xl@wp.pl> * * 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 rewritten from scratch.
*/
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 endianness */
} while (blockidx->NotLastBlock);
}
return (sum == len) ? 0 : 1;
}
/* * send data to the idma pipe
* */ staticint uea_idma_write(struct uea_softc *sc, constvoid *data, u32 size)
{ int ret = -ENOMEM;
u8 *xfer_buff; int bytes_read;
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
*/ staticvoid 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;
/* send block info through the IDMA pipe */ if (uea_idma_write(sc, &bi, E4_BLOCK_INFO_SIZE))
uea_err(INS_TO_USBDEV(sc), "sending DSP start bi failed\n");
}
/* we send a request, but we expect a reply */
sc->cmv_dsc.e1.function = function | 0x2;
sc->cmv_dsc.e1.idx++;
sc->cmv_dsc.e1.address = address;
sc->cmv_dsc.e1.offset = offset;
/* we send a request, but we expect a reply */
sc->cmv_dsc.e4.function = function | (0x1 << 4);
sc->cmv_dsc.e4.offset = offset;
sc->cmv_dsc.e4.address = address;
sc->cmv_dsc.e4.group = group;
/* in bulk mode the modem have problem with high rate * changing internal timing could improve things, but the * value is mysterious. * ADI930 don't support it (-EPIPE error).
*/
/* Original timing (1Mbit/s) from ADI (used in windows driver) */
timeout = (dsrate <= 1024*1024) ? 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" : "");
}
/* * Monitor the modem and update the stat * return 0 if everything is ok * return < 0 if an error occurs (-EAGAIN reboot needed)
*/ staticint uea_stat_e1(struct uea_softc *sc)
{
u32 data; int ret;
uea_enters(INS_TO_USBDEV(sc));
data = sc->stats.phy.state;
ret = uea_read_cmv_e1(sc, E1_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" " (may be try other cmv/dsp)\n"); return -EAGAIN;
case 4 ... 6: /* test state */
uea_warn(INS_TO_USBDEV(sc), "modem in test mode - not supported\n"); return -EAGAIN;
/* release the dsp firmware as it is not needed until * the next failure
*/
release_firmware(sc->dsp_firm);
sc->dsp_firm = NULL;
}
/* always update it as atm layer could not be init when we switch to * operational state
*/
UPDATE_ATM_SIGNAL(ATM_PHY_SIG_FOUND);
/* wake up processes waiting for synchronization */
wake_up(&sc->sync_q);
ret = uea_read_cmv_e1(sc, E1_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 = 0x%x\n",
sc->stats.phy.flags); return 0;
}
ret = uea_read_cmv_e1(sc, E1_SA_RATE, 0, &data); if (ret < 0) return ret;
/* release the dsp firmware as it is not needed until * the next failure
*/
release_firmware(sc->dsp_firm);
sc->dsp_firm = NULL;
}
/* always update it as atm layer could not be init when we switch to * operational state
*/
UPDATE_ATM_SIGNAL(ATM_PHY_SIG_FOUND);
/* wake up processes waiting for synchronization */
wake_up(&sc->sync_q);
/* TODO improve this state machine : * we need some CMV info : what they do and their unit * we should find the equivalent of eagle3- CMV
*/ /* check flags */
ret = uea_read_cmv_e4(sc, 1, E4_SA_DIAG, 0, 0, &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 = 0x%x\n",
sc->stats.phy.flags); if (sc->stats.phy.flags & 1) /* delineation LOSS */ return -EAGAIN; if (sc->stats.phy.flags & 0x4000) /* Reset Flag */ return -EAGAIN; return 0;
}
/* rate data may be in upper or lower half of 64 bit word, strange */
ret = uea_read_cmv_e4(sc, 4, E4_SA_RATE, 0, 0, tmp_arr); if (ret < 0) return ret;
data = (tmp_arr[0]) ? tmp_arr[0] : tmp_arr[1];
sc->stats.phy.usrate = data / 1000;
ret = uea_read_cmv_e4(sc, 4, E4_SA_RATE, 1, 0, tmp_arr); if (ret < 0) return ret;
data = (tmp_arr[0]) ? tmp_arr[0] : tmp_arr[1];
uea_set_bulk_timeout(sc, data / 1000);
sc->stats.phy.dsrate = data / 1000;
UPDATE_ATM_STAT(link_rate, sc->stats.phy.dsrate * 1000 / 424);
ret = uea_read_cmv_e4(sc, 1, E4_SA_INFO, 68, 1, &data); if (ret < 0) return ret;
sc->stats.phy.dsattenuation = data / 10;
ret = uea_read_cmv_e4(sc, 1, E4_SA_INFO, 69, 1, &data); if (ret < 0) return ret;
sc->stats.phy.usattenuation = data / 10;
ret = uea_read_cmv_e4(sc, 1, E4_SA_INFO, 68, 3, &data); if (ret < 0) return ret;
sc->stats.phy.dsmargin = data / 2;
ret = uea_read_cmv_e4(sc, 1, E4_SA_INFO, 69, 3, &data); if (ret < 0) return ret;
sc->stats.phy.usmargin = data / 10;
kernel_param_lock(THIS_MODULE); /* set proper name corresponding modem version and line type */ if (cmv_file[sc->modem_index] == NULL) { if (UEA_CHIP_VERSION(sc) == ADI930)
file_arr[3] = '9'; elseif (UEA_CHIP_VERSION(sc) == EAGLE_IV)
file_arr[3] = '4'; else
file_arr[3] = 'e';
staticint uea_send_cmvs_e1(struct uea_softc *sc)
{ int i, ret, len; void *cmvs_ptr; conststruct 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;
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,
get_unaligned_le32(&cmvs_v1[i].address),
get_unaligned_le16(&cmvs_v1[i].offset),
get_unaligned_le32(&cmvs_v1[i].data)); if (ret < 0) goto out;
}
} elseif (ver == 2) { struct uea_cmvs_v2 *cmvs_v2 = cmvs_ptr;
for (i = 0; i < len; i++) {
ret = uea_write_cmv_e1(sc,
get_unaligned_le32(&cmvs_v2[i].address),
(u16) get_unaligned_le32(&cmvs_v2[i].offset),
get_unaligned_le32(&cmvs_v2[i].data)); if (ret < 0) goto out;
}
} else { /* This really 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;
}
staticint uea_send_cmvs_e4(struct uea_softc *sc)
{ int i, ret, len; void *cmvs_ptr; conststruct 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;
for (i = 0; i < len; i++) {
ret = uea_write_cmv_e4(sc, 1,
get_unaligned_le32(&cmvs_v2[i].group),
get_unaligned_le32(&cmvs_v2[i].address),
get_unaligned_le32(&cmvs_v2[i].offset),
get_unaligned_le32(&cmvs_v2[i].data)); if (ret < 0) goto out;
}
} else { /* This really 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
*/
staticint uea_start_reset(struct uea_softc *sc)
{
u16 zero = 0; /* ;-) */ int ret;
/* mask interrupt */
sc->booting = 1; /* We need to set this here because, a ack timeout could have occurred, * 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_SIGNAL(ATM_PHY_SIG_LOST);
/* 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;
/* * In case of an error wait 1s before rebooting the modem * if the modem don't request reboot (-EAGAIN). * Monitor the modem every 1s.
*/
staticint 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));
}
uea_leaves(INS_TO_USBDEV(sc)); return ret;
}
/* Load second usb firmware for ADI930 chip */ staticint load_XILINX_firmware(struct uea_softc *sc)
{ conststruct firmware *fw_entry; int ret, size, u, ln; const u8 *pfw;
u8 value; char *fw_name = FPGA930_FIRMWARE;
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);
/* The modem send us an ack. First with check if it right */ staticvoid 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 preamble (func = 2, sub = 2) to * the first MEMACCESS 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_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 ||
get_unaligned_le32(&cmv->dwSymbolicAddress) != dsc->address ||
le16_to_cpu(cmv->wOffsetAddress) != dsc->offset) goto bad2;
/* The modem send us an ack. First with check if it right */ staticvoid 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;
/* 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;
/* * Start the modem : init the data and start kernel thread
*/ staticint uea_boot(struct uea_softc *sc, struct usb_interface *intf)
{ struct intr_pkt *intr; int ret = -ENOMEM; int size;
ret = usb_submit_urb(sc->urb_int, GFP_KERNEL); if (ret < 0) {
uea_err(INS_TO_USBDEV(sc), "urb submission failed with error %d\n", ret); goto err1;
}
/* Create worker thread, but don't start it here. Start it after * all usbatm generic initialization is done.
*/
sc->kthread = kthread_create(uea_kthread, sc, "ueagle-atm"); if (IS_ERR(sc->kthread)) {
uea_err(INS_TO_USBDEV(sc), "failed to create thread\n");
ret = PTR_ERR(sc->kthread); goto err2;
}
/* * Stop the modem : kill kernel thread and free data
*/ staticvoid uea_stop(struct uea_softc *sc)
{ int ret;
uea_enters(INS_TO_USBDEV(sc));
ret = kthread_stop(sc->kthread);
uea_dbg(INS_TO_USBDEV(sc), "kthread finish with status %d\n", ret);
intf = to_usb_interface(dev); if (!intf) return NULL;
usbatm = usb_get_intfdata(intf); if (!usbatm) return NULL;
return usbatm->driver_data;
}
static ssize_t stat_status_show(struct device *dev, struct device_attribute *attr, char *buf)
{ int ret = -ENODEV; struct uea_softc *sc;
mutex_lock(&uea_mutex);
sc = dev_to_uea(dev); if (!sc) goto out;
ret = sysfs_emit(buf, "%08x\n", sc->stats.phy.state);
out:
mutex_unlock(&uea_mutex); return ret;
}
static ssize_t stat_status_store(struct device *dev, struct device_attribute *attr, constchar *buf, size_t count)
{ int ret = -ENODEV; struct uea_softc *sc;
mutex_lock(&uea_mutex);
sc = dev_to_uea(dev); if (!sc) goto out;
sc->reset = 1;
ret = count;
out:
mutex_unlock(&uea_mutex); return ret;
}
static DEVICE_ATTR_RW(stat_status);
static ssize_t stat_human_status_show(struct device *dev, struct device_attribute *attr, char *buf)
{ int ret = -ENODEV; int modem_state; struct uea_softc *sc;
mutex_lock(&uea_mutex);
sc = dev_to_uea(dev); if (!sc) goto out;
if (UEA_CHIP_VERSION(sc) == EAGLE_IV) { switch (sc->stats.phy.state) { case 0x0: /* not yet synchronized */ case 0x1: case 0x3: case 0x4:
modem_state = 0; break; case 0x5: /* initialization */ case 0x6: case 0x9: case 0xa:
modem_state = 1; break; case 0x7: /* operational */
modem_state = 2; break; case 0x2: /* fail ... */
modem_state = 3; break; default: /* unknown */
modem_state = 4; break;
}
} else
modem_state = GET_STATUS(sc->stats.phy.state);
switch (modem_state) { case 0:
ret = sysfs_emit(buf, "Modem is booting\n"); break; case 1:
ret = sysfs_emit(buf, "Modem is initializing\n"); break; case 2:
ret = sysfs_emit(buf, "Modem is operational\n"); break; case 3:
ret = sysfs_emit(buf, "Modem synchronization failed\n"); break; default:
ret = sysfs_emit(buf, "Modem state is unknown\n"); break;
}
out:
mutex_unlock(&uea_mutex); return ret;
}
/* interface 1 is for outbound traffic */
ret = claim_interface(usb, usbatm, UEA_US_IFACE_NO); if (ret < 0) return ret;
/* ADI930 has only 2 interfaces and inbound traffic is on interface 1 */ if (UEA_CHIP_VERSION(id) != ADI930) { /* interface 2 is for inbound traffic */
ret = claim_interface(usb, usbatm, UEA_DS_IFACE_NO); if (ret < 0) return ret;
}
sc = kzalloc(sizeof(struct uea_softc), GFP_KERNEL); if (!sc) return -ENOMEM;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.