xref: /freebsd/sys/dev/thunderbolt/tb_dev.c (revision 2ed9833791f28e14843ac813f90cb030e45948dc)
1*2ed98337SAymeric Wibo /*-
2*2ed98337SAymeric Wibo  * SPDX-License-Identifier: BSD-2-Clause
3*2ed98337SAymeric Wibo  *
4*2ed98337SAymeric Wibo  * Copyright (c) 2022 Scott Long
5*2ed98337SAymeric Wibo  * All rights reserved.
6*2ed98337SAymeric Wibo  *
7*2ed98337SAymeric Wibo  * Redistribution and use in source and binary forms, with or without
8*2ed98337SAymeric Wibo  * modification, are permitted provided that the following conditions
9*2ed98337SAymeric Wibo  * are met:
10*2ed98337SAymeric Wibo  * 1. Redistributions of source code must retain the above copyright
11*2ed98337SAymeric Wibo  *    notice, this list of conditions and the following disclaimer.
12*2ed98337SAymeric Wibo  * 2. Redistributions in binary form must reproduce the above copyright
13*2ed98337SAymeric Wibo  *    notice, this list of conditions and the following disclaimer in the
14*2ed98337SAymeric Wibo  *    documentation and/or other materials provided with the distribution.
15*2ed98337SAymeric Wibo  *
16*2ed98337SAymeric Wibo  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17*2ed98337SAymeric Wibo  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18*2ed98337SAymeric Wibo  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19*2ed98337SAymeric Wibo  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20*2ed98337SAymeric Wibo  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21*2ed98337SAymeric Wibo  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22*2ed98337SAymeric Wibo  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23*2ed98337SAymeric Wibo  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24*2ed98337SAymeric Wibo  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25*2ed98337SAymeric Wibo  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26*2ed98337SAymeric Wibo  * SUCH DAMAGE.
27*2ed98337SAymeric Wibo  */
28*2ed98337SAymeric Wibo 
29*2ed98337SAymeric Wibo #include "opt_thunderbolt.h"
30*2ed98337SAymeric Wibo 
31*2ed98337SAymeric Wibo /* Userspace control device for USB4 / TB3 */
32*2ed98337SAymeric Wibo #include <sys/types.h>
33*2ed98337SAymeric Wibo #include <sys/param.h>
34*2ed98337SAymeric Wibo #include <sys/systm.h>
35*2ed98337SAymeric Wibo #include <sys/kernel.h>
36*2ed98337SAymeric Wibo #include <sys/module.h>
37*2ed98337SAymeric Wibo #include <sys/bus.h>
38*2ed98337SAymeric Wibo #include <sys/conf.h>
39*2ed98337SAymeric Wibo #include <sys/malloc.h>
40*2ed98337SAymeric Wibo #include <sys/queue.h>
41*2ed98337SAymeric Wibo #include <sys/sysctl.h>
42*2ed98337SAymeric Wibo #include <sys/lock.h>
43*2ed98337SAymeric Wibo #include <sys/mutex.h>
44*2ed98337SAymeric Wibo #include <sys/nv.h>
45*2ed98337SAymeric Wibo #include <sys/taskqueue.h>
46*2ed98337SAymeric Wibo #include <sys/gsb_crc32.h>
47*2ed98337SAymeric Wibo #include <sys/endian.h>
48*2ed98337SAymeric Wibo #include <vm/vm.h>
49*2ed98337SAymeric Wibo #include <vm/pmap.h>
50*2ed98337SAymeric Wibo 
51*2ed98337SAymeric Wibo #include <machine/bus.h>
52*2ed98337SAymeric Wibo #include <machine/stdarg.h>
53*2ed98337SAymeric Wibo 
54*2ed98337SAymeric Wibo #include <dev/thunderbolt/nhi_reg.h>
55*2ed98337SAymeric Wibo #include <dev/thunderbolt/nhi_var.h>
56*2ed98337SAymeric Wibo #include <dev/thunderbolt/tb_reg.h>
57*2ed98337SAymeric Wibo #include <dev/thunderbolt/tb_var.h>
58*2ed98337SAymeric Wibo #include <dev/thunderbolt/tbcfg_reg.h>
59*2ed98337SAymeric Wibo #include <dev/thunderbolt/router_var.h>
60*2ed98337SAymeric Wibo #include <dev/thunderbolt/tb_debug.h>
61*2ed98337SAymeric Wibo #include <dev/thunderbolt/tb_dev.h>
62*2ed98337SAymeric Wibo #include <dev/thunderbolt/tb_ioctl.h>
63*2ed98337SAymeric Wibo 
64*2ed98337SAymeric Wibo struct tbdev_if;
65*2ed98337SAymeric Wibo struct tbdev_dm;
66*2ed98337SAymeric Wibo struct tbdev_rt;
67*2ed98337SAymeric Wibo 
68*2ed98337SAymeric Wibo struct tbdev_if {
69*2ed98337SAymeric Wibo 	TAILQ_ENTRY(tbdev_if)	dev_next;
70*2ed98337SAymeric Wibo 	char			name[SPECNAMELEN];
71*2ed98337SAymeric Wibo };
72*2ed98337SAymeric Wibo 
73*2ed98337SAymeric Wibo struct tbdev_dm {
74*2ed98337SAymeric Wibo 	TAILQ_ENTRY(tbdev_dm)	dev_next;
75*2ed98337SAymeric Wibo 	char			uid[16];
76*2ed98337SAymeric Wibo };
77*2ed98337SAymeric Wibo 
78*2ed98337SAymeric Wibo struct tbdev_rt {
79*2ed98337SAymeric Wibo 	TAILQ_ENTRY(tbdev_rt)	dev_next;
80*2ed98337SAymeric Wibo 	uint64_t		route;
81*2ed98337SAymeric Wibo };
82*2ed98337SAymeric Wibo 
83*2ed98337SAymeric Wibo static int tbdev_static_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td);
84*2ed98337SAymeric Wibo 
85*2ed98337SAymeric Wibo static struct cdevsw tbdev_static_devsw = {
86*2ed98337SAymeric Wibo 	.d_version = D_VERSION,
87*2ed98337SAymeric Wibo 	.d_ioctl = tbdev_static_ioctl,
88*2ed98337SAymeric Wibo 	.d_name = "tbt"
89*2ed98337SAymeric Wibo };
90*2ed98337SAymeric Wibo static struct cdev *tb_dev = NULL;
91*2ed98337SAymeric Wibo 
92*2ed98337SAymeric Wibo static TAILQ_HEAD(, tbdev_if) tbdev_head = TAILQ_HEAD_INITIALIZER(tbdev_head);
93*2ed98337SAymeric Wibo static TAILQ_HEAD(, tbdev_dm) tbdomain_head = TAILQ_HEAD_INITIALIZER(tbdomain_head);
94*2ed98337SAymeric Wibo static TAILQ_HEAD(, tbdev_rt) tbrouter_head = TAILQ_HEAD_INITIALIZER(tbrouter_head);
95*2ed98337SAymeric Wibo 
96*2ed98337SAymeric Wibo static struct mtx tbdev_mtx;
97*2ed98337SAymeric Wibo MTX_SYSINIT(tbdev_mtx, &tbdev_mtx, "TBT Device Mutex", MTX_DEF);
98*2ed98337SAymeric Wibo 
99*2ed98337SAymeric Wibo MALLOC_DEFINE(M_THUNDERBOLT, "thunderbolt", "memory for thunderbolt");
100*2ed98337SAymeric Wibo 
101*2ed98337SAymeric Wibo static void
tbdev_init(void * arg)102*2ed98337SAymeric Wibo tbdev_init(void *arg)
103*2ed98337SAymeric Wibo {
104*2ed98337SAymeric Wibo 
105*2ed98337SAymeric Wibo 	tb_dev = make_dev(&tbdev_static_devsw, 0, UID_ROOT, GID_OPERATOR,
106*2ed98337SAymeric Wibo 	    0644, TBT_DEVICE_NAME);
107*2ed98337SAymeric Wibo 	if (tb_dev == NULL)
108*2ed98337SAymeric Wibo 		printf("Cannot create Thunderbolt system device\n");
109*2ed98337SAymeric Wibo 
110*2ed98337SAymeric Wibo 	return;
111*2ed98337SAymeric Wibo }
112*2ed98337SAymeric Wibo 
113*2ed98337SAymeric Wibo SYSINIT(tbdev_init, SI_SUB_KICK_SCHEDULER, SI_ORDER_FIRST, tbdev_init, NULL);
114*2ed98337SAymeric Wibo 
115*2ed98337SAymeric Wibo static void
tbdev_uninit(void * arg)116*2ed98337SAymeric Wibo tbdev_uninit(void *arg)
117*2ed98337SAymeric Wibo {
118*2ed98337SAymeric Wibo 	if (tb_dev != NULL) {
119*2ed98337SAymeric Wibo 		destroy_dev(tb_dev);
120*2ed98337SAymeric Wibo 		tb_dev = NULL;
121*2ed98337SAymeric Wibo 	}
122*2ed98337SAymeric Wibo }
123*2ed98337SAymeric Wibo 
124*2ed98337SAymeric Wibo SYSUNINIT(tbdev_uninit, SI_SUB_KICK_SCHEDULER, SI_ORDER_ANY, tbdev_uninit, NULL);
125*2ed98337SAymeric Wibo 
126*2ed98337SAymeric Wibo int
tbdev_add_interface(struct nhi_softc * nhi)127*2ed98337SAymeric Wibo tbdev_add_interface(struct nhi_softc *nhi)
128*2ed98337SAymeric Wibo {
129*2ed98337SAymeric Wibo 	struct tbdev_if *ifce;
130*2ed98337SAymeric Wibo 
131*2ed98337SAymeric Wibo 	ifce = malloc(sizeof(struct tbdev_if), M_THUNDERBOLT, M_ZERO|M_NOWAIT);
132*2ed98337SAymeric Wibo 	if (ifce == NULL)
133*2ed98337SAymeric Wibo 		return (ENOMEM);
134*2ed98337SAymeric Wibo 
135*2ed98337SAymeric Wibo 	strlcpy(ifce->name, device_get_nameunit(nhi->dev), SPECNAMELEN);
136*2ed98337SAymeric Wibo 	mtx_lock(&tbdev_mtx);
137*2ed98337SAymeric Wibo 	TAILQ_INSERT_TAIL(&tbdev_head, ifce, dev_next);
138*2ed98337SAymeric Wibo 	mtx_unlock(&tbdev_mtx);
139*2ed98337SAymeric Wibo 
140*2ed98337SAymeric Wibo 	return (0);
141*2ed98337SAymeric Wibo }
142*2ed98337SAymeric Wibo 
143*2ed98337SAymeric Wibo int
tbdev_remove_interface(struct nhi_softc * nhi)144*2ed98337SAymeric Wibo tbdev_remove_interface(struct nhi_softc *nhi)
145*2ed98337SAymeric Wibo {
146*2ed98337SAymeric Wibo 	struct tbdev_if *ifce = NULL, *if_back;
147*2ed98337SAymeric Wibo 	const char *name;
148*2ed98337SAymeric Wibo 
149*2ed98337SAymeric Wibo 	name = device_get_nameunit(nhi->dev);
150*2ed98337SAymeric Wibo 	mtx_lock(&tbdev_mtx);
151*2ed98337SAymeric Wibo 	TAILQ_FOREACH_SAFE(ifce, &tbdev_head, dev_next, if_back) {
152*2ed98337SAymeric Wibo 		if (strncmp(name, ifce->name, SPECNAMELEN) == 0) {
153*2ed98337SAymeric Wibo 			TAILQ_REMOVE(&tbdev_head, ifce, dev_next);
154*2ed98337SAymeric Wibo 			break;
155*2ed98337SAymeric Wibo 		}
156*2ed98337SAymeric Wibo 	}
157*2ed98337SAymeric Wibo 	mtx_unlock(&tbdev_mtx);
158*2ed98337SAymeric Wibo 
159*2ed98337SAymeric Wibo 	if (ifce != NULL)
160*2ed98337SAymeric Wibo 		free(ifce, M_THUNDERBOLT);
161*2ed98337SAymeric Wibo 
162*2ed98337SAymeric Wibo 	return (0);
163*2ed98337SAymeric Wibo }
164*2ed98337SAymeric Wibo 
165*2ed98337SAymeric Wibo int
tbdev_add_domain(void * domain)166*2ed98337SAymeric Wibo tbdev_add_domain(void *domain)
167*2ed98337SAymeric Wibo {
168*2ed98337SAymeric Wibo 
169*2ed98337SAymeric Wibo 	return (0);
170*2ed98337SAymeric Wibo }
171*2ed98337SAymeric Wibo 
172*2ed98337SAymeric Wibo int
tbdev_remove_domain(void * domain)173*2ed98337SAymeric Wibo tbdev_remove_domain(void *domain)
174*2ed98337SAymeric Wibo {
175*2ed98337SAymeric Wibo 
176*2ed98337SAymeric Wibo 	return (0);
177*2ed98337SAymeric Wibo }
178*2ed98337SAymeric Wibo 
179*2ed98337SAymeric Wibo int
tbdev_add_router(struct router_softc * rt)180*2ed98337SAymeric Wibo tbdev_add_router(struct router_softc *rt)
181*2ed98337SAymeric Wibo {
182*2ed98337SAymeric Wibo 
183*2ed98337SAymeric Wibo 	return (0);
184*2ed98337SAymeric Wibo }
185*2ed98337SAymeric Wibo 
186*2ed98337SAymeric Wibo int
tbdev_remove_router(struct router_softc * rt)187*2ed98337SAymeric Wibo tbdev_remove_router(struct router_softc *rt)
188*2ed98337SAymeric Wibo {
189*2ed98337SAymeric Wibo 
190*2ed98337SAymeric Wibo 	return (0);
191*2ed98337SAymeric Wibo }
192*2ed98337SAymeric Wibo 
193*2ed98337SAymeric Wibo static int
tbdev_discover(caddr_t addr)194*2ed98337SAymeric Wibo tbdev_discover(caddr_t addr)
195*2ed98337SAymeric Wibo {
196*2ed98337SAymeric Wibo 	nvlist_t	*nvl = NULL;
197*2ed98337SAymeric Wibo 	struct tbt_ioc	*ioc = (struct tbt_ioc *)addr;
198*2ed98337SAymeric Wibo 	struct tbdev_if *dev;
199*2ed98337SAymeric Wibo 	struct tbdev_dm	*dm;
200*2ed98337SAymeric Wibo 	struct tbdev_rt	*rt;
201*2ed98337SAymeric Wibo 	void		*nvlpacked = NULL;
202*2ed98337SAymeric Wibo 	const char	*cmd = NULL;
203*2ed98337SAymeric Wibo 	int		error = 0;
204*2ed98337SAymeric Wibo 
205*2ed98337SAymeric Wibo 	if ((ioc->data == NULL) || (ioc->size == 0)) {
206*2ed98337SAymeric Wibo 		printf("data or size is 0\n");
207*2ed98337SAymeric Wibo 		return (EINVAL);
208*2ed98337SAymeric Wibo 	}
209*2ed98337SAymeric Wibo 
210*2ed98337SAymeric Wibo 	if ((ioc->len == 0) || (ioc->len > TBT_IOCMAXLEN) ||
211*2ed98337SAymeric Wibo 	    (ioc->len > ioc->size)) {
212*2ed98337SAymeric Wibo 		printf("len is wrong\n");
213*2ed98337SAymeric Wibo 		return (EINVAL);
214*2ed98337SAymeric Wibo 	}
215*2ed98337SAymeric Wibo 
216*2ed98337SAymeric Wibo 	nvlpacked = malloc(ioc->len, M_THUNDERBOLT, M_NOWAIT);
217*2ed98337SAymeric Wibo 	if (nvlpacked == NULL) {
218*2ed98337SAymeric Wibo 		printf("cannot allocate nvlpacked\n");
219*2ed98337SAymeric Wibo 		return (ENOMEM);
220*2ed98337SAymeric Wibo 	}
221*2ed98337SAymeric Wibo 
222*2ed98337SAymeric Wibo 	error = copyin(ioc->data, nvlpacked, ioc->len);
223*2ed98337SAymeric Wibo 	if (error) {
224*2ed98337SAymeric Wibo 		free(nvlpacked, M_THUNDERBOLT);
225*2ed98337SAymeric Wibo 		printf("error %d from copyin\n", error);
226*2ed98337SAymeric Wibo 		return (error);
227*2ed98337SAymeric Wibo 	}
228*2ed98337SAymeric Wibo 
229*2ed98337SAymeric Wibo 	nvl = nvlist_unpack(nvlpacked, ioc->len, NV_FLAG_NO_UNIQUE);
230*2ed98337SAymeric Wibo 	if (nvl == NULL) {
231*2ed98337SAymeric Wibo 		free(nvlpacked, M_THUNDERBOLT);
232*2ed98337SAymeric Wibo 		printf("cannot unpack nvlist\n");
233*2ed98337SAymeric Wibo 		return (EINVAL);
234*2ed98337SAymeric Wibo 	}
235*2ed98337SAymeric Wibo 	free(nvlpacked, M_THUNDERBOLT);
236*2ed98337SAymeric Wibo 	nvlpacked = NULL;
237*2ed98337SAymeric Wibo 
238*2ed98337SAymeric Wibo 	if (nvlist_exists_string(nvl, TBT_DISCOVER_TYPE))
239*2ed98337SAymeric Wibo 		cmd = nvlist_get_string(nvl, TBT_DISCOVER_TYPE);
240*2ed98337SAymeric Wibo 	if (cmd == NULL) {
241*2ed98337SAymeric Wibo 		printf("cannot find type string\n");
242*2ed98337SAymeric Wibo 		error = EINVAL;
243*2ed98337SAymeric Wibo 		goto out;
244*2ed98337SAymeric Wibo 	}
245*2ed98337SAymeric Wibo 
246*2ed98337SAymeric Wibo 	mtx_lock(&tbdev_mtx);
247*2ed98337SAymeric Wibo 	if (strncmp(cmd, TBT_DISCOVER_IFACE, TBT_NAMLEN) == 0) {
248*2ed98337SAymeric Wibo 		TAILQ_FOREACH(dev, &tbdev_head, dev_next)
249*2ed98337SAymeric Wibo 			nvlist_add_string(nvl, TBT_DISCOVER_IFACE, dev->name);
250*2ed98337SAymeric Wibo 	} else if (strncmp(cmd, TBT_DISCOVER_DOMAIN, TBT_NAMLEN) == 0) {
251*2ed98337SAymeric Wibo 		TAILQ_FOREACH(dm, &tbdomain_head, dev_next)
252*2ed98337SAymeric Wibo 			nvlist_add_string(nvl, TBT_DISCOVER_DOMAIN, dm->uid);
253*2ed98337SAymeric Wibo 	} else if (strncmp(cmd, TBT_DISCOVER_ROUTER, TBT_NAMLEN) == 0) {
254*2ed98337SAymeric Wibo 		TAILQ_FOREACH(rt, &tbrouter_head, dev_next)
255*2ed98337SAymeric Wibo 			nvlist_add_number(nvl, TBT_DISCOVER_ROUTER, rt->route);
256*2ed98337SAymeric Wibo 	} else {
257*2ed98337SAymeric Wibo 		printf("cannot find supported tpye\n");
258*2ed98337SAymeric Wibo 		error = EINVAL;
259*2ed98337SAymeric Wibo 		goto out;
260*2ed98337SAymeric Wibo 	}
261*2ed98337SAymeric Wibo 	mtx_unlock(&tbdev_mtx);
262*2ed98337SAymeric Wibo 
263*2ed98337SAymeric Wibo 	error = nvlist_error(nvl);
264*2ed98337SAymeric Wibo 	if (error != 0) {
265*2ed98337SAymeric Wibo 		printf("error %d state in nvlist\n", error);
266*2ed98337SAymeric Wibo 		return (error);
267*2ed98337SAymeric Wibo 	}
268*2ed98337SAymeric Wibo 
269*2ed98337SAymeric Wibo 	nvlpacked = nvlist_pack(nvl, &ioc->len);
270*2ed98337SAymeric Wibo 	if (nvlpacked == NULL) {
271*2ed98337SAymeric Wibo 		printf("cannot allocate new packed buffer\n");
272*2ed98337SAymeric Wibo 		return (ENOMEM);
273*2ed98337SAymeric Wibo 	}
274*2ed98337SAymeric Wibo 	if (ioc->size < ioc->len) {
275*2ed98337SAymeric Wibo 		printf("packed buffer is too big to copyout\n");
276*2ed98337SAymeric Wibo 		return (ENOSPC);
277*2ed98337SAymeric Wibo 	}
278*2ed98337SAymeric Wibo 
279*2ed98337SAymeric Wibo 	error = copyout(nvlpacked, ioc->data, ioc->len);
280*2ed98337SAymeric Wibo 	if (error)
281*2ed98337SAymeric Wibo 		printf("error %d on copyout\n", error);
282*2ed98337SAymeric Wibo 
283*2ed98337SAymeric Wibo out:
284*2ed98337SAymeric Wibo 	if (nvlpacked != NULL)
285*2ed98337SAymeric Wibo 		free(nvlpacked, M_NVLIST);
286*2ed98337SAymeric Wibo 	if (nvl != NULL)
287*2ed98337SAymeric Wibo 		nvlist_destroy(nvl);
288*2ed98337SAymeric Wibo 
289*2ed98337SAymeric Wibo 	return (error);
290*2ed98337SAymeric Wibo }
291*2ed98337SAymeric Wibo 
292*2ed98337SAymeric Wibo static int
tbdev_request(caddr_t addr)293*2ed98337SAymeric Wibo tbdev_request(caddr_t addr)
294*2ed98337SAymeric Wibo {
295*2ed98337SAymeric Wibo 	struct tbt_ioc	*ioc = (struct tbt_ioc *)addr;
296*2ed98337SAymeric Wibo 	nvlist_t	*nvl = NULL;
297*2ed98337SAymeric Wibo 	void		*nvlpacked = NULL;
298*2ed98337SAymeric Wibo 	int		error = 0;
299*2ed98337SAymeric Wibo 
300*2ed98337SAymeric Wibo 	if ((ioc->data == NULL) || (ioc->size == 0))
301*2ed98337SAymeric Wibo 		return (ENOMEM);
302*2ed98337SAymeric Wibo 
303*2ed98337SAymeric Wibo 	nvlpacked = nvlist_pack(nvl, &ioc->len);
304*2ed98337SAymeric Wibo 	if (nvlpacked == NULL)
305*2ed98337SAymeric Wibo 		return (ENOMEM);
306*2ed98337SAymeric Wibo 	if (ioc->size < ioc->len)
307*2ed98337SAymeric Wibo 		return (ENOSPC);
308*2ed98337SAymeric Wibo 
309*2ed98337SAymeric Wibo 	error = copyout(nvlpacked, ioc->data, ioc->len);
310*2ed98337SAymeric Wibo 	return (error);
311*2ed98337SAymeric Wibo }
312*2ed98337SAymeric Wibo 
313*2ed98337SAymeric Wibo static int
tbdev_static_ioctl(struct cdev * dev,u_long cmd,caddr_t addr,int flags,struct thread * td)314*2ed98337SAymeric Wibo tbdev_static_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags,
315*2ed98337SAymeric Wibo     struct thread *td)
316*2ed98337SAymeric Wibo {
317*2ed98337SAymeric Wibo 	int error = 0;
318*2ed98337SAymeric Wibo 
319*2ed98337SAymeric Wibo 	switch (cmd) {
320*2ed98337SAymeric Wibo 	case TBT_DISCOVER:
321*2ed98337SAymeric Wibo 		error = tbdev_discover(addr);
322*2ed98337SAymeric Wibo 		break;
323*2ed98337SAymeric Wibo 	case TBT_REQUEST:
324*2ed98337SAymeric Wibo 		error = tbdev_request(addr);
325*2ed98337SAymeric Wibo 		break;
326*2ed98337SAymeric Wibo 	default:
327*2ed98337SAymeric Wibo 		error = EINVAL;
328*2ed98337SAymeric Wibo 	}
329*2ed98337SAymeric Wibo 
330*2ed98337SAymeric Wibo 	return (error);
331*2ed98337SAymeric Wibo }
332