* Copyright (c) 2003, 2004
* Damien Bergamini <damien.bergamini@free.fr>. All rights reserved.
*
- * Copyright (c) 2005 Matthieu Castet <castet.matthieu@free.fr>
+ * Copyright (c) 2005-2007 Matthieu Castet <castet.matthieu@free.fr>
+ * Copyright (c) 2005-2007 Stanislaw Gruszka <stf_xl@wp.pl>
*
* 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
if (debug >= 1) \
dev_dbg(&(usb_dev)->dev, \
"[ueagle-atm dbg] %s: " format, \
- __FUNCTION__, ##args); \
+ __func__, ##args); \
} while (0)
#define uea_vdbg(usb_dev, format, args...) \
} while (0)
#define uea_enters(usb_dev) \
- uea_vdbg(usb_dev, "entering %s\n", __FUNCTION__)
+ uea_vdbg(usb_dev, "entering %s\n", __func__)
#define uea_leaves(usb_dev) \
- uea_vdbg(usb_dev, "leaving %s\n", __FUNCTION__)
+ uea_vdbg(usb_dev, "leaving %s\n", __func__)
#define uea_err(usb_dev, format,args...) \
dev_err(&(usb_dev)->dev ,"[UEAGLE-ATM] " format , ##args)
struct task_struct *kthread;
u32 data;
u32 data1;
- wait_queue_head_t cmv_ack_wait;
int cmv_ack;
union cmv_dsc cmv_dsc;
struct work_struct task;
+ struct workqueue_struct *work_q;
u16 pageno;
u16 ovl;
*/
#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
static int modem_index;
static unsigned int debug;
-static int use_iso[NB_MODEM] = {[0 ... (NB_MODEM - 1)] = 1};
+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(use_iso, bool, NULL, 0644);
-MODULE_PARM_DESC(use_iso, "use isochronous usb pipe for incoming traffic");
+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(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) \
if (size < 4)
goto err_fw_corrupted;
- crc = FW_GET_LONG(pfw);
+ crc = get_unaligned_le32(pfw);
pfw += 4;
size -= 4;
if (crc32_be(0, pfw, size) != crc)
while (size > 3) {
u8 len = FW_GET_BYTE(pfw);
- u16 add = FW_GET_WORD(pfw + 1);
+ u16 add = get_unaligned_le16(pfw + 1);
size -= len + 3;
if (size < 0)
for (i = 0; i < pagecount; i++) {
- pageoffset = FW_GET_LONG(dsp + p);
+ pageoffset = get_unaligned_le32(dsp + p);
p += 4;
if (pageoffset == 0)
return 1;
pp += 2; /* skip blockaddr */
- blocksize = FW_GET_WORD(dsp + pp);
+ blocksize = get_unaligned_le16(dsp + pp);
pp += 2;
/* enough space for block data? */
goto bad1;
p += 4 * pageno;
- pageoffset = FW_GET_LONG(p);
+ pageoffset = get_unaligned_le32(p);
if (pageoffset == 0)
goto bad1;
bi.wOvlOffset = cpu_to_le16(ovl | 0x8000);
for (i = 0; i < blockcount; i++) {
- blockaddr = FW_GET_WORD(p);
+ blockaddr = get_unaligned_le16(p);
p += 2;
- blocksize = FW_GET_WORD(p);
+ blocksize = get_unaligned_le16(p);
p += 2;
bi.wSize = cpu_to_le16(blocksize);
blockoffset = sc->dsp_firm->data + le32_to_cpu(blockidx->PageOffset);
bi.dwSize = cpu_to_be32(blocksize);
- bi.dwAddress = swab32(blockidx->PageAddress);
+ bi.dwAddress = cpu_to_be32(le32_to_cpu(blockidx->PageAddress));
uea_dbg(INS_TO_USBDEV(sc),
- "sending block %u for DSP page %u size %u adress %x\n",
+ "sending block %u for DSP page %u size %u address %x\n",
blockno, pageno, blocksize, le32_to_cpu(blockidx->PageAddress));
/* send block info through the IDMA pipe */
return;
p = (struct l1_code *) sc->dsp_firm->data;
- if (pageno >= p->page_header[0].PageNumber) {
+ if (pageno >= le16_to_cpu(p->page_header[0].PageNumber)) {
uea_err(INS_TO_USBDEV(sc), "invalid DSP page %u requested\n", pageno);
return;
}
bi.bPageNumber = 0xff;
bi.wReserved = cpu_to_be16(UEA_RESERVED);
bi.dwSize = cpu_to_be32(E4_PAGE_BYTES(p->page_header[0].PageSize));
- bi.dwAddress = swab32(p->page_header[0].PageAddress);
+ bi.dwAddress = cpu_to_be32(le32_to_cpu(p->page_header[0].PageAddress));
/* send block info through the IDMA pipe */
if (uea_idma_write(sc, &bi, E4_BLOCK_INFO_SIZE))
{
BUG_ON(sc->cmv_ack);
sc->cmv_ack = 1;
- wake_up(&sc->cmv_ack_wait);
+ wake_up(&sc->sync_q);
}
static inline int wait_cmv_ack(struct uea_softc *sc)
{
- int ret = wait_event_interruptible_timeout(sc->cmv_ack_wait,
- sc->cmv_ack, ACK_TIMEOUT);
+ int ret = uea_wait(sc, sc->cmv_ack , ACK_TIMEOUT);
+
sc->cmv_ack = 0;
uea_dbg(INS_TO_USBDEV(sc), "wait_event_timeout : %d ms\n",
cmv.bDirection = E1_HOSTTOMODEM;
cmv.bFunction = function;
cmv.wIndex = cpu_to_le16(sc->cmv_dsc.e1.idx);
- put_unaligned(cpu_to_le32(address), &cmv.dwSymbolicAddress);
+ put_unaligned_le32(address, &cmv.dwSymbolicAddress);
cmv.wOffsetAddress = cpu_to_le16(offset);
- put_unaligned(cpu_to_le32(data >> 16 | data << 16), &cmv.dwData);
+ put_unaligned_le32(data >> 16 | data << 16, &cmv.dwData);
ret = uea_request(sc, UEA_E1_SET_BLOCK, UEA_MPTX_START, sizeof(cmv), &cmv);
if (ret < 0)
*/
if (UEA_CHIP_VERSION(sc) == ADI930 ||
- use_iso[sc->modem_index] > 0 ||
+ altsetting[sc->modem_index] > 0 ||
sc->stats.phy.dsrate == dsrate)
return;
if (size < 5)
goto err_fw_corrupted;
- crc = FW_GET_LONG(data);
+ crc = get_unaligned_le32(data);
data += 4;
size -= 4;
if (crc32_be(0, data, size) != crc)
"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));
+ 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;
}
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));
+ 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;
}
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));
+ 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;
}
uea_request(sc, UEA_SET_MODE, UEA_START_RESET, 0, NULL);
/* original driver use 200ms, but windows driver use 100ms */
- msleep(100);
+ 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);
uea_request(sc, UEA_SET_2183_DATA, UEA_SWAP_MAILBOX, 2, &zero);
}
- msleep(1000);
+ 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);
/* start loading DSP */
sc->pageno = 0;
sc->ovl = 0;
- schedule_work(&sc->task);
+ queue_work(sc->work_q, &sc->task);
/* wait for modem ready CMV */
ret = wait_cmv_ack(sc);
if (!ret)
ret = sc->stat(sc);
if (ret != -EAGAIN)
- msleep_interruptible(1000);
- if (try_to_freeze())
- uea_err(INS_TO_USBDEV(sc), "suspend/resume not supported, "
- "please unplug/replug your modem\n");
+ uea_wait(sc, 0, msecs_to_jiffies(1000));
+ try_to_freeze();
}
uea_leaves(INS_TO_USBDEV(sc));
return ret;
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);
+ put_unaligned_le32(dsc->address, &cmv->dwSymbolicAddress);
cmv->wOffsetAddress = cpu_to_le16(dsc->offset);
} else
goto bad2;
/* in case of MEMACCESS */
if (le16_to_cpu(cmv->wIndex) != dsc->idx ||
- le32_to_cpu(get_unaligned(&cmv->dwSymbolicAddress)) != dsc->address ||
+ get_unaligned_le32(&cmv->dwSymbolicAddress) != dsc->address ||
le16_to_cpu(cmv->wOffsetAddress) != dsc->offset)
goto bad2;
- sc->data = le32_to_cpu(get_unaligned(&cmv->dwData));
+ sc->data = get_unaligned_le32(&cmv->dwData);
sc->data = sc->data << 16 | sc->data >> 16;
wake_up_cmv_ack(sc);
return;
bad2:
- uea_err(INS_TO_USBDEV(sc), "unexpected cmv received,"
+ uea_err(INS_TO_USBDEV(sc), "unexpected cmv received, "
"Function : %d, Subfunction : %d\n",
E1_FUNCTION_TYPE(cmv->bFunction),
E1_FUNCTION_SUBTYPE(cmv->bFunction));
return;
bad2:
- uea_err(INS_TO_USBDEV(sc), "unexpected cmv received,"
+ uea_err(INS_TO_USBDEV(sc), "unexpected cmv received, "
"Function : %d, Subfunction : %d\n",
E4_FUNCTION_TYPE(cmv->wFunction),
E4_FUNCTION_SUBTYPE(cmv->wFunction));
{
sc->pageno = intr->e1_bSwapPageNo;
sc->ovl = intr->e1_bOvl >> 4 | intr->e1_bOvl << 4;
- schedule_work(&sc->task);
+ 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;
- schedule_work(&sc->task);
+ queue_work(sc->work_q, &sc->task);
}
/*
}
init_waitqueue_head(&sc->sync_q);
- init_waitqueue_head(&sc->cmv_ack_wait);
+
+ sc->work_q = create_workqueue("ueagle-dsp");
+ if (!sc->work_q) {
+ uea_err(INS_TO_USBDEV(sc), "cannot allocate workqueue\n");
+ uea_leaves(INS_TO_USBDEV(sc));
+ return -ENOMEM;
+ }
if (UEA_CHIP_VERSION(sc) == ADI930)
load_XILINX_firmware(sc);
if (!intr) {
uea_err(INS_TO_USBDEV(sc),
"cannot allocate interrupt package\n");
- uea_leaves(INS_TO_USBDEV(sc));
- return -ENOMEM;
+ goto err0;
}
sc->urb_int = usb_alloc_urb(0, GFP_KERNEL);
if (!sc->urb_int) {
uea_err(INS_TO_USBDEV(sc), "cannot allocate interrupt URB\n");
- goto err;
+ goto err1;
}
usb_fill_int_urb(sc->urb_int, sc->usb_dev,
if (ret < 0) {
uea_err(INS_TO_USBDEV(sc),
"urb submition failed with error %d\n", ret);
- goto err;
+ goto err1;
}
sc->kthread = kthread_run(uea_kthread, sc, "ueagle-atm");
err2:
usb_kill_urb(sc->urb_int);
-err:
+err1:
usb_free_urb(sc->urb_int);
sc->urb_int = NULL;
kfree(intr);
+err0:
+ destroy_workqueue(sc->work_q);
uea_leaves(INS_TO_USBDEV(sc));
return -ENOMEM;
}
ret = kthread_stop(sc->kthread);
uea_dbg(INS_TO_USBDEV(sc), "kthread finish with status %d\n", ret);
- /* stop any pending boot process */
- flush_scheduled_work();
-
uea_request(sc, UEA_SET_MODE, UEA_LOOPBACK_ON, 0, NULL);
usb_kill_urb(sc->urb_int);
kfree(sc->urb_int->transfer_buffer);
usb_free_urb(sc->urb_int);
+ /* stop any pending boot process, when no one can schedule work */
+ destroy_workqueue(sc->work_q);
+
if (sc->dsp_firm)
release_firmware(sc->dsp_firm);
uea_leaves(INS_TO_USBDEV(sc));
struct usb_device *usb = interface_to_usbdev(intf);
struct uea_softc *sc;
int ret, ifnum = intf->altsetting->desc.bInterfaceNumber;
+ unsigned int alt;
uea_enters(usb);
else
sc->annex = (le16_to_cpu(sc->usb_dev->descriptor.bcdDevice) & 0x80)?ANNEXB:ANNEXA;
+ alt = altsetting[sc->modem_index];
/* ADI930 don't support iso */
- if (UEA_CHIP_VERSION(id) != ADI930 && use_iso[sc->modem_index]) {
- int i;
-
- /* try set fastest alternate for inbound traffic interface */
- for (i = FASTEST_ISO_INTF; i > 0; i--)
- if (usb_set_interface(usb, UEA_DS_IFACE_NO, i) == 0)
- break;
-
- if (i > 0) {
- uea_dbg(usb, "set alternate %d for 2 interface\n", i);
+ if (UEA_CHIP_VERSION(id) != ADI930 && alt > 0) {
+ if (alt <= 8 && usb_set_interface(usb, UEA_DS_IFACE_NO, alt) == 0) {
+ uea_dbg(usb, "set alternate %u for 2 interface\n", alt);
uea_info(usb, "using iso mode\n");
usbatm->flags |= UDSL_USE_ISOC | UDSL_IGNORE_EILSEQ;
} else {
- uea_err(usb, "setting any alternate failed for "
- "2 interface, using bulk mode\n");
+ uea_err(usb, "setting alternate %u failed for "
+ "2 interface, using bulk mode\n", alt);
}
}