icE1usb: Move GPS-DO USB control to separate USB interface

doing so significantly simplifies the development of a Linux kernel
driver, as the GPS-DO only exists once (not twice, like the per-E1-line
interface), and Linux kernel USB drivers typically are for an interface.

There is an option to write a usb_device_driver, but doing so will
exclude the per-interface drivers from still being probed in their usual
fashion.

While we introduce this new USB Interface for the GPS-DO, we also
move the related control endpoint requests from the device level to the
interface level.

Finally, some naming inconsistency between "enum
ice1usb_gpsdo_antenna_state" vs. the member name antenna_status is
resolved.

Change-Id: Icd6555a14896c38626fb147b78af44ff719f2254
This commit is contained in:
Harald Welte 2022-01-30 20:41:12 +01:00
parent fddf5990bd
commit cac342af6b
10 changed files with 172 additions and 82 deletions

View File

@ -56,6 +56,7 @@ HEADERS_app=\
usb_dev.h \
usb_e1.h \
usb_gps.h \
usb_gpsdo.h \
usb_str_app.gen.h \
$(NULL)
@ -69,6 +70,7 @@ SOURCES_app=\
usb_dev.c \
usb_e1.c \
usb_gps.c \
usb_gpsdo.c \
$(NULL)

View File

@ -23,6 +23,7 @@
#include "usb_dev.h"
#include "usb_e1.h"
#include "usb_gps.h"
#include "usb_gpsdo.h"
#include "utils.h"
@ -109,6 +110,7 @@ void main()
usb_dfu_rt_init();
usb_e1_init();
usb_gps_init();
usb_gpsdo_init();
/* Start */
led_state(true);

View File

@ -96,7 +96,7 @@ gpsdo_get_status(struct e1usb_gpsdo_status *status)
};
status->state = state_map[g_gpsdo.state];
status->antenna_status = ant_map[gps_antenna_status()];
status->antenna_state = ant_map[gps_antenna_status()];
status->valid_fix = gps_has_valid_fix();
status->mode = (g_gpsdo.state == STATE_DISABLED) ? ICE1USB_GPSDO_MODE_DISABLED : ICE1USB_GPSDO_MODE_AUTO;
status->tune.coarse = g_gpsdo.tune.coarse;

View File

@ -17,17 +17,22 @@
/*! returns a bit-mask of optional device capabilities (see enum e1usb_dev_capability) */
#define ICE1USB_DEV_GET_CAPABILITIES 0x01
#define ICE1USB_DEV_GET_FW_BUILD 0x02
#define ICE1USB_DEV_GET_GPSDO_STATUS 0x10
#define ICE1USB_DEV_GET_GPSDO_MODE 0x12 /*!< uint8_t */
#define ICE1USB_DEV_SET_GPSDO_MODE 0x13 /*!< wValue = mode */
#define ICE1USB_DEV_GET_GPSDO_TUNE 0x14 /*!< data = struct e1usb_gpsdo_tune */
#define ICE1USB_DEV_SET_GPSDO_TUNE 0x15 /*!< data = struct e1usb_gpsdo_tune */
enum e1usb_dev_capability {
/*! Does this board have a GPS-DO */
ICE1USB_DEV_CAP_GPSDO,
};
/***********************************************************************
* Control Endpoint / GPS-DO Interface Requests
***********************************************************************/
#define ICE1USB_INTF_GET_GPSDO_STATUS 0x10
#define ICE1USB_INTF_GET_GPSDO_MODE 0x12 /*!< uint8_t */
#define ICE1USB_INTF_SET_GPSDO_MODE 0x13 /*!< wValue = mode */
#define ICE1USB_INTF_GET_GPSDO_TUNE 0x14 /*!< data = struct e1usb_gpsdo_tune */
#define ICE1USB_INTF_SET_GPSDO_TUNE 0x15 /*!< data = struct e1usb_gpsdo_tune */
enum ice1usb_gpsdo_mode {
ICE1USB_GPSDO_MODE_DISABLED = 0,
ICE1USB_GPSDO_MODE_AUTO = 1,
@ -55,7 +60,7 @@ struct e1usb_gpsdo_tune {
struct e1usb_gpsdo_status {
uint8_t state;
uint8_t antenna_status; /*!< Antenna status */
uint8_t antenna_state; /*!< Antenna state */
uint8_t valid_fix; /*!< Valid GPS Fix (0/1) */
uint8_t mode; /*!< Current configured operating mode */
struct e1usb_gpsdo_tune tune; /*!< Current VCXO tuning values */
@ -63,7 +68,9 @@ struct e1usb_gpsdo_status {
} __attribute__((packed));
/* Interface Requests */
/***********************************************************************
* Control Endpoint / E1 Interface Requests
***********************************************************************/
/*! returns a bit-mask of optional device capabilities (see enum e1usb_intf_capability) */
#define ICE1USB_INTF_GET_CAPABILITIES 0x01

View File

@ -53,6 +53,11 @@ static const struct {
struct usb_ep_desc ep_data_in;
} __attribute__ ((packed)) cdc;
/* GPS-DO (control EP only) */
struct {
struct usb_intf_desc intf;
} __attribute__ ((packed)) gpsdo;
/* DFU Runtime */
struct {
struct usb_intf_desc intf;
@ -275,6 +280,19 @@ static const struct {
.bInterval = 0x00,
},
},
.gpsdo = {
.intf = {
.bLength = sizeof(struct usb_intf_desc),
.bDescriptorType = USB_DT_INTF,
.bInterfaceNumber = USB_INTF_GPSDO,
.bAlternateSetting = 0,
.bNumEndpoints = 0,
.bInterfaceClass = 0xff,
.bInterfaceSubClass = 0xe1,
.bInterfaceProtocol = 0xd0,
.iInterface = 11,
}
},
.dfu = {
.intf = {
.bLength = sizeof(struct usb_intf_desc),
@ -285,7 +303,7 @@ static const struct {
.bInterfaceClass = 0xfe,
.bInterfaceSubClass = 0x01,
.bInterfaceProtocol = 0x01,
.iInterface = 11,
.iInterface = 12,
},
.func = {
.bLength = sizeof(struct usb_dfu_func_desc),

View File

@ -10,8 +10,9 @@
#define USB_INTF_E1(p) (0 + (p))
#define USB_INTF_GPS_CDC_CTL 2
#define USB_INTF_GPS_CDC_DATA 3
#define USB_INTF_DFU 4
#define USB_INTF_NUM 5
#define USB_INTF_GPSDO 4
#define USB_INTF_DFU 5
#define USB_INTF_NUM 6
#define USB_EP_E1_IN(p) (0x82 + (3 * (p)))
#define USB_EP_E1_OUT(p) (0x01 + (3 * (p)))

View File

@ -12,7 +12,6 @@
#include <no2usb/usb_proto.h>
#include "console.h"
#include "gpsdo.h"
#include "misc.h"
#include "ice1usb_proto.h"
@ -21,61 +20,6 @@
const char *fw_build_str = BUILD_INFO;
static void
_get_gpsdo_status(struct usb_ctrl_req *req, struct usb_xfer *xfer)
{
struct e1usb_gpsdo_status status;
gpsdo_get_status(&status);
memcpy(xfer->data, &status, sizeof(struct e1usb_gpsdo_status));
xfer->len = sizeof(struct e1usb_gpsdo_status);
}
static void
_get_gpsdo_mode(struct usb_ctrl_req *req, struct usb_xfer *xfer)
{
xfer->data[0] = gpsdo_enabled() ? ICE1USB_GPSDO_MODE_DISABLED : ICE1USB_GPSDO_MODE_AUTO;
xfer->len = 1;
}
static void
_set_gpsdo_mode(struct usb_ctrl_req *req, struct usb_xfer *xfer)
{
gpsdo_enable(req->wValue != ICE1USB_GPSDO_MODE_DISABLED);
}
static void
_get_gpsdo_tune(struct usb_ctrl_req *req, struct usb_xfer *xfer)
{
uint16_t coarse, fine;
struct e1usb_gpsdo_tune tune;
gpsdo_get_tune(&coarse, &fine);
tune.coarse = coarse;
tune.fine = fine;
memcpy(xfer->data, &tune, sizeof(struct e1usb_gpsdo_tune));
xfer->len = sizeof(struct e1usb_gpsdo_tune);
}
static bool
_set_gpsdo_tune_done(struct usb_xfer *xfer)
{
const struct e1usb_gpsdo_tune *tune = (const void *) xfer->data;
gpsdo_set_tune(tune->coarse, tune->fine);
return true;
}
static void
_set_gpsdo_tune(struct usb_ctrl_req *req, struct usb_xfer *xfer)
{
xfer->cb_done = _set_gpsdo_tune_done;
xfer->cb_ctx = req;
xfer->len = sizeof(struct e1usb_gpsdo_tune);
}
static enum usb_fnd_resp
_usb_dev_ctrl_req(struct usb_ctrl_req *req, struct usb_xfer *xfer)
{
@ -93,21 +37,6 @@ _usb_dev_ctrl_req(struct usb_ctrl_req *req, struct usb_xfer *xfer)
xfer->data = (void*) fw_build_str;
xfer->len = strlen(fw_build_str);
break;
case ICE1USB_DEV_GET_GPSDO_STATUS:
_get_gpsdo_status(req, xfer);
break;
case ICE1USB_DEV_GET_GPSDO_MODE:
_get_gpsdo_mode(req, xfer);
break;
case ICE1USB_DEV_SET_GPSDO_MODE:
_set_gpsdo_mode(req, xfer);
break;
case ICE1USB_DEV_GET_GPSDO_TUNE:
_get_gpsdo_tune(req, xfer);
break;
case ICE1USB_DEV_SET_GPSDO_TUNE:
_set_gpsdo_tune(req, xfer);
break;
default:
return USB_FND_ERROR;
}

View File

@ -0,0 +1,120 @@
/*
* usb_gpsdo.c
*
* Copyright (C) 2019-2022 Sylvain Munaut <tnt@246tNt.com>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <no2usb/usb.h>
#include <no2usb/usb_hw.h>
#include <no2usb/usb_priv.h>
#include <no2usb/usb_proto.h>
#include "usb_desc_ids.h"
#include "gpsdo.h"
#include "ice1usb_proto.h"
static void
_get_gpsdo_status(struct usb_ctrl_req *req, struct usb_xfer *xfer)
{
struct e1usb_gpsdo_status status;
gpsdo_get_status(&status);
memcpy(xfer->data, &status, sizeof(struct e1usb_gpsdo_status));
xfer->len = sizeof(struct e1usb_gpsdo_status);
}
static void
_get_gpsdo_mode(struct usb_ctrl_req *req, struct usb_xfer *xfer)
{
xfer->data[0] = gpsdo_enabled() ? ICE1USB_GPSDO_MODE_DISABLED : ICE1USB_GPSDO_MODE_AUTO;
xfer->len = 1;
}
static void
_set_gpsdo_mode(struct usb_ctrl_req *req, struct usb_xfer *xfer)
{
gpsdo_enable(req->wValue != ICE1USB_GPSDO_MODE_DISABLED);
}
static void
_get_gpsdo_tune(struct usb_ctrl_req *req, struct usb_xfer *xfer)
{
uint16_t coarse, fine;
struct e1usb_gpsdo_tune tune;
gpsdo_get_tune(&coarse, &fine);
tune.coarse = coarse;
tune.fine = fine;
memcpy(xfer->data, &tune, sizeof(struct e1usb_gpsdo_tune));
xfer->len = sizeof(struct e1usb_gpsdo_tune);
}
static bool
_set_gpsdo_tune_done(struct usb_xfer *xfer)
{
const struct e1usb_gpsdo_tune *tune = (const void *) xfer->data;
gpsdo_set_tune(tune->coarse, tune->fine);
return true;
}
static void
_set_gpsdo_tune(struct usb_ctrl_req *req, struct usb_xfer *xfer)
{
xfer->cb_done = _set_gpsdo_tune_done;
xfer->cb_ctx = req;
xfer->len = sizeof(struct e1usb_gpsdo_tune);
}
static enum usb_fnd_resp
_gpsdo_ctrl_req(struct usb_ctrl_req *req, struct usb_xfer *xfer)
{
/* Check it's for an interface */
if (USB_REQ_TYPE_RCPT(req) != (USB_REQ_TYPE_VENDOR | USB_REQ_RCPT_INTF))
return USB_FND_CONTINUE;
/* Check it's for the GPS-DO interface */
if (req->wIndex != USB_INTF_GPSDO)
return USB_FND_CONTINUE;
switch (req->bRequest) {
case ICE1USB_INTF_GET_GPSDO_STATUS:
_get_gpsdo_status(req, xfer);
break;
case ICE1USB_INTF_GET_GPSDO_MODE:
_get_gpsdo_mode(req, xfer);
break;
case ICE1USB_INTF_SET_GPSDO_MODE:
_set_gpsdo_mode(req, xfer);
break;
case ICE1USB_INTF_GET_GPSDO_TUNE:
_get_gpsdo_tune(req, xfer);
break;
case ICE1USB_INTF_SET_GPSDO_TUNE:
_set_gpsdo_tune(req, xfer);
break;
default:
return USB_FND_ERROR;
}
return USB_FND_SUCCESS;
}
static struct usb_fn_drv _gpsdo_drv = {
.ctrl_req = _gpsdo_ctrl_req,
};
void
usb_gpsdo_init(void)
{
usb_register_function_driver(&_gpsdo_drv);
}

View File

@ -0,0 +1,10 @@
/*
* usb_gpsdo.h
*
* Copyright (C) 2022 Harald Welte <laforge@osmocom.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#pragma once
void usb_gpsdo_init(void);

View File

@ -8,4 +8,5 @@ E1 port 1 (disabled)
E1 port 1
GPS (CDC control)
GPS (CDC data)
GPS-DO control
DFU runtime