1/*	$OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $	*/
2
3/*-
4 * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
5 * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org>
6 * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
7 *
8 * Permission to use, copy, modify, and distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice and this permission notice appear in all copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 */
20
21#include <sys/cdefs.h>
22__FBSDID("$FreeBSD$");
23
24#include <sys/param.h>
25#include <sys/lock.h>
26#include <sys/mutex.h>
27#include <sys/mbuf.h>
28#include <sys/kernel.h>
29#include <sys/socket.h>
30#include <sys/systm.h>
31#include <sys/malloc.h>
32#include <sys/queue.h>
33#include <sys/taskqueue.h>
34#include <sys/bus.h>
35#include <sys/endian.h>
36
37#include <net/if.h>
38#include <net/ethernet.h>
39#include <net/if_media.h>
40
41#include <net80211/ieee80211_var.h>
42#include <net80211/ieee80211_radiotap.h>
43
44#include <dev/usb/usb.h>
45#include <dev/usb/usbdi.h>
46
47#include <dev/rtwn/if_rtwnvar.h>
48#include <dev/rtwn/if_rtwn_debug.h>
49
50#include <dev/rtwn/usb/rtwn_usb_var.h>
51#include <dev/rtwn/usb/rtwn_usb_reg.h>
52
53static int	rtwn_do_request(struct rtwn_softc *,
54		    struct usb_device_request *, void *);
55static int	rtwn_usb_read_region_1(struct rtwn_softc *,
56		    uint16_t, uint8_t *, int);
57
58/* USB Requests. */
59#define R92C_REQ_REGS		0x05
60
61static int
62rtwn_do_request(struct rtwn_softc *sc, struct usb_device_request *req,
63    void *data)
64{
65	struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc);
66	usb_error_t err;
67	int ntries = 10;
68
69	RTWN_ASSERT_LOCKED(sc);
70
71	while (ntries--) {
72		err = usbd_do_request_flags(uc->uc_udev, &sc->sc_mtx,
73		    req, data, 0, NULL, 250 /* ms */);
74		if (err == USB_ERR_NORMAL_COMPLETION)
75			return (0);
76
77		RTWN_DPRINTF(sc, RTWN_DEBUG_USB,
78		    "%s: control request failed, %s (retries left: %d)\n",
79		    __func__, usbd_errstr(err), ntries);
80		if (err == USB_ERR_NOT_CONFIGURED)
81			return (ENXIO);
82
83		usb_pause_mtx(&sc->sc_mtx, hz / 100);
84	}
85	return (EIO);
86}
87
88/* export for rtwn_fw_write_block() */
89int
90rtwn_usb_write_region_1(struct rtwn_softc *sc, uint16_t addr, uint8_t *buf,
91    int len)
92{
93	usb_device_request_t req;
94
95	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
96	req.bRequest = R92C_REQ_REGS;
97	USETW(req.wValue, addr);
98	USETW(req.wIndex, 0);
99	USETW(req.wLength, len);
100	return (rtwn_do_request(sc, &req, buf));
101}
102
103int
104rtwn_usb_write_1(struct rtwn_softc *sc, uint16_t addr, uint8_t val)
105{
106	return (rtwn_usb_write_region_1(sc, addr, &val, sizeof(val)));
107}
108
109int
110rtwn_usb_write_2(struct rtwn_softc *sc, uint16_t addr, uint16_t val)
111{
112	val = htole16(val);
113	return (rtwn_usb_write_region_1(sc, addr, (uint8_t *)&val, sizeof(val)));
114}
115
116int
117rtwn_usb_write_4(struct rtwn_softc *sc, uint16_t addr, uint32_t val)
118{
119	val = htole32(val);
120	return (rtwn_usb_write_region_1(sc, addr, (uint8_t *)&val, sizeof(val)));
121}
122
123static int
124rtwn_usb_read_region_1(struct rtwn_softc *sc, uint16_t addr, uint8_t *buf,
125    int len)
126{
127	usb_device_request_t req;
128
129	req.bmRequestType = UT_READ_VENDOR_DEVICE;
130	req.bRequest = R92C_REQ_REGS;
131	USETW(req.wValue, addr);
132	USETW(req.wIndex, 0);
133	USETW(req.wLength, len);
134	return (rtwn_do_request(sc, &req, buf));
135}
136
137uint8_t
138rtwn_usb_read_1(struct rtwn_softc *sc, uint16_t addr)
139{
140	uint8_t val;
141
142	if (rtwn_usb_read_region_1(sc, addr, &val, 1) != 0)
143		return (0xff);
144	return (val);
145}
146
147uint16_t
148rtwn_usb_read_2(struct rtwn_softc *sc, uint16_t addr)
149{
150	uint16_t val;
151
152	if (rtwn_usb_read_region_1(sc, addr, (uint8_t *)&val, 2) != 0)
153		return (0xffff);
154	return (le16toh(val));
155}
156
157uint32_t
158rtwn_usb_read_4(struct rtwn_softc *sc, uint16_t addr)
159{
160	uint32_t val;
161
162	if (rtwn_usb_read_region_1(sc, addr, (uint8_t *)&val, 4) != 0)
163		return (0xffffffff);
164	return (le32toh(val));
165}
166
167void
168rtwn_usb_delay(struct rtwn_softc *sc, int usec)
169{
170
171	/* 1ms delay as default is too big. */
172	if (usec < 1000)
173		DELAY(usec);
174	else
175		usb_pause_mtx(&sc->sc_mtx, msecs_to_ticks(usec / 1000));
176}
177