Bug Summary

File:dev/wscons/wsmux.c
Warning:line 842, column 2
Value stored to 'odisplaydv' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.4 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name wsmux.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=all -relaxed-aliasing -ffp-contract=on -fno-rounding-math -mconstructor-aliases -ffreestanding -mcmodel=kernel -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -target-feature -sse2 -target-feature -sse -target-feature -3dnow -target-feature -mmx -target-feature +save-args -target-feature +retpoline-external-thunk -disable-red-zone -no-implicit-float -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -nostdsysteminc -nobuiltininc -resource-dir /usr/local/llvm16/lib/clang/16 -I /usr/src/sys -I /usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -I /usr/src/sys/arch -I /usr/src/sys/dev/pci/drm/include -I /usr/src/sys/dev/pci/drm/include/uapi -I /usr/src/sys/dev/pci/drm/amd/include/asic_reg -I /usr/src/sys/dev/pci/drm/amd/include -I /usr/src/sys/dev/pci/drm/amd/amdgpu -I /usr/src/sys/dev/pci/drm/amd/display -I /usr/src/sys/dev/pci/drm/amd/display/include -I /usr/src/sys/dev/pci/drm/amd/display/dc -I /usr/src/sys/dev/pci/drm/amd/display/amdgpu_dm -I /usr/src/sys/dev/pci/drm/amd/pm/inc -I /usr/src/sys/dev/pci/drm/amd/pm/legacy-dpm -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/inc -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/smu11 -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/smu12 -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/smu13 -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/inc -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/hwmgr -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/smumgr -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/inc -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/inc/pmfw_if -I /usr/src/sys/dev/pci/drm/amd/display/dc/inc -I /usr/src/sys/dev/pci/drm/amd/display/dc/inc/hw -I /usr/src/sys/dev/pci/drm/amd/display/dc/clk_mgr -I /usr/src/sys/dev/pci/drm/amd/display/modules/inc -I /usr/src/sys/dev/pci/drm/amd/display/modules/hdcp -I /usr/src/sys/dev/pci/drm/amd/display/dmub/inc -I /usr/src/sys/dev/pci/drm/i915 -D DDB -D DIAGNOSTIC -D KTRACE -D ACCOUNTING -D KMEMSTATS -D PTRACE -D POOL_DEBUG -D CRYPTO -D SYSVMSG -D SYSVSEM -D SYSVSHM -D UVM_SWAP_ENCRYPT -D FFS -D FFS2 -D FFS_SOFTUPDATES -D UFS_DIRHASH -D QUOTA -D EXT2FS -D MFS -D NFSCLIENT -D NFSSERVER -D CD9660 -D UDF -D MSDOSFS -D FIFO -D FUSE -D SOCKET_SPLICE -D TCP_ECN -D TCP_SIGNATURE -D INET6 -D IPSEC -D PPP_BSDCOMP -D PPP_DEFLATE -D PIPEX -D MROUTING -D MPLS -D BOOT_CONFIG -D USER_PCICONF -D APERTURE -D MTRR -D NTFS -D SUSPEND -D HIBERNATE -D PCIVERBOSE -D USBVERBOSE -D WSDISPLAY_COMPAT_USL -D WSDISPLAY_COMPAT_RAWKBD -D WSDISPLAY_DEFAULTSCREENS=6 -D X86EMU -D ONEWIREVERBOSE -D MULTIPROCESSOR -D MAXUSERS=80 -D _KERNEL -O2 -Wno-pointer-sign -Wno-address-of-packed-member -Wno-constant-conversion -Wno-unused-but-set-variable -Wno-gnu-folding-constant -fdebug-compilation-dir=/usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fcf-protection=branch -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -o /home/ben/Projects/scan/2024-01-11-110808-61670-1 -x c /usr/src/sys/dev/wscons/wsmux.c
1/* $OpenBSD: wsmux.c,v 1.56 2022/07/02 08:50:42 visa Exp $ */
2/* $NetBSD: wsmux.c,v 1.37 2005/04/30 03:47:12 augustss Exp $ */
3
4/*
5 * Copyright (c) 1998, 2005 The NetBSD Foundation, Inc.
6 * All rights reserved.
7 *
8 * Author: Lennart Augustsson <augustss@carlstedt.se>
9 * Carlstedt Research & Technology
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33#include "wsmux.h"
34#include "wsdisplay.h"
35#include "wskbd.h"
36#include "wsmouse.h"
37
38/*
39 * wscons mux device.
40 *
41 * The mux device is a collection of real mice and keyboards and acts as
42 * a merge point for all the events from the different real devices.
43 */
44
45#include <sys/param.h>
46#include <sys/conf.h>
47#include <sys/ioctl.h>
48#include <sys/fcntl.h>
49#include <sys/kernel.h>
50#include <sys/malloc.h>
51#include <sys/proc.h>
52#include <sys/queue.h>
53#include <sys/syslog.h>
54#include <sys/systm.h>
55#include <sys/tty.h>
56#include <sys/signalvar.h>
57#include <sys/device.h>
58
59#include <dev/wscons/wsconsio.h>
60#include <dev/wscons/wsksymdef.h>
61#include <dev/wscons/wseventvar.h>
62#include <dev/wscons/wsmuxvar.h>
63
64#define WSMUX_MAXDEPTH8 8
65
66#ifdef WSMUX_DEBUG
67#define DPRINTF(x) if (wsmuxdebug) printf x
68#define DPRINTFN(n,x) if (wsmuxdebug > (n)) printf x
69int wsmuxdebug = 0;
70#else
71#define DPRINTF(x)
72#define DPRINTFN(n,x)
73#endif
74
75/*
76 * The wsmux pseudo device is used to multiplex events from several wsmouse,
77 * wskbd, and/or wsmux devices together.
78 * The devices connected together form a tree with muxes in the interior
79 * and real devices (mouse and kbd) at the leaves. The special case of
80 * a tree with one node (mux or other) is supported as well.
81 * Only the device at the root of the tree can be opened (if a non-root
82 * device is opened the subtree rooted at that point is severed from the
83 * containing tree). When the root is opened it allocates a wseventvar
84 * struct which all the nodes in the tree will send their events too.
85 * An ioctl() performed on the root is propagated to all the nodes.
86 * There are also ioctl() operations to add and remove nodes from a tree.
87 */
88
89int wsmux_mux_open(struct wsevsrc *, struct wseventvar *);
90int wsmux_mux_close(struct wsevsrc *);
91
92int wsmux_do_open(struct wsmux_softc *, struct wseventvar *);
93
94void wsmux_do_close(struct wsmux_softc *);
95#if NWSDISPLAY1 > 0
96int wsmux_evsrc_set_display(struct device *, struct device *);
97#else
98#define wsmux_evsrc_set_display NULL((void *)0)
99#endif
100
101int wsmux_do_displayioctl(struct device *dev, u_long cmd, caddr_t data,
102 int flag, struct proc *p);
103int wsmux_do_ioctl(struct device *, u_long, caddr_t,int,struct proc *);
104
105int wsmux_add_mux(int, struct wsmux_softc *);
106
107int wsmux_depth(struct wsmux_softc *);
108
109void wsmuxattach(int);
110
111void wsmux_detach_sc_locked(struct wsmux_softc *, struct wsevsrc *);
112
113struct wssrcops wsmux_srcops = {
114 .type = WSMUX_MUX3,
115 .dopen = wsmux_mux_open,
116 .dclose = wsmux_mux_close,
117 .dioctl = wsmux_do_ioctl,
118 .ddispioctl = wsmux_do_displayioctl,
119 .dsetdisplay = wsmux_evsrc_set_display,
120};
121
122/*
123 * Lock used by wsmux_add_mux() to grant exclusive access to the tree of
124 * stacked wsmux devices.
125 */
126struct rwlock wsmux_tree_lock = RWLOCK_INITIALIZER("wsmuxtreelk"){ 0, "wsmuxtreelk" };
127
128/* From upper level */
129void
130wsmuxattach(int n)
131{
132}
133
134/* Keep track of all muxes that have been allocated */
135int nwsmux = 0;
136struct wsmux_softc **wsmuxdevs = NULL((void *)0);
137
138/* Return mux n, create if necessary */
139struct wsmux_softc *
140wsmux_getmux(int n)
141{
142 struct wsmux_softc *sc;
143 struct wsmux_softc **new, **old;
144 int i;
145
146 if (n >= WSMUX_MAXDEV32)
147 return (NULL((void *)0));
148
149 /* Make sure there is room for mux n in the table */
150 if (n >= nwsmux) {
151 old = wsmuxdevs;
152 new = mallocarray(n + 1, sizeof (*wsmuxdevs),
153 M_DEVBUF2, M_NOWAIT0x0002);
154 if (new == NULL((void *)0)) {
155 printf("wsmux_getmux: no memory for mux %d\n", n);
156 return (NULL((void *)0));
157 }
158 if (old != NULL((void *)0))
159 bcopy(old, new, nwsmux * sizeof(*wsmuxdevs));
160 for (i = nwsmux; i < (n + 1); i++)
161 new[i] = NULL((void *)0);
162 if (old != NULL((void *)0))
163 free(old, M_DEVBUF2, nwsmux * sizeof(*wsmuxdevs));
164 wsmuxdevs = new;
165 nwsmux = n + 1;
166 }
167
168 sc = wsmuxdevs[n];
169 if (sc == NULL((void *)0)) {
170 sc = wsmux_create("wsmux", n);
171 if (sc == NULL((void *)0))
172 printf("wsmux: attach out of memory\n");
173 wsmuxdevs[n] = sc;
174 }
175 return (sc);
176}
177
178/*
179 * open() of the pseudo device from device table.
180 */
181int
182wsmuxopen(dev_t dev, int flags, int mode, struct proc *p)
183{
184 struct wsmux_softc *sc;
185 struct wseventvar *evar;
186 int error, unit;
187
188 unit = minor(dev)((unsigned)((dev) & 0xff) | (((dev) & 0xffff0000) >>
8))
;
189 sc = wsmux_getmux(unit);
190 if (sc == NULL((void *)0))
191 return (ENXIO6);
192
193 DPRINTF(("%s: %s: sc=%p\n", __func__, sc->sc_base.me_dv.dv_xname, sc));
194
195 if ((flags & (FREAD0x0001 | FWRITE0x0002)) == FWRITE0x0002) {
196 /* Not opening for read, only ioctl is available. */
197 return (0);
198 }
199
200 if (sc->sc_base.me_parent != NULL((void *)0)) {
201 /* Grab the mux out of the greedy hands of the parent mux. */
202 DPRINTF(("%s: detach\n", __func__));
203 wsmux_detach_sc(&sc->sc_base);
204 }
205
206 if (sc->sc_base.me_evp != NULL((void *)0))
207 /* Already open. */
208 return (EBUSY16);
209
210 evar = &sc->sc_base.me_evar;
211 if (wsevent_init(evar))
212 return (EBUSY16);
213#ifdef WSDISPLAY_COMPAT_RAWKBD1
214 sc->sc_rawkbd = 0;
215#endif
216
217 error = wsmux_do_open(sc, evar);
218 if (error)
219 wsevent_fini(evar);
220 return (error);
221}
222
223/*
224 * Open of a mux via the parent mux.
225 */
226int
227wsmux_mux_open(struct wsevsrc *me, struct wseventvar *evar)
228{
229 struct wsmux_softc *sc = (struct wsmux_softc *)me;
230
231#ifdef DIAGNOSTIC1
232 if (sc->sc_base.me_parent == NULL((void *)0)) {
233 printf("wsmux_mux_open: no parent\n");
234 return (EINVAL22);
235 }
236#endif
237
238 return (wsmux_do_open(sc, evar));
239}
240
241/* Common part of opening a mux. */
242int
243wsmux_do_open(struct wsmux_softc *sc, struct wseventvar *evar)
244{
245 struct wsevsrc *me;
246#ifdef DIAGNOSTIC1
247 int error;
248#endif
249
250 /* The device could already be attached to a mux. */
251 if (sc->sc_base.me_evp != NULL((void *)0))
252 return (EBUSY16);
253 sc->sc_base.me_evp = evar; /* remember event variable, mark as open */
254
255 /* Open all children. */
256 rw_enter_read(&sc->sc_lock);
257 TAILQ_FOREACH(me, &sc->sc_cld, me_next)for((me) = ((&sc->sc_cld)->tqh_first); (me) != ((void
*)0); (me) = ((me)->me_next.tqe_next))
{
258 DPRINTF(("%s: %s: m=%p dev=%s\n", __func__,
259 sc->sc_base.me_dv.dv_xname, me,
260 me->me_dv.dv_xname));
261#ifdef DIAGNOSTIC1
262 if (me->me_evp != NULL((void *)0)) {
263 printf("wsmuxopen: dev already in use\n");
264 continue;
265 }
266 if (me->me_parent != sc) {
267 printf("wsmux_do_open: bad child=%p\n", me);
268 continue;
269 }
270 error = wsevsrc_open(me, evar)((me)->me_ops->dopen((me), evar));
271 if (error) {
272 DPRINTF(("%s: open failed %d\n", __func__, error));
273 }
274#else
275 /* ignore errors, failing children will not be marked open */
276 (void)wsevsrc_open(me, evar)((me)->me_ops->dopen((me), evar));
277#endif
278 }
279 rw_exit_read(&sc->sc_lock);
280
281 return (0);
282}
283
284/*
285 * close() of the pseudo device from device table.
286 */
287int
288wsmuxclose(dev_t dev, int flags, int mode, struct proc *p)
289{
290 struct wsmux_softc *sc =
291 (struct wsmux_softc *)wsmuxdevs[minor(dev)((unsigned)((dev) & 0xff) | (((dev) & 0xffff0000) >>
8))
];
292 struct wseventvar *evar = sc->sc_base.me_evp;
293
294 if ((flags & (FREAD0x0001 | FWRITE0x0002)) == FWRITE0x0002)
295 /* Not open for read */
296 return (0);
297
298 wsmux_do_close(sc);
299 sc->sc_base.me_evp = NULL((void *)0);
300 wsevent_fini(evar);
301 return (0);
302}
303
304/*
305 * Close of a mux via the parent mux.
306 */
307int
308wsmux_mux_close(struct wsevsrc *me)
309{
310 struct wsmux_softc *sc = (struct wsmux_softc *)me;
311
312 wsmux_do_close(sc);
313 sc->sc_base.me_evp = NULL((void *)0);
314
315 return (0);
316}
317
318/* Common part of closing a mux. */
319void
320wsmux_do_close(struct wsmux_softc *sc)
321{
322 struct wsevsrc *me;
323
324 DPRINTF(("%s: %s: sc=%p\n", __func__, sc->sc_base.me_dv.dv_xname, sc));
325
326 /* Close all the children. */
327 rw_enter_read(&sc->sc_lock);
328 TAILQ_FOREACH(me, &sc->sc_cld, me_next)for((me) = ((&sc->sc_cld)->tqh_first); (me) != ((void
*)0); (me) = ((me)->me_next.tqe_next))
{
329 DPRINTF(("%s %s: m=%p dev=%s\n", __func__,
330 sc->sc_base.me_dv.dv_xname, me, me->me_dv.dv_xname));
331#ifdef DIAGNOSTIC1
332 if (me->me_parent != sc) {
333 printf("wsmuxclose: bad child=%p\n", me);
334 continue;
335 }
336#endif
337 (void)wsevsrc_close(me)((me)->me_ops->dclose((me)));
338 }
339 rw_exit_read(&sc->sc_lock);
340}
341
342/*
343 * read() of the pseudo device from device table.
344 */
345int
346wsmuxread(dev_t dev, struct uio *uio, int flags)
347{
348 struct wsmux_softc *sc = wsmuxdevs[minor(dev)((unsigned)((dev) & 0xff) | (((dev) & 0xffff0000) >>
8))
];
349 struct wseventvar *evar;
350 int error;
351
352 evar = sc->sc_base.me_evp;
353 if (evar == NULL((void *)0)) {
354#ifdef DIAGNOSTIC1
355 /* XXX can we get here? */
356 printf("wsmuxread: not open\n");
357#endif
358 return (EINVAL22);
359 }
360
361 DPRINTFN(5, ("%s: %s event read evar=%p\n", __func__,
362 sc->sc_base.me_dv.dv_xname, evar));
363 error = wsevent_read(evar, uio, flags);
364 DPRINTFN(5, ("%s: %s event read ==> error=%d\n", __func__,
365 sc->sc_base.me_dv.dv_xname, error));
366 return (error);
367}
368
369/*
370 * ioctl of the pseudo device from device table.
371 */
372int
373wsmuxioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
374{
375 return wsmux_do_ioctl(&wsmuxdevs[minor(dev)((unsigned)((dev) & 0xff) | (((dev) & 0xffff0000) >>
8))
]->sc_base.me_dv, cmd, data, flag, p);
376}
377
378/*
379 * ioctl of a mux via the parent mux, continuation of wsmuxioctl().
380 */
381int
382wsmux_do_ioctl(struct device *dv, u_long cmd, caddr_t data, int flag,
383 struct proc *p)
384{
385 struct wsmux_softc *sc = (struct wsmux_softc *)dv;
386 struct wsevsrc *me;
387 int error, ok;
388 int s, put, get, n;
389 struct wseventvar *evar;
390 struct wscons_event *ev;
391 struct wsmux_device_list *l;
392
393 DPRINTF(("%s: %s: enter sc=%p, cmd=%08lx\n", __func__,
394 sc->sc_base.me_dv.dv_xname, sc, cmd));
395
396 switch (cmd) {
397 case WSMUXIO_INJECTEVENT((unsigned long)0x80000000 | ((sizeof(struct wscons_event) &
0x1fff) << 16) | ((('W')) << 8) | ((96)))
:
398 case WSMUXIO_ADD_DEVICE((unsigned long)0x80000000 | ((sizeof(struct wsmux_device) &
0x1fff) << 16) | ((('W')) << 8) | ((97)))
:
399 case WSMUXIO_REMOVE_DEVICE((unsigned long)0x80000000 | ((sizeof(struct wsmux_device) &
0x1fff) << 16) | ((('W')) << 8) | ((98)))
:
400#ifdef WSDISPLAY_COMPAT_RAWKBD1
401 case WSKBDIO_SETMODE((unsigned long)0x80000000 | ((sizeof(int) & 0x1fff) <<
16) | ((('W')) << 8) | ((19)))
:
402#endif
403 if ((flag & FWRITE0x0002) == 0)
404 return (EACCES13);
405 }
406
407 switch (cmd) {
408 case WSMUXIO_INJECTEVENT((unsigned long)0x80000000 | ((sizeof(struct wscons_event) &
0x1fff) << 16) | ((('W')) << 8) | ((96)))
:
409 /* Inject an event, e.g., from moused. */
410 DPRINTF(("%s: inject\n", sc->sc_base.me_dv.dv_xname));
411 evar = sc->sc_base.me_evp;
412 if (evar == NULL((void *)0)) {
413 /* No event sink, so ignore it. */
414 DPRINTF(("%s: event ignored\n", __func__));
415 return (0);
416 }
417
418 s = spltty()splraise(0x9);
419 get = evar->get;
420 put = evar->put;
421 ev = &evar->q[put];
422 if (++put % WSEVENT_QSIZE256 == get) {
423 put--;
424 splx(s)spllower(s);
425 return (ENOSPC28);
426 }
427 if (put >= WSEVENT_QSIZE256)
428 put = 0;
429 *ev = *(struct wscons_event *)data;
430 nanotime(&ev->time);
431 evar->put = put;
432 WSEVENT_WAKEUP(evar){ selwakeup(&(evar)->sel); if ((evar)->wanted) { (evar
)->wanted = 0; wakeup((caddr_t)(evar)); } if ((evar)->async
) pgsigio(&(evar)->sigio, 23, 0); }
;
433 splx(s)spllower(s);
434 return (0);
435 case WSMUXIO_ADD_DEVICE((unsigned long)0x80000000 | ((sizeof(struct wsmux_device) &
0x1fff) << 16) | ((('W')) << 8) | ((97)))
:
436#define d ((struct wsmux_device *)data)
437 DPRINTF(("%s: add type=%d, no=%d\n", sc->sc_base.me_dv.dv_xname,
438 d->type, d->idx));
439 if (d->idx < 0)
440 return (ENXIO6);
441 switch (d->type) {
442#if NWSMOUSE1 > 0
443 case WSMUX_MOUSE1:
444 return (wsmouse_add_mux(d->idx, sc));
445#endif
446#if NWSKBD1 > 0
447 case WSMUX_KBD2:
448 return (wskbd_add_mux(d->idx, sc));
449#endif
450 case WSMUX_MUX3:
451 return (wsmux_add_mux(d->idx, sc));
452 default:
453 return (EINVAL22);
454 }
455 case WSMUXIO_REMOVE_DEVICE((unsigned long)0x80000000 | ((sizeof(struct wsmux_device) &
0x1fff) << 16) | ((('W')) << 8) | ((98)))
:
456 DPRINTF(("%s: rem type=%d, no=%d\n", sc->sc_base.me_dv.dv_xname,
457 d->type, d->idx));
458 /* Locate the device */
459 rw_enter_write(&sc->sc_lock);
460 TAILQ_FOREACH(me, &sc->sc_cld, me_next)for((me) = ((&sc->sc_cld)->tqh_first); (me) != ((void
*)0); (me) = ((me)->me_next.tqe_next))
{
461 if (me->me_ops->type == d->type &&
462 me->me_dv.dv_unit == d->idx) {
463 DPRINTF(("%s: detach\n", __func__));
464 wsmux_detach_sc_locked(sc, me);
465 rw_exit_write(&sc->sc_lock);
466 return (0);
467 }
468 }
469 rw_exit_write(&sc->sc_lock);
470 return (EINVAL22);
471#undef d
472
473 case WSMUXIO_LIST_DEVICES(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof
(struct wsmux_device_list) & 0x1fff) << 16) | ((('W'
)) << 8) | ((99)))
:
474 DPRINTF(("%s: list\n", sc->sc_base.me_dv.dv_xname));
475 l = (struct wsmux_device_list *)data;
476 n = 0;
477 rw_enter_read(&sc->sc_lock);
478 TAILQ_FOREACH(me, &sc->sc_cld, me_next)for((me) = ((&sc->sc_cld)->tqh_first); (me) != ((void
*)0); (me) = ((me)->me_next.tqe_next))
{
479 if (n >= WSMUX_MAXDEV32)
480 break;
481 l->devices[n].type = me->me_ops->type;
482 l->devices[n].idx = me->me_dv.dv_unit;
483 n++;
484 }
485 rw_exit_read(&sc->sc_lock);
486 l->ndevices = n;
487 return (0);
488#ifdef WSDISPLAY_COMPAT_RAWKBD1
489 case WSKBDIO_SETMODE((unsigned long)0x80000000 | ((sizeof(int) & 0x1fff) <<
16) | ((('W')) << 8) | ((19)))
:
490 sc->sc_rawkbd = *(int *)data;
491 DPRINTF(("%s: save rawkbd = %d\n", __func__, sc->sc_rawkbd));
492 break;
493#endif
494 case FIONBIO((unsigned long)0x80000000 | ((sizeof(int) & 0x1fff) <<
16) | ((('f')) << 8) | ((126)))
:
495 DPRINTF(("%s: FIONBIO\n", sc->sc_base.me_dv.dv_xname));
496 return (0);
497
498 case FIOASYNC((unsigned long)0x80000000 | ((sizeof(int) & 0x1fff) <<
16) | ((('f')) << 8) | ((125)))
:
499 DPRINTF(("%s: FIOASYNC\n", sc->sc_base.me_dv.dv_xname));
500 evar = sc->sc_base.me_evp;
501 if (evar == NULL((void *)0))
502 return (EINVAL22);
503 evar->async = *(int *)data != 0;
504 return (0);
505 case FIOGETOWN((unsigned long)0x40000000 | ((sizeof(int) & 0x1fff) <<
16) | ((('f')) << 8) | ((123)))
:
506 case TIOCGPGRP((unsigned long)0x40000000 | ((sizeof(int) & 0x1fff) <<
16) | ((('t')) << 8) | ((119)))
:
507 DPRINTF(("%s: getown (%lu)\n", sc->sc_base.me_dv.dv_xname,
508 cmd));
509 evar = sc->sc_base.me_evp;
510 if (evar == NULL((void *)0))
511 return (EINVAL22);
512 sigio_getown(&evar->sigio, cmd, data);
513 return (0);
514 case FIOSETOWN((unsigned long)0x80000000 | ((sizeof(int) & 0x1fff) <<
16) | ((('f')) << 8) | ((124)))
:
515 case TIOCSPGRP((unsigned long)0x80000000 | ((sizeof(int) & 0x1fff) <<
16) | ((('t')) << 8) | ((118)))
:
516 DPRINTF(("%s: setown (%lu)\n", sc->sc_base.me_dv.dv_xname,
517 cmd));
518 evar = sc->sc_base.me_evp;
519 if (evar == NULL((void *)0))
520 return (EINVAL22);
521 return (sigio_setown(&evar->sigio, cmd, data));
522 default:
523 DPRINTF(("%s: unknown\n", sc->sc_base.me_dv.dv_xname));
524 break;
525 }
526
527 if (sc->sc_base.me_evp == NULL((void *)0)
528#if NWSDISPLAY1 > 0
529 && sc->sc_displaydvsc_base.me_dispdv == NULL((void *)0)
530#endif
531 )
532 return (EACCES13);
533
534 /*
535 * If children are attached: return 0 if any of the ioctl() succeeds,
536 * otherwise the last error.
537 */
538 error = ENOTTY25;
539 ok = 0;
540 rw_enter_read(&sc->sc_lock);
541 TAILQ_FOREACH(me, &sc->sc_cld, me_next)for((me) = ((&sc->sc_cld)->tqh_first); (me) != ((void
*)0); (me) = ((me)->me_next.tqe_next))
{
542#ifdef DIAGNOSTIC1
543 /* XXX check evp? */
544 if (me->me_parent != sc) {
545 printf("wsmux_do_ioctl: bad child %p\n", me);
546 continue;
547 }
548#endif
549 error = wsevsrc_ioctl(me, cmd, data, flag, p)((me)->me_ops->dioctl(&(me)->me_dv, cmd, (caddr_t
)data, flag, p))
;
550 DPRINTF(("%s: %s: me=%p dev=%s ==> %d\n", __func__,
551 sc->sc_base.me_dv.dv_xname, me, me->me_dv.dv_xname,
552 error));
553 if (!error)
554 ok = 1;
555 }
556 rw_exit_read(&sc->sc_lock);
557 if (ok)
558 error = 0;
559
560 return (error);
561}
562
563int
564wsmuxkqfilter(dev_t dev, struct knote *kn)
565{
566 struct wsmux_softc *sc = wsmuxdevs[minor(dev)((unsigned)((dev) & 0xff) | (((dev) & 0xffff0000) >>
8))
];
567
568 if (sc->sc_base.me_evp == NULL((void *)0))
569 return (ENXIO6);
570 return (wsevent_kqfilter(sc->sc_base.me_evp, kn));
571}
572
573/*
574 * Add mux unit as a child to muxsc.
575 */
576int
577wsmux_add_mux(int unit, struct wsmux_softc *muxsc)
578{
579 struct wsmux_softc *sc, *m;
580 int error;
581 int depth = 0;
582
583 sc = wsmux_getmux(unit);
584 if (sc == NULL((void *)0))
585 return (ENXIO6);
586
587 rw_enter_write(&wsmux_tree_lock);
588
589 DPRINTF(("%s: %s(%p) to %s(%p)\n", __func__,
590 sc->sc_base.me_dv.dv_xname, sc,
591 muxsc->sc_base.me_dv.dv_xname, muxsc));
592
593 if (sc->sc_base.me_parent != NULL((void *)0) || sc->sc_base.me_evp != NULL((void *)0)) {
594 error = EBUSY16;
595 goto out;
596 }
597
598 /* The mux we are adding must not be an ancestor of itself. */
599 for (m = muxsc; m != NULL((void *)0); m = m->sc_base.me_parent) {
600 if (m == sc) {
601 error = EINVAL22;
602 goto out;
603 }
604 depth++;
605 }
606
607 /*
608 * Limit the number of stacked wsmux devices to avoid exhausting
609 * the kernel stack during wsmux_do_open().
610 */
611 if (depth + wsmux_depth(sc) > WSMUX_MAXDEPTH8) {
612 error = EBUSY16;
613 goto out;
614 }
615
616 error = wsmux_attach_sc(muxsc, &sc->sc_base);
617out:
618 rw_exit_write(&wsmux_tree_lock);
619 return (error);
620}
621
622/* Create a new mux softc. */
623struct wsmux_softc *
624wsmux_create(const char *name, int unit)
625{
626 struct wsmux_softc *sc;
627
628 DPRINTF(("%s: allocating\n", __func__));
629 sc = malloc(sizeof *sc, M_DEVBUF2, M_NOWAIT0x0002 | M_ZERO0x0008);
630 if (sc == NULL((void *)0))
631 return (NULL((void *)0));
632 TAILQ_INIT(&sc->sc_cld)do { (&sc->sc_cld)->tqh_first = ((void *)0); (&
sc->sc_cld)->tqh_last = &(&sc->sc_cld)->tqh_first
; } while (0)
;
633 rw_init_flags(&sc->sc_lock, "wsmuxlk", RWL_DUPOK)_rw_init_flags(&sc->sc_lock, "wsmuxlk", 0x01, ((void *
)0))
;
634 snprintf(sc->sc_base.me_dv.dv_xname, sizeof sc->sc_base.me_dv.dv_xname,
635 "%s%d", name, unit);
636 sc->sc_base.me_dv.dv_unit = unit;
637 sc->sc_base.me_ops = &wsmux_srcops;
638 sc->sc_kbd_layout = KB_NONE0x0000;
639 return (sc);
640}
641
642/* Attach me as a child to sc. */
643int
644wsmux_attach_sc(struct wsmux_softc *sc, struct wsevsrc *me)
645{
646 int error;
647
648 if (sc == NULL((void *)0))
649 return (EINVAL22);
650
651 rw_enter_write(&sc->sc_lock);
652
653 DPRINTF(("%s: %s(%p): type=%d\n", __func__,
654 sc->sc_base.me_dv.dv_xname, sc, me->me_ops->type));
655
656#ifdef DIAGNOSTIC1
657 if (me->me_parent != NULL((void *)0)) {
658 rw_exit_write(&sc->sc_lock);
659 printf("wsmux_attach_sc: busy\n");
660 return (EBUSY16);
661 }
662#endif
663 me->me_parent = sc;
664 TAILQ_INSERT_TAIL(&sc->sc_cld, me, me_next)do { (me)->me_next.tqe_next = ((void *)0); (me)->me_next
.tqe_prev = (&sc->sc_cld)->tqh_last; *(&sc->
sc_cld)->tqh_last = (me); (&sc->sc_cld)->tqh_last
= &(me)->me_next.tqe_next; } while (0)
;
665
666 error = 0;
667#if NWSDISPLAY1 > 0
668 if (sc->sc_displaydvsc_base.me_dispdv != NULL((void *)0)) {
669 /* This is a display mux, so attach the new device to it. */
670 DPRINTF(("%s: %s: set display %p\n", __func__,
671 sc->sc_base.me_dv.dv_xname, sc->sc_displaydv));
672 if (me->me_ops->dsetdisplay != NULL((void *)0)) {
673 error = wsevsrc_set_display(me, sc->sc_displaydv)((me)->me_ops->dsetdisplay(&(me)->me_dv, sc->
sc_base.me_dispdv))
;
674 /* Ignore that the console already has a display. */
675 if (error == EBUSY16)
676 error = 0;
677 if (!error) {
678#ifdef WSDISPLAY_COMPAT_RAWKBD1
679 DPRINTF(("%s: %s set rawkbd=%d\n", __func__,
680 me->me_dv.dv_xname, sc->sc_rawkbd));
681 (void)wsevsrc_ioctl(me, WSKBDIO_SETMODE,((me)->me_ops->dioctl(&(me)->me_dv, ((unsigned long
)0x80000000 | ((sizeof(int) & 0x1fff) << 16) | ((('W'
)) << 8) | ((19))), (caddr_t)&sc->sc_rawkbd, 0x0002
, 0))
682 &sc->sc_rawkbd, FWRITE, 0)((me)->me_ops->dioctl(&(me)->me_dv, ((unsigned long
)0x80000000 | ((sizeof(int) & 0x1fff) << 16) | ((('W'
)) << 8) | ((19))), (caddr_t)&sc->sc_rawkbd, 0x0002
, 0))
;
683#endif
684 }
685 }
686 }
687#endif
688 if (sc->sc_base.me_evp != NULL((void *)0)) {
689 /* Mux is open, try to open the subdevice. */
690 error = wsevsrc_open(me, sc->sc_base.me_evp)((me)->me_ops->dopen((me), sc->sc_base.me_evp));
691 } else {
692 /* Mux is closed, ensure that the subdevice is also closed. */
693 if (me->me_evp != NULL((void *)0))
694 error = EBUSY16;
695 }
696
697 if (error) {
698 me->me_parent = NULL((void *)0);
699 TAILQ_REMOVE(&sc->sc_cld, me, me_next)do { if (((me)->me_next.tqe_next) != ((void *)0)) (me)->
me_next.tqe_next->me_next.tqe_prev = (me)->me_next.tqe_prev
; else (&sc->sc_cld)->tqh_last = (me)->me_next.tqe_prev
; *(me)->me_next.tqe_prev = (me)->me_next.tqe_next; ((me
)->me_next.tqe_prev) = ((void *)-1); ((me)->me_next.tqe_next
) = ((void *)-1); } while (0)
;
700 }
701
702 rw_exit_write(&sc->sc_lock);
703
704 DPRINTF(("%s: %s(%p) done, error=%d\n", __func__,
705 sc->sc_base.me_dv.dv_xname, sc, error));
706 return (error);
707}
708
709/* Remove me from the parent. */
710void
711wsmux_detach_sc(struct wsevsrc *me)
712{
713 struct wsmux_softc *sc = me->me_parent;
714
715 if (sc == NULL((void *)0)) {
716 printf("wsmux_detach_sc: %s has no parent\n",
717 me->me_dv.dv_xname);
718 return;
719 }
720
721 rw_enter_write(&sc->sc_lock);
722 wsmux_detach_sc_locked(sc, me);
723 rw_exit_write(&sc->sc_lock);
724}
725
726void
727wsmux_detach_sc_locked(struct wsmux_softc *sc, struct wsevsrc *me)
728{
729 rw_assert_wrlock(&sc->sc_lock);
730
731 DPRINTF(("%s: %s(%p) parent=%p\n", __func__,
732 me->me_dv.dv_xname, me, sc));
733
734 if (me->me_parent != sc) {
735 /* Device detached or attached to another mux while sleeping. */
736 return;
737 }
738
739#if NWSDISPLAY1 > 0
740 if (sc->sc_displaydvsc_base.me_dispdv != NULL((void *)0)) {
741 if (me->me_ops->dsetdisplay != NULL((void *)0))
742 /* ignore error, there's nothing we can do */
743 (void)wsevsrc_set_display(me, NULL)((me)->me_ops->dsetdisplay(&(me)->me_dv, ((void *
)0)))
;
744 } else
745#endif
746 if (me->me_evp != NULL((void *)0)) {
747 DPRINTF(("%s: close\n", __func__));
748 /* mux device is open, so close multiplexee */
749 (void)wsevsrc_close(me)((me)->me_ops->dclose((me)));
750 }
751
752 TAILQ_REMOVE(&sc->sc_cld, me, me_next)do { if (((me)->me_next.tqe_next) != ((void *)0)) (me)->
me_next.tqe_next->me_next.tqe_prev = (me)->me_next.tqe_prev
; else (&sc->sc_cld)->tqh_last = (me)->me_next.tqe_prev
; *(me)->me_next.tqe_prev = (me)->me_next.tqe_next; ((me
)->me_next.tqe_prev) = ((void *)-1); ((me)->me_next.tqe_next
) = ((void *)-1); } while (0)
;
753 me->me_parent = NULL((void *)0);
754
755 DPRINTF(("%s: done sc=%p\n", __func__, sc));
756}
757
758/*
759 * Display ioctl() of a mux via the parent mux.
760 */
761int
762wsmux_do_displayioctl(struct device *dv, u_long cmd, caddr_t data, int flag,
763 struct proc *p)
764{
765 struct wsmux_softc *sc = (struct wsmux_softc *)dv;
766 struct wsevsrc *me;
767 int error, ok;
768
769 DPRINTF(("%s: %s: sc=%p, cmd=%08lx\n", __func__,
770 sc->sc_base.me_dv.dv_xname, sc, cmd));
771
772#ifdef WSDISPLAY_COMPAT_RAWKBD1
773 if (cmd == WSKBDIO_SETMODE((unsigned long)0x80000000 | ((sizeof(int) & 0x1fff) <<
16) | ((('W')) << 8) | ((19)))
) {
774 sc->sc_rawkbd = *(int *)data;
775 DPRINTF(("%s: rawkbd = %d\n", __func__, sc->sc_rawkbd));
776 }
777#endif
778
779 /*
780 * Return 0 if any of the ioctl() succeeds, otherwise the last error.
781 * Return -1 if no mux component accepts the ioctl.
782 */
783 error = -1;
784 ok = 0;
785 rw_enter_read(&sc->sc_lock);
786 TAILQ_FOREACH(me, &sc->sc_cld, me_next)for((me) = ((&sc->sc_cld)->tqh_first); (me) != ((void
*)0); (me) = ((me)->me_next.tqe_next))
{
787 DPRINTF(("%s: me=%p\n", __func__, me));
788#ifdef DIAGNOSTIC1
789 if (me->me_parent != sc) {
790 printf("wsmux_displayioctl: bad child %p\n", me);
791 continue;
792 }
793#endif
794 if (me->me_ops->ddispioctl != NULL((void *)0)) {
795 error = wsevsrc_display_ioctl(me, cmd, data, flag, p)((me)->me_ops->ddispioctl(&(me)->me_dv, cmd, (caddr_t
)data, flag, p))
;
796 DPRINTF(("%s: me=%p dev=%s ==> %d\n", __func__,
797 me, me->me_dv.dv_xname, error));
798 if (!error)
799 ok = 1;
800 }
801 }
802 rw_exit_read(&sc->sc_lock);
803 if (ok)
804 error = 0;
805
806 return (error);
807}
808
809#if NWSDISPLAY1 > 0
810/*
811 * Set display of a mux via the parent mux.
812 */
813int
814wsmux_evsrc_set_display(struct device *dv, struct device *displaydv)
815{
816 struct wsmux_softc *sc = (struct wsmux_softc *)dv;
817
818 DPRINTF(("%s: %s: displaydv=%p\n", __func__,
819 sc->sc_base.me_dv.dv_xname, displaydv));
820
821 if (displaydv != NULL((void *)0)) {
822 if (sc->sc_displaydvsc_base.me_dispdv != NULL((void *)0))
823 return (EBUSY16);
824 } else {
825 if (sc->sc_displaydvsc_base.me_dispdv == NULL((void *)0))
826 return (ENXIO6);
827 }
828
829 return wsmux_set_display(sc, displaydv);
830}
831
832int
833wsmux_set_display(struct wsmux_softc *sc, struct device *displaydv)
834{
835 struct device *odisplaydv;
836 struct wsevsrc *me;
837 struct wsmux_softc *nsc = displaydv ? sc : NULL((void *)0);
838 int error, ok;
839
840 rw_enter_read(&sc->sc_lock);
841
842 odisplaydv = sc->sc_displaydvsc_base.me_dispdv;
Value stored to 'odisplaydv' is never read
843 sc->sc_displaydvsc_base.me_dispdv = displaydv;
844
845 if (displaydv) {
846 DPRINTF(("%s: connecting to %s\n",
847 sc->sc_base.me_dv.dv_xname, displaydv->dv_xname));
848 }
849 ok = 0;
850 error = 0;
851 TAILQ_FOREACH(me, &sc->sc_cld, me_next)for((me) = ((&sc->sc_cld)->tqh_first); (me) != ((void
*)0); (me) = ((me)->me_next.tqe_next))
{
852#ifdef DIAGNOSTIC1
853 if (me->me_parent != sc) {
854 printf("wsmux_set_display: bad child parent %p\n", me);
855 continue;
856 }
857#endif
858 if (me->me_ops->dsetdisplay != NULL((void *)0)) {
859 error = wsevsrc_set_display(me,((me)->me_ops->dsetdisplay(&(me)->me_dv, nsc ? nsc
->sc_base.me_dispdv : ((void *)0)))
860 nsc ? nsc->sc_displaydv : NULL)((me)->me_ops->dsetdisplay(&(me)->me_dv, nsc ? nsc
->sc_base.me_dispdv : ((void *)0)))
;
861 DPRINTF(("%s: m=%p dev=%s error=%d\n", __func__,
862 me, me->me_dv.dv_xname, error));
863 if (!error) {
864 ok = 1;
865#ifdef WSDISPLAY_COMPAT_RAWKBD1
866 DPRINTF(("%s: %s set rawkbd=%d\n", __func__,
867 me->me_dv.dv_xname, sc->sc_rawkbd));
868 (void)wsevsrc_ioctl(me, WSKBDIO_SETMODE,((me)->me_ops->dioctl(&(me)->me_dv, ((unsigned long
)0x80000000 | ((sizeof(int) & 0x1fff) << 16) | ((('W'
)) << 8) | ((19))), (caddr_t)&sc->sc_rawkbd, 0x0002
, 0))
869 &sc->sc_rawkbd, FWRITE, 0)((me)->me_ops->dioctl(&(me)->me_dv, ((unsigned long
)0x80000000 | ((sizeof(int) & 0x1fff) << 16) | ((('W'
)) << 8) | ((19))), (caddr_t)&sc->sc_rawkbd, 0x0002
, 0))
;
870#endif
871 }
872 }
873 }
874 if (ok)
875 error = 0;
876
877 if (displaydv == NULL((void *)0)) {
878 DPRINTF(("%s: disconnecting from %s\n",
879 sc->sc_base.me_dv.dv_xname, odisplaydv->dv_xname));
880 }
881
882 rw_exit_read(&sc->sc_lock);
883
884 return (error);
885}
886#endif /* NWSDISPLAY > 0 */
887
888uint32_t
889wsmux_get_layout(struct wsmux_softc *sc)
890{
891 return sc->sc_kbd_layout;
892}
893
894void
895wsmux_set_layout(struct wsmux_softc *sc, uint32_t layout)
896{
897 if ((layout & (KB_DEFAULT0x80000000 | KB_NOENCODING0x00000080)) == 0)
898 sc->sc_kbd_layout = layout;
899}
900
901/*
902 * Returns the depth of the longest chain of nested wsmux devices starting
903 * from sc.
904 */
905int
906wsmux_depth(struct wsmux_softc *sc)
907{
908 struct wsevsrc *me;
909 int depth;
910 int maxdepth = 0;
911
912 rw_assert_anylock(&wsmux_tree_lock);
913
914 rw_enter_read(&sc->sc_lock);
915 TAILQ_FOREACH(me, &sc->sc_cld, me_next)for((me) = ((&sc->sc_cld)->tqh_first); (me) != ((void
*)0); (me) = ((me)->me_next.tqe_next))
{
916 if (me->me_ops->type != WSMUX_MUX3)
917 continue;
918
919 depth = wsmux_depth((struct wsmux_softc *)me);
920 if (depth > maxdepth)
921 maxdepth = depth;
922 }
923 rw_exit_read(&sc->sc_lock);
924
925 return (maxdepth + 1);
926}