zyd_usb.c revision e8da18d8c173d57b68019b8d92471843c44ec746
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Copyright (c) 2007 by Lukas Turek <turek@ksvi.mff.cuni.cz>
* Copyright (c) 2007 by Jiri Svoboda <jirik.svoboda@seznam.cz>
* Copyright (c) 2007 by Martin Krulis <martin.krulis@matfyz.cz>
* Copyright (c) 2006 by Damien Bergamini <damien.bergamini@free.fr>
* Copyright (c) 2006 by Florian Stoehr <ich@florian-stoehr.de>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
/*
* ZD1211 wLAN driver
* USB communication
*
* Manage USB communication with the ZD-based device.
*/
#include <sys/byteorder.h>
#include <sys/mac_provider.h>
#include "zyd.h"
#include "zyd_reg.h"
static zyd_usb_info_t usb_ids[] = {
};
/*
*/
{
int i;
for (i = 0; i < sizeof (usb_ids) / sizeof (zyd_usb_info_t); i++) {
}
return (ZYD_ZD1211B);
}
/*
* Vendor-specific write to the default control pipe.
*/
static zyd_res
{
int err;
int retry = 0;
/* Always clean structures before use */
return (ZYD_FAILURE);
if (retry++ > 3)
break;
}
if (err != USB_SUCCESS) {
"control pipe send failure (%d)\n", err));
return (ZYD_FAILURE);
}
return (ZYD_SUCCESS);
}
/*
* Vendor-specific read from the default control pipe.
*/
static zyd_res
{
int err;
/* Pointer msg must be either set to NULL or point to a valid mblk! */
if (err != USB_SUCCESS) {
return (ZYD_FAILURE);
}
ZYD_WARN("control pipe failure: "
return (ZYD_FAILURE);
}
/* Fragmented message, concatenate */
}
/*
* Now we can be sure the message is in a single block
* so we can copy it.
*/
return (ZYD_SUCCESS);
}
/*
* Load firmware into the chip.
*/
{
while (size > 0) {
!= USB_SUCCESS)
return (ZYD_FAILURE);
}
/* check whether the upload succeeded */
!= ZYD_SUCCESS)
return (ZYD_FAILURE);
}
/*
* Return a specific alt_if from the device descriptor tree.
*/
static usb_alt_if_data_t *
{
/*
* Assume everything is in the tree for now,
* (USB_PARSE_LVL_ALL)
* so we can directly index the array.
*/
/* Descend to configuration, configs are 1-based */
return (NULL);
/* Descend to interface */
return (NULL);
/* Descend to alt */
return (NULL);
return (ifalt);
}
/*
* Print all endpoints of an alt_if.
*/
static void
{
int i;
for (i = 0; i < ifalt->altif_n_ep; i++) {
}
}
/*
* For the given alt_if, find an endpoint with the given
* address and direction.
*
* ep_direction USB_EP_DIR_IN or USB_EP_DIR_OUT
*/
static usb_ep_data_t *
{
int i;
for (i = 0; i < alt_if->altif_n_ep; i++) {
return (ep_data);
}
}
return (NULL);
}
enum zyd_usb_use_attr
{
ZYD_USB_USE_ATTR = 1,
ZYD_USB_NO_ATTR = 0
};
/*
* alt_if. Furthemore, if use_attr == ZYD_USB_USE_ATTR,
* check whether the endpoint's transfer type is attr.
*/
static zyd_res
enum zyd_usb_use_attr use_attr,
{
if ((use_attr == ZYD_USB_USE_ATTR) &&
return (ZYD_FAILURE);
}
return (ZYD_FAILURE);
}
return (ZYD_SUCCESS);
}
/*
* Open communication pipes.
*
* The following pipes are used by the ZD1211:
*
* 1/OUT BULK
* 2/IN BULK
* 3/IN INTR
* 4/OUT BULK or INTR
*/
{
ZYD_WARN("alt_if not found\n");
return (ZYD_FAILURE);
}
#ifdef DEBUG
if (zyd_dbg_flags & ZYD_DBG_USB)
#endif
ZYD_SUCCESS) {
ZYD_WARN("failed to open data OUT pipe\n");
goto fail;
}
ZYD_SUCCESS) {
ZYD_WARN("failed to open data IN pipe\n");
goto fail;
}
ZYD_SUCCESS) {
ZYD_WARN("failed to open command IN pipe\n");
goto fail;
}
/*
* Pipe 4/OUT is either a bulk or interrupt pipe.
*/
ZYD_SUCCESS) {
ZYD_WARN("failed to open command OUT pipe\n");
goto fail;
}
return (ZYD_SUCCESS);
fail:
return (ZYD_FAILURE);
}
/*
* Close communication pipes.
*/
void
{
}
}
}
}
}
/*
* Send a sequence of bytes to a bulk pipe.
*
* uc pointer to usb module state
* data pointer to a buffer of bytes
* len size of the buffer (bytes)
*/
/*ARGSUSED*/
static void
{
else
}
if (resched)
}
/*
* Called when the transfer from zyd_usb_bulk_pipe_send() terminates
* or an exception occurs on the pipe.
*/
/*ARGSUSED*/
static void
{
struct zyd_cb_lock *lock;
/* Just signal that something happened */
}
static zyd_res
{
int res;
struct zyd_cb_lock lock;
ZYD_WARN("failed to allocate bulk request\n");
return (ZYD_FAILURE);
}
if (res != USB_SUCCESS) {
"failed writing to bulk OUT pipe (%d)\n", res));
return (ZYD_FAILURE);
}
ZYD_WARN("timeout - pipe reset\n");
res = ZYD_FAILURE;
} else {
}
return (res);
}
/*
* Called when the transfer from zyd_usb_intr_pipe_send() terminates
* or an exception occurs on the pipe.
*/
/*ARGSUSED*/
static void
{
struct zyd_cb_lock *lock;
/* Just signal that something happened */
}
/*
* Send a sequence of bytes to an interrupt pipe.
*
* uc pointer to usb module state
* data pointer to a buffer of bytes
* len size of the buffer (bytes)
*/
static zyd_res
{
int res;
struct zyd_cb_lock lock;
ZYD_WARN("failed to allocate interupt request\n");
return (ZYD_FAILURE);
}
if (res != USB_SUCCESS) {
return (ZYD_FAILURE);
}
ZYD_WARN("timeout - pipe reset\n");
res = ZYD_FAILURE;
} else {
}
return (res);
}
/*
* Send a sequence of bytes to the cmd_out pipe. (in a single USB transfer)
*
* uc pointer to usb module state
* data pointer to a buffer of bytes
* len size of the buffer (bytes)
*/
static zyd_res
{
/* Determine the type of cmd_out */
if (type == USB_EP_ATTR_BULK)
else
return (res);
}
/*
* Format and send a command to the cmd_out pipe.
*
* uc pointer to usb module state
* code ZD command code (16-bit)
* data raw buffer containing command data
* len size of the data buffer (bytes)
*/
{
if (res != ZYD_SUCCESS) {
return (ZYD_FAILURE);
}
return (ZYD_SUCCESS);
}
/*
* Issue an ioread request.
*
* Issues a ZD ioread command (with a vector of addresses passed in raw
* form as in_data) and blocks until the response is received
* and filled into the response buffer.
*
* uc pointer to usb module state
* in_data pointer to request data
* in_len request data size (bytes)
* out_data pointer to response buffer
* out_len response buffer size (bytes)
*/
{
int cnt;
/* Initialise io_read structure */
if (res != ZYD_SUCCESS) {
return (ZYD_FAILURE);
}
cnt = 0;
++cnt;
}
ZYD_WARN("I/O read request: timeout\n");
return (ZYD_FAILURE);
}
return (ZYD_FAILURE);
}
return (ZYD_SUCCESS);
}
/*
* Called when data arrives from the cmd_in pipe.
*/
/*ARGSUSED*/
static void
{
struct zyd_ioread *rdp;
unsigned char *data;
/* Fragmented message, concatenate */
} else {
/* Non-fragmented message, use directly */
}
if (code != ZYD_RESPONSE_IOREAD) {
/* Other response types not handled yet */
return;
}
ZYD_WARN("no ioread pending\n");
return;
}
/* Now move on to the data part */
ZYD_WARN("too few bytes received\n");
}
}
/*
* Called when an exception occurs on the cmd_in pipe.
*/
/*ARGSUSED*/
static void
{
struct zyd_ioread *rdp;
}
}
/*
* Start interrupt polling on the cmd_in pipe.
*/
{
int res;
ZYD_WARN("failed to allocate interrupt request\n");
return (ZYD_FAILURE);
}
if (res != USB_SUCCESS) {
ZYD_WARN("failed starting command IN polling: pipe failure\n");
return (ZYD_FAILURE);
}
return (ZYD_SUCCESS);
}
/*
* Stop interrupt polling on the cmd_in pipe.
*/
void
{
}
/*
* Called when data arrives on the data_in pipe.
*/
/*ARGSUSED*/
static void
{
struct zyd_rx_desc *desc;
unsigned char *data;
/* Fragmented STREAMS message? */
/* Fragmented, concatenate it into a single block */
ZYD_WARN("failed to concatenate fragments\n");
goto error;
}
} else {
/* Not fragmented, use directly */
}
if (len < 2) {
ZYD_WARN("received usb transfer too short\n");
goto error;
}
/*
* If this is a composite packet, the last two bytes contain
* two special signature bytes.
*/
/* multi-frame transfer */
int i;
for (i = 0; i < ZYD_MAX_RXFRAMECNT; i++) {
break;
/* next frame is aligned on a 32-bit boundary */
}
} else {
/* single-frame transfer */
}
return;
ZYD_WARN("error restarting data_in transfer\n");
}
}
/*
* Called when an exception occurs on the data_in pipe.
*/
/*ARGSUSED*/
static void
{
}
/*
* Start a receive request on the data_in pipe.
*/
static zyd_res
{
int res;
ZYD_WARN("failed to allocate bulk IN request\n");
return (ZYD_FAILURE);
}
req->bulk_timeout = 0;
if (res != USB_SUCCESS) {
ZYD_WARN("error starting receive request on data_in pipe\n");
return (ZYD_FAILURE);
}
return (ZYD_SUCCESS);
}
/*
* Start receiving packets on the data_in pipe.
*/
{
for (int i = 0; i < ZYD_RX_LIST_COUNT; i++) {
ZYD_WARN("failed to start data IN requests\n");
return (ZYD_FAILURE);
}
}
return (ZYD_SUCCESS);
}
/*
* Stop receiving packets on the data_in pipe.
*/
void
{
}
/*
* Send a packet to data_out.
*
* A packet consists of a zyd_tx_header + the IEEE802.11 frame.
*/
{
int res;
ZYD_WARN("failed to allocate bulk request\n");
return (ZYD_FAILURE);
}
send_req->bulk_cb_flags = 0;
if (res != USB_SUCCESS) {
return (USB_FAILURE);
}
return (USB_SUCCESS);
}
/*
* Initialize USB device communication and USB module state.
*
* uc pointer to usb module state
* dip pointer to device info structure
*/
{
int ures;
if (ures != USB_SUCCESS) {
return (ZYD_FAILURE);
}
/*
* LVL_ALL is needed for later endpoint scanning,
* and the tree must not be freed before that.
*/
if (ures != USB_SUCCESS) {
goto fail;
}
if (ures != USB_SUCCESS) {
goto fail;
}
if (ures != USB_SUCCESS) {
ZYD_WARN("usb_register_hotplug_cbs failed, error code: %d\n",
ures);
goto fail;
}
return (ZYD_SUCCESS);
fail:
return (ZYD_FAILURE);
}
/*
* Deinitialize USB device communication.
*/
void
{
}
/*
* Device connected
*/
static int
{
"reconnect before resume\n"));
/* check device changes after disconnect */
return (DDI_FAILURE);
}
ZYD_WARN("failed to reinit hardware\n");
return (DDI_FAILURE);
}
ZYD_WARN("failed to restart hardware\n");
goto fail;
}
}
return (DDI_SUCCESS);
fail:
return (DDI_FAILURE);
}
static int
{
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
return (DDI_SUCCESS);
}
int
{
"suspend after disconnect\n"));
return (DDI_SUCCESS);
}
return (DDI_SUCCESS);
}
int
{
"resume after disconnect\n"));
return (DDI_SUCCESS);
}
/* check device changes after disconnect */
ZYD_WARN("different device connected to same port\n");
return (DDI_SUCCESS);
}
ZYD_WARN("failed to reinit hardware\n");
return (DDI_FAILURE);
}
ZYD_WARN("failed to restart hardware\n");
return (DDI_FAILURE);
}
}
return (DDI_SUCCESS);
}