blob: 4dd8913ce0b72ad98bf1c9f53c14d41ce87ea1de [file] [log] [blame]
Harald Weltecac342a2022-01-30 20:41:12 +01001/*
2 * usb_gpsdo.c
3 *
4 * Copyright (C) 2019-2022 Sylvain Munaut <tnt@246tNt.com>
5 * SPDX-License-Identifier: GPL-3.0-or-later
6 */
7
8#include <stdint.h>
9#include <stdbool.h>
10#include <string.h>
11
12#include <no2usb/usb.h>
13#include <no2usb/usb_hw.h>
14#include <no2usb/usb_priv.h>
15
16#include <no2usb/usb_proto.h>
17
18#include "usb_desc_ids.h"
19#include "gpsdo.h"
20
21#include "ice1usb_proto.h"
22
23static void
24_get_gpsdo_status(struct usb_ctrl_req *req, struct usb_xfer *xfer)
25{
26 struct e1usb_gpsdo_status status;
27
28 gpsdo_get_status(&status);
29
30 memcpy(xfer->data, &status, sizeof(struct e1usb_gpsdo_status));
31 xfer->len = sizeof(struct e1usb_gpsdo_status);
32}
33
34static void
35_get_gpsdo_mode(struct usb_ctrl_req *req, struct usb_xfer *xfer)
36{
37 xfer->data[0] = gpsdo_enabled() ? ICE1USB_GPSDO_MODE_DISABLED : ICE1USB_GPSDO_MODE_AUTO;
38 xfer->len = 1;
39}
40
41static void
42_set_gpsdo_mode(struct usb_ctrl_req *req, struct usb_xfer *xfer)
43{
44 gpsdo_enable(req->wValue != ICE1USB_GPSDO_MODE_DISABLED);
45}
46
47static void
48_get_gpsdo_tune(struct usb_ctrl_req *req, struct usb_xfer *xfer)
49{
50 uint16_t coarse, fine;
51 struct e1usb_gpsdo_tune tune;
52
53 gpsdo_get_tune(&coarse, &fine);
54 tune.coarse = coarse;
55 tune.fine = fine;
56
57 memcpy(xfer->data, &tune, sizeof(struct e1usb_gpsdo_tune));
58 xfer->len = sizeof(struct e1usb_gpsdo_tune);
59}
60
61static bool
62_set_gpsdo_tune_done(struct usb_xfer *xfer)
63{
64 const struct e1usb_gpsdo_tune *tune = (const void *) xfer->data;
65 gpsdo_set_tune(tune->coarse, tune->fine);
66 return true;
67}
68
69static void
70_set_gpsdo_tune(struct usb_ctrl_req *req, struct usb_xfer *xfer)
71{
72 xfer->cb_done = _set_gpsdo_tune_done;
73 xfer->cb_ctx = req;
74 xfer->len = sizeof(struct e1usb_gpsdo_tune);
75}
76
77
78static enum usb_fnd_resp
79_gpsdo_ctrl_req(struct usb_ctrl_req *req, struct usb_xfer *xfer)
80{
81 /* Check it's for an interface */
82 if (USB_REQ_TYPE_RCPT(req) != (USB_REQ_TYPE_VENDOR | USB_REQ_RCPT_INTF))
83 return USB_FND_CONTINUE;
84
85 /* Check it's for the GPS-DO interface */
86 if (req->wIndex != USB_INTF_GPSDO)
87 return USB_FND_CONTINUE;
88
89 switch (req->bRequest) {
90 case ICE1USB_INTF_GET_GPSDO_STATUS:
91 _get_gpsdo_status(req, xfer);
92 break;
93 case ICE1USB_INTF_GET_GPSDO_MODE:
94 _get_gpsdo_mode(req, xfer);
95 break;
96 case ICE1USB_INTF_SET_GPSDO_MODE:
97 _set_gpsdo_mode(req, xfer);
98 break;
99 case ICE1USB_INTF_GET_GPSDO_TUNE:
100 _get_gpsdo_tune(req, xfer);
101 break;
102 case ICE1USB_INTF_SET_GPSDO_TUNE:
103 _set_gpsdo_tune(req, xfer);
104 break;
105 default:
106 return USB_FND_ERROR;
107 }
108
109 return USB_FND_SUCCESS;
110}
111
112static struct usb_fn_drv _gpsdo_drv = {
113 .ctrl_req = _gpsdo_ctrl_req,
114};
115
116void
117usb_gpsdo_init(void)
118{
119 usb_register_function_driver(&_gpsdo_drv);
120}