WIP: USB control request handling
Change-Id: I9d28566ba21a2a78def5e4a0ba07ecbc4a583aa9
This commit is contained in:
parent
22bcd180d2
commit
069d34377d
|
@ -0,0 +1,69 @@
|
|||
#pragma once
|
||||
|
||||
/* Header file describing the USB protocol between the icE1usb firmware and the host
|
||||
* software (currently really only osmo-e1d) */
|
||||
|
||||
/* Device Requests */
|
||||
|
||||
/*! returns a bit-mask of optional device capabilities (see enum e1usb_dev_capability) */
|
||||
#define ICE1USB_DEV_GET_CAPABILITIES 0x01
|
||||
/*! returns a
|
||||
#define ICE1USB_DEV_GET_FW_BUILD 0x02
|
||||
|
||||
enum e1usb_dev_capability {
|
||||
/*! Does this board have a GPS-DO */
|
||||
ICE1USB_DEV_CAP_GPSDO,
|
||||
};
|
||||
|
||||
|
||||
/* Interface Requests */
|
||||
|
||||
/*! returns a bit-mask of optional device capabilities (see enum e1usb_intf_capability) */
|
||||
#define ICE1USB_INTF_GET_CAPABILITIES 0x01
|
||||
#define ICE1USB_INTF_SET_TX_CFG 0x02 /*!< struct ice1usb_tx_config */
|
||||
#define ICE1USB_INTF_GET_TX_CFG 0x03 /*!< struct ice1usb_tx_config */
|
||||
#define ICE1USB_INTF_SET_RX_CFG 0x04 /*!< struct ice1usb_rx_config */
|
||||
#define ICE1USB_INTF_GET_RX_CFG 0x05 /*!< struct ice1usb_rx_config */
|
||||
|
||||
//enum e1usb_intf_capability { };
|
||||
|
||||
enum ice1usb_tx_mode {
|
||||
ICE1USB_TX_MODE_TRANSP = 0,
|
||||
ICE1USB_TX_MODE_TS0 = 1,
|
||||
ICE1USB_TX_MODE_TS0_CRC4 = 2,
|
||||
ICE1USB_TX_MODE_TS0_CRC4_E = 3,
|
||||
};
|
||||
|
||||
enum ice1usb_tx_timing {
|
||||
ICE1USB_TX_TIME_SRC_REMOTE = 0,
|
||||
ICE1USB_TX_TIME_SRC_LOCAL = 1,
|
||||
};
|
||||
|
||||
enum ice1usb_tx_ext_loopback {
|
||||
ICE1USB_TX_EXT_LOOPBACK_OFF = 0,
|
||||
ICE1USB_TX_EXT_LOOPBACK_SAME = 1,
|
||||
ICE1USB_TX_EXT_LOOPBACK_CROSS = 2,
|
||||
};
|
||||
|
||||
/* ICE1USB_INTF_{GET,SET}_TX_CFG */
|
||||
struct ice1usb_tx_config {
|
||||
uint8_t mode; /*!< enum ice1usb_tx_mode */
|
||||
uint8_t timing; /*!< enum ice1usb_tx_timing */
|
||||
uint8_t ext_loopback; /*!< enum ice1usb_tx_ext_loopback */
|
||||
uint8_t alarm; /*!< 1 = transmit alarm; 0 = don't */
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
enum ice1usb_rx_mode {
|
||||
/*! transparent, unaligned bitstream */
|
||||
ICE1USB_RX_MODE_TRANSP = 0,
|
||||
/*! alignment to E1 frame */
|
||||
ICE1USB_RX_MODE_FRAME = 1,
|
||||
/*! alignment to E1 multiframe */
|
||||
ICE1USB_RX_MODE_MULTIFRAME = 2,
|
||||
};
|
||||
|
||||
/* ICE1USB_INTF_{GET,SET}_RX_CFG */
|
||||
struct ice1usb_rx_config {
|
||||
uint8_t mode; /*!< enum ice1usb_rx_mode */
|
||||
} __attribute__((packed));
|
|
@ -16,11 +16,26 @@
|
|||
#include "misc.h"
|
||||
#include "e1.h"
|
||||
|
||||
#include "ice1usb_proto.h"
|
||||
|
||||
struct {
|
||||
bool running; /* are we running (transceiving USB data)? */
|
||||
int out_bdi; /* buffer descriptor index for OUT EP */
|
||||
int in_bdi; /* buffer descriptor index for IN EP */
|
||||
} g_usb_e1;
|
||||
struct ice1usb_tx_config tx_cfg;
|
||||
struct ice1usb_rx_config rx_cfg;
|
||||
} g_usb_e1 = {
|
||||
/* default configuration at power-up */
|
||||
.tx_cfg = {
|
||||
.mode = ICE1USB_TX_MODE_TS0_CRC4_E,
|
||||
.timing = ICE1USB_TX_TIME_SRC_REMOTE,
|
||||
.ext_loopback = ICE1USB_TX_EXT_LOOPBACK_OFF,
|
||||
.alarm = 0,
|
||||
},
|
||||
.rx_cfg = {
|
||||
.mode = ICE1USB_RX_MODE_MULTIFRAME,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
/* Hack */
|
||||
|
@ -261,10 +276,115 @@ _e1_get_intf(const struct usb_intf_desc *base, uint8_t *alt)
|
|||
return USB_FND_SUCCESS;
|
||||
}
|
||||
|
||||
static bool
|
||||
_set_tx_mode_done(struct usb_xfer *xfer)
|
||||
{
|
||||
const struct ice1usb_tx_config *cfg = (const struct ice1usb_tx_config *) xfer->data;
|
||||
printf("set_tx_mode %02x%02x%02x%02x\r\n",
|
||||
xfer->data[0], xfer->data[1], xfer->data[2], xfer->data[3]);
|
||||
g_usb_e1.tx_cfg = *cfg;
|
||||
/* FIXME: actually change E1 core config */
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
_set_rx_mode_done(struct usb_xfer *xfer)
|
||||
{
|
||||
const struct ice1usb_rx_config *cfg = (const struct ice1usb_rx_config *) xfer->data;
|
||||
printf("set_rx_mode %02x\r\n", xfer->data[0]);
|
||||
g_usb_e1.rx_cfg = *cfg;
|
||||
/* FIXME: actually change E1 core config */
|
||||
return true;
|
||||
}
|
||||
|
||||
/* per-interface requests */
|
||||
static enum usb_fnd_resp
|
||||
_e1_ctrl_req_intf(struct usb_ctrl_req *req, struct usb_xfer *xfer)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
switch (req->bRequest) {
|
||||
case ICE1USB_INTF_GET_CAPABILITIES:
|
||||
/* no optional capabilities yet */
|
||||
xfer->len = 0;
|
||||
break;
|
||||
case ICE1USB_INTF_SET_TX_CFG:
|
||||
if (req->wLength < sizeof(struct ice1usb_tx_config))
|
||||
return USB_FND_ERROR;
|
||||
xfer->cb_done = _set_tx_mode_done;
|
||||
xfer->cb_ctx = req;
|
||||
xfer->len = sizeof(struct ice1usb_tx_config);
|
||||
break;
|
||||
case ICE1USB_INTF_GET_TX_CFG:
|
||||
if (req->wLength < sizeof(struct ice1usb_tx_config))
|
||||
return USB_FND_ERROR;
|
||||
memcpy(xfer->data, &g_usb_e1.tx_cfg, sizeof(struct ice1usb_tx_config));
|
||||
xfer->len = sizeof(struct ice1usb_tx_config);
|
||||
break;
|
||||
case ICE1USB_INTF_SET_RX_CFG:
|
||||
if (req->wLength < sizeof(struct ice1usb_rx_config))
|
||||
return USB_FND_ERROR;
|
||||
xfer->cb_done = _set_rx_mode_done;
|
||||
xfer->cb_ctx = req;
|
||||
xfer->len = sizeof(struct ice1usb_rx_config);
|
||||
break;
|
||||
case ICE1USB_INTF_GET_RX_CFG:
|
||||
if (req->wLength < sizeof(struct ice1usb_rx_config))
|
||||
return USB_FND_ERROR;
|
||||
memcpy(xfer->data, &g_usb_e1.rx_cfg, sizeof(struct ice1usb_rx_config));
|
||||
xfer->len = sizeof(struct ice1usb_rx_config);
|
||||
break;
|
||||
default:
|
||||
return USB_FND_ERROR;
|
||||
}
|
||||
|
||||
return USB_FND_SUCCESS;
|
||||
}
|
||||
|
||||
/* device-global requests */
|
||||
static enum usb_fnd_resp
|
||||
_e1_ctrl_req_dev(struct usb_ctrl_req *req, struct usb_xfer *xfer)
|
||||
{
|
||||
switch (req->bRequest) {
|
||||
case ICE1USB_DEV_GET_CAPABILITIES:
|
||||
xfer->data[0] = (1 << ICE1USB_DEV_CAP_GPSDO);
|
||||
xfer->len = 1;
|
||||
break;
|
||||
default:
|
||||
return USB_FND_ERROR;
|
||||
}
|
||||
|
||||
return USB_FND_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/* USB host issues a control request to us */
|
||||
static enum usb_fnd_resp
|
||||
_e1_ctrl_req(struct usb_ctrl_req *req, struct usb_xfer *xfer)
|
||||
{
|
||||
if (USB_REQ_TYPE(req) != USB_REQ_TYPE_VENDOR)
|
||||
return USB_FND_CONTINUE;
|
||||
|
||||
switch (USB_REQ_RCPT(req)) {
|
||||
case USB_REQ_RCPT_DEV:
|
||||
return _e1_ctrl_req_dev(req, xfer);
|
||||
case USB_REQ_RCPT_INTF:
|
||||
if (req->wIndex != 0)
|
||||
return USB_FND_ERROR;
|
||||
return _e1_ctrl_req_intf(req, xfer);
|
||||
case USB_REQ_RCPT_EP:
|
||||
case USB_REQ_RCPT_OTHER:
|
||||
default:
|
||||
return USB_FND_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static struct usb_fn_drv _e1_drv = {
|
||||
.set_conf = _e1_set_conf,
|
||||
.set_intf = _e1_set_intf,
|
||||
.get_intf = _e1_get_intf,
|
||||
.ctrl_req = _e1_ctrl_req,
|
||||
};
|
||||
|
||||
void
|
||||
|
|
Loading…
Reference in New Issue