Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 237376
b: refs/heads/master
c: eefdbec
h: refs/heads/master
v: v3
  • Loading branch information
Jussi Kivilinna authored and John W. Linville committed Feb 14, 2011
1 parent e6ecb09 commit 5adef9f
Show file tree
Hide file tree
Showing 3 changed files with 143 additions and 26 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 37939810b937aba830dd751291fcdc51cae1a6cb
refs/heads/master: eefdbec1ea8b7093d2c09d1825f68438701723cf
162 changes: 138 additions & 24 deletions trunk/drivers/net/wireless/zd1211rw/zd_usb.c
Original file line number Diff line number Diff line change
Expand Up @@ -1156,6 +1156,7 @@ void zd_usb_init(struct zd_usb *usb, struct ieee80211_hw *hw,
memset(usb, 0, sizeof(*usb));
usb->intf = usb_get_intf(intf);
usb_set_intfdata(usb->intf, hw);
init_usb_anchor(&usb->submitted_cmds);
init_usb_interrupt(usb);
init_usb_tx(usb);
init_usb_rx(usb);
Expand Down Expand Up @@ -1663,13 +1664,104 @@ int zd_usb_ioread16v(struct zd_usb *usb, u16 *values,
return r;
}

int zd_usb_iowrite16v(struct zd_usb *usb, const struct zd_ioreq16 *ioreqs,
unsigned int count)
static void iowrite16v_urb_complete(struct urb *urb)
{
struct zd_usb *usb = urb->context;

if (urb->status && !usb->cmd_error)
usb->cmd_error = urb->status;
}

static int zd_submit_waiting_urb(struct zd_usb *usb, bool last)
{
int r;
struct urb *urb = usb->urb_async_waiting;

if (!urb)
return 0;

usb->urb_async_waiting = NULL;

if (!last)
urb->transfer_flags |= URB_NO_INTERRUPT;

usb_anchor_urb(urb, &usb->submitted_cmds);
r = usb_submit_urb(urb, GFP_KERNEL);
if (r) {
usb_unanchor_urb(urb);
dev_dbg_f(zd_usb_dev(usb),
"error in usb_submit_urb(). Error number %d\n", r);
goto error;
}

/* fall-through with r == 0 */
error:
usb_free_urb(urb);
return r;
}

static void zd_usb_iowrite16v_async_start(struct zd_usb *usb)
{
ZD_ASSERT(usb_anchor_empty(&usb->submitted_cmds));
ZD_ASSERT(usb->urb_async_waiting == NULL);
ZD_ASSERT(!usb->in_async);

ZD_ASSERT(mutex_is_locked(&zd_usb_to_chip(usb)->mutex));

usb->in_async = 1;
usb->cmd_error = 0;
usb->urb_async_waiting = NULL;
}

static int zd_usb_iowrite16v_async_end(struct zd_usb *usb, unsigned int timeout)
{
int r;

ZD_ASSERT(mutex_is_locked(&zd_usb_to_chip(usb)->mutex));
ZD_ASSERT(usb->in_async);

/* Submit last iowrite16v URB */
r = zd_submit_waiting_urb(usb, true);
if (r) {
dev_dbg_f(zd_usb_dev(usb),
"error in zd_submit_waiting_usb(). "
"Error number %d\n", r);

usb_kill_anchored_urbs(&usb->submitted_cmds);
goto error;
}

if (timeout)
timeout = usb_wait_anchor_empty_timeout(&usb->submitted_cmds,
timeout);
if (!timeout) {
usb_kill_anchored_urbs(&usb->submitted_cmds);
if (usb->cmd_error == -ENOENT) {
dev_dbg_f(zd_usb_dev(usb), "timed out");
r = -ETIMEDOUT;
goto error;
}
}

r = usb->cmd_error;
error:
usb->in_async = 0;
return r;
}

static int zd_usb_iowrite16v_async(struct zd_usb *usb,
const struct zd_ioreq16 *ioreqs,
unsigned int count)
{
int r;
struct usb_device *udev;
struct usb_req_write_regs *req = NULL;
int i, req_len, actual_req_len;
int i, req_len;
struct urb *urb;
struct usb_host_endpoint *ep;

ZD_ASSERT(mutex_is_locked(&zd_usb_to_chip(usb)->mutex));
ZD_ASSERT(usb->in_async);

if (count == 0)
return 0;
Expand All @@ -1685,17 +1777,23 @@ int zd_usb_iowrite16v(struct zd_usb *usb, const struct zd_ioreq16 *ioreqs,
return -EWOULDBLOCK;
}

ZD_ASSERT(mutex_is_locked(&zd_usb_to_chip(usb)->mutex));
BUILD_BUG_ON(sizeof(struct usb_req_write_regs) +
USB_MAX_IOWRITE16_COUNT * sizeof(struct reg_data) >
sizeof(usb->req_buf));
BUG_ON(sizeof(struct usb_req_write_regs) +
count * sizeof(struct reg_data) >
sizeof(usb->req_buf));
udev = zd_usb_to_usbdev(usb);

ep = usb_pipe_endpoint(udev, usb_sndintpipe(udev, EP_REGS_OUT));
if (!ep)
return -ENOENT;

urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb)
return -ENOMEM;

req_len = sizeof(struct usb_req_write_regs) +
count * sizeof(struct reg_data);
req = (void *)usb->req_buf;
req = kmalloc(req_len, GFP_KERNEL);
if (!req) {
r = -ENOMEM;
goto error;
}

req->id = cpu_to_le16(USB_REQ_WRITE_REGS);
for (i = 0; i < count; i++) {
Expand All @@ -1704,28 +1802,44 @@ int zd_usb_iowrite16v(struct zd_usb *usb, const struct zd_ioreq16 *ioreqs,
rw->value = cpu_to_le16(ioreqs[i].value);
}

udev = zd_usb_to_usbdev(usb);
r = usb_interrupt_msg(udev, usb_sndintpipe(udev, EP_REGS_OUT),
req, req_len, &actual_req_len, 50 /* ms */);
usb_fill_int_urb(urb, udev, usb_sndintpipe(udev, EP_REGS_OUT),
req, req_len, iowrite16v_urb_complete, usb,
ep->desc.bInterval);
urb->transfer_flags |= URB_FREE_BUFFER | URB_SHORT_NOT_OK;

/* Submit previous URB */
r = zd_submit_waiting_urb(usb, false);
if (r) {
dev_dbg_f(zd_usb_dev(usb),
"error in usb_interrupt_msg(). Error number %d\n", r);
goto error;
}
if (req_len != actual_req_len) {
dev_dbg_f(zd_usb_dev(usb),
"error in usb_interrupt_msg()"
" req_len %d != actual_req_len %d\n",
req_len, actual_req_len);
r = -EIO;
"error in zd_submit_waiting_usb(). "
"Error number %d\n", r);
goto error;
}

/* FALL-THROUGH with r == 0 */
/* Delay submit so that URB_NO_INTERRUPT flag can be set for all URBs
* of currect batch except for very last.
*/
usb->urb_async_waiting = urb;
return 0;
error:
usb_free_urb(urb);
return r;
}

int zd_usb_iowrite16v(struct zd_usb *usb, const struct zd_ioreq16 *ioreqs,
unsigned int count)
{
int r;

zd_usb_iowrite16v_async_start(usb);
r = zd_usb_iowrite16v_async(usb, ioreqs, count);
if (r) {
zd_usb_iowrite16v_async_end(usb, 0);
return r;
}
return zd_usb_iowrite16v_async_end(usb, 50 /* ms */);
}

int zd_usb_rfwrite(struct zd_usb *usb, u32 value, u8 bits)
{
int r;
Expand Down
5 changes: 4 additions & 1 deletion trunk/drivers/net/wireless/zd1211rw/zd_usb.h
Original file line number Diff line number Diff line change
Expand Up @@ -217,8 +217,11 @@ struct zd_usb {
struct zd_usb_rx rx;
struct zd_usb_tx tx;
struct usb_interface *intf;
struct usb_anchor submitted_cmds;
struct urb *urb_async_waiting;
int cmd_error;
u8 req_buf[64]; /* zd_usb_iowrite16v needs 62 bytes */
u8 is_zd1211b:1, initialized:1, was_running:1;
u8 is_zd1211b:1, initialized:1, was_running:1, in_async:1;
};

#define zd_usb_dev(usb) (&usb->intf->dev)
Expand Down

0 comments on commit 5adef9f

Please sign in to comment.