1 /* $NetBSD: wsdisplay_compat_usl.c,v 1.45 2008/04/24 15:35:28 ad Exp $ */
5 * Matthias Drochner. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: wsdisplay_compat_usl.c,v 1.45 2008/04/24 15:35:28 ad Exp $");
32 #include "opt_compat_freebsd.h"
33 #include "opt_compat_netbsd.h"
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/callout.h>
38 #include <sys/ioctl.h>
39 #include <sys/kernel.h>
41 #include <sys/signalvar.h>
42 #include <sys/malloc.h>
43 #include <sys/errno.h>
44 #include <sys/kauth.h>
46 #include <dev/wscons/wsconsio.h>
47 #include <dev/wscons/wsdisplayvar.h>
48 #include <dev/wscons/wscons_callbacks.h>
49 #include <dev/wscons/wsdisplay_usl_io.h>
51 #include "opt_wsdisplay_compat.h"
54 struct wsscreen
*s_scr
;
58 #define SF_DETACHPENDING 1
59 #define SF_ATTACHPENDING 2
60 int s_acqsig
, s_relsig
;
61 int s_frsig
; /* unused */
62 void (*s_callback
)(void *, int, int);
64 callout_t s_attach_ch
;
65 callout_t s_detach_ch
;
68 static int usl_sync_init(struct wsscreen
*, struct usl_syncdata
**,
69 struct proc
*, int, int, int);
70 static void usl_sync_done(struct usl_syncdata
*);
71 static int usl_sync_check(void *);
72 static int usl_sync_check_sig(struct usl_syncdata
*, int, int);
73 static struct usl_syncdata
*usl_sync_get(struct wsscreen
*);
75 static int usl_detachproc(void *, int, void (*)(void *, int, int), void *);
76 static int usl_detachack(struct usl_syncdata
*, int);
77 static void usl_detachtimeout(void *);
78 static int usl_attachproc(void *, int, void (*)(void *, int, int), void *);
79 static int usl_attachack(struct usl_syncdata
*, int);
80 static void usl_attachtimeout(void *);
82 static const struct wscons_syncops usl_syncops
= {
86 #define _usl_sync_destroy ((void (*)(void *))usl_sync_done)
90 #ifndef WSCOMPAT_USL_SYNCTIMEOUT
91 #define WSCOMPAT_USL_SYNCTIMEOUT 5 /* seconds */
93 static int wscompat_usl_synctimeout
= WSCOMPAT_USL_SYNCTIMEOUT
;
96 usl_sync_init(struct wsscreen
*scr
, struct usl_syncdata
**sdp
,
97 struct proc
*p
, int acqsig
, int relsig
, int frsig
)
99 struct usl_syncdata
*sd
;
102 sd
= malloc(sizeof(struct usl_syncdata
), M_DEVBUF
, M_WAITOK
);
107 sd
->s_pid
= p
->p_pid
;
109 sd
->s_acqsig
= acqsig
;
110 sd
->s_relsig
= relsig
;
112 callout_init(&sd
->s_attach_ch
, 0);
113 callout_setfunc(&sd
->s_attach_ch
, usl_attachtimeout
, sd
);
114 callout_init(&sd
->s_detach_ch
, 0);
115 callout_setfunc(&sd
->s_detach_ch
, usl_detachtimeout
, sd
);
116 res
= wsscreen_attach_sync(scr
, &usl_syncops
, sd
);
126 usl_sync_done(struct usl_syncdata
*sd
)
128 if (sd
->s_flags
& SF_DETACHPENDING
) {
129 callout_stop(&sd
->s_detach_ch
);
130 (*sd
->s_callback
)(sd
->s_cbarg
, 0, 0);
132 if (sd
->s_flags
& SF_ATTACHPENDING
) {
133 callout_stop(&sd
->s_attach_ch
);
134 (*sd
->s_callback
)(sd
->s_cbarg
, ENXIO
, 0);
136 wsscreen_detach_sync(sd
->s_scr
);
141 usl_sync_check_sig(struct usl_syncdata
*sd
, int sig
, int flags
)
144 mutex_enter(proc_lock
);
145 if (sd
->s_proc
== p_find(sd
->s_pid
, PFIND_LOCKED
)) {
146 sd
->s_flags
|= flags
;
148 psignal(sd
->s_proc
, sig
);
149 mutex_exit(proc_lock
);
152 mutex_exit(proc_lock
);
154 printf("usl_sync_check: process %d died\n", sd
->s_pid
);
160 usl_sync_check(void *vsd
)
163 struct usl_syncdata
*sd
= vsd
;
164 return usl_sync_check_sig(sd
, 0, 0);
167 static struct usl_syncdata
*
168 usl_sync_get(struct wsscreen
*scr
)
172 if (wsscreen_lookup_sync(scr
, &usl_syncops
, &sd
))
174 return (struct usl_syncdata
*)sd
;
178 usl_detachproc(void *cookie
, int waitok
,
179 void (*callback
)(void *, int, int), void *cbarg
)
181 struct usl_syncdata
*sd
= cookie
;
183 /* we really need a callback */
188 * Normally, this is called from the controlling process.
189 * Is is supposed to reply with a VT_RELDISP ioctl(), so
190 * it is not useful to tsleep() here.
192 sd
->s_callback
= callback
;
195 if (!usl_sync_check_sig(sd
, sd
->s_relsig
, SF_DETACHPENDING
))
199 callout_schedule(&sd
->s_detach_ch
, wscompat_usl_synctimeout
* hz
);
204 usl_detachack(struct usl_syncdata
*sd
, int ack
)
206 if (!(sd
->s_flags
& SF_DETACHPENDING
)) {
207 printf("usl_detachack: not detaching\n");
211 callout_stop(&sd
->s_detach_ch
);
212 sd
->s_flags
&= ~SF_DETACHPENDING
;
215 (*sd
->s_callback
)(sd
->s_cbarg
, (ack
? 0 : EIO
), 1);
221 usl_detachtimeout(void *arg
)
223 struct usl_syncdata
*sd
= arg
;
225 printf("usl_detachtimeout\n");
227 if (!(sd
->s_flags
& SF_DETACHPENDING
)) {
228 printf("usl_detachtimeout: not detaching\n");
232 sd
->s_flags
&= ~SF_DETACHPENDING
;
235 (*sd
->s_callback
)(sd
->s_cbarg
, EIO
, 0);
237 (void) usl_sync_check(sd
);
241 usl_attachproc(void *cookie
, int waitok
,
242 void (*callback
)(void *, int, int), void *cbarg
)
244 struct usl_syncdata
*sd
= cookie
;
246 /* we really need a callback */
250 sd
->s_callback
= callback
;
252 if (!usl_sync_check_sig(sd
, sd
->s_acqsig
, SF_ATTACHPENDING
))
255 callout_schedule(&sd
->s_attach_ch
, wscompat_usl_synctimeout
* hz
);
260 usl_attachack(struct usl_syncdata
*sd
, int ack
)
262 if (!(sd
->s_flags
& SF_ATTACHPENDING
)) {
263 printf("usl_attachack: not attaching\n");
267 callout_stop(&sd
->s_attach_ch
);
268 sd
->s_flags
&= ~SF_ATTACHPENDING
;
271 (*sd
->s_callback
)(sd
->s_cbarg
, (ack
? 0 : EIO
), 1);
277 usl_attachtimeout(void *arg
)
279 struct usl_syncdata
*sd
= arg
;
281 printf("usl_attachtimeout\n");
283 if (!(sd
->s_flags
& SF_ATTACHPENDING
)) {
284 printf("usl_attachtimeout: not attaching\n");
288 sd
->s_flags
&= ~SF_ATTACHPENDING
;
291 (*sd
->s_callback
)(sd
->s_cbarg
, EIO
, 0);
293 (void) usl_sync_check(sd
);
297 wsdisplay_usl_ioctl1(device_t dv
, u_long cmd
, void *data
,
298 int flag
, struct lwp
*l
)
300 struct wsdisplay_softc
*sc
= device_private(dv
);
305 maxidx
= wsdisplay_maxscreenidx(sc
);
306 for (idx
= 0; idx
<= maxidx
; idx
++) {
307 if (wsdisplay_screenstate(sc
, idx
) == 0) {
308 *(int *)data
= idx
+ 1;
314 idx
= wsdisplay_getactivescreen(sc
);
315 *(int *)data
= idx
+ 1;
319 * a gross and disgusting hack to make this abused up ioctl,
320 * which is a gross and disgusting hack on its own, work on
321 * LP64/BE - we want the lower 32bit so we simply dereference
322 * the argument pointer as long. May cause problems with 32bit
323 * kernels on sparc64?
326 idx
= *(long *)data
- 1;
329 return (wsdisplay_switch(dv
, idx
, 1));
331 idx
= *(long *)data
- 1;
334 return (wsscreen_switchwait(sc
, idx
));
336 #define ss ((struct vt_stat *)data)
337 idx
= wsdisplay_getactivescreen(sc
);
338 ss
->v_active
= idx
+ 1;
340 maxidx
= wsdisplay_maxscreenidx(sc
);
341 for (idx
= 0; idx
<= maxidx
; idx
++)
342 if (wsdisplay_screenstate(sc
, idx
) == EBUSY
)
343 ss
->v_state
|= (1 << (idx
+ 1));
347 #ifdef WSDISPLAY_COMPAT_PCVT
349 #define id ((struct pcvtid *)data)
350 strlcpy(id
->name
, "pcvt", sizeof(id
->name
));
356 #ifdef WSDISPLAY_COMPAT_SYSCONS
358 *(int *)data
= 0x200; /* version 2.0 */
363 return (EPASSTHROUGH
);
368 wsdisplay_usl_ioctl2(struct wsdisplay_softc
*sc
, struct wsscreen
*scr
,
369 u_long cmd
, void *data
, int flag
, struct lwp
*l
)
371 struct proc
*p
= l
->l_proc
;
375 struct usl_syncdata
*sd
;
376 struct wskbd_bell_data bd
;
380 #define newmode ((struct vt_mode *)data)
381 if (newmode
->mode
== VT_PROCESS
) {
382 res
= usl_sync_init(scr
, &sd
, p
, newmode
->acqsig
,
383 newmode
->relsig
, newmode
->frsig
);
387 sd
= usl_sync_get(scr
);
394 #define cmode ((struct vt_mode *)data)
395 sd
= usl_sync_get(scr
);
397 cmode
->mode
= VT_PROCESS
;
398 cmode
->relsig
= sd
->s_relsig
;
399 cmode
->acqsig
= sd
->s_acqsig
;
400 cmode
->frsig
= sd
->s_frsig
;
402 cmode
->mode
= VT_AUTO
;
406 #define d (*(long *)data)
407 sd
= usl_sync_get(scr
);
413 return (usl_detachack(sd
, (d
== VT_TRUE
)));
415 return (usl_attachack(sd
, 1));
422 #if defined(__i386__) && (defined(COMPAT_11) || defined(COMPAT_FREEBSD))
423 if (kauth_authorize_machdep(l
->l_cred
, KAUTH_MACHDEP_IOPL
,
424 NULL
, NULL
, NULL
, NULL
) != 0)
429 #if defined(__i386__) && (defined(COMPAT_11) || defined(COMPAT_FREEBSD))
432 struct trapframe
*fp
= (struct trapframe
*)curlwp
->l_md
.md_regs
;
434 fp
->tf_eflags
|= PSL_IOPL
;
436 fp
->tf_eflags
&= ~PSL_IOPL
;
441 /* XXX ignore for now */
445 return (EPASSTHROUGH
);
448 * the following are converted to wsdisplay ioctls
451 req
= WSDISPLAYIO_SMODE
;
452 #define d (*(int *)data)
455 intarg
= WSDISPLAYIO_MODE_MAPPED
;
458 intarg
= WSDISPLAYIO_MODE_EMUL
;
467 req
= WSKBDIO_COMPLEXBELL
;
468 #define d (*(int *)data)
470 #define PCVT_SYSBEEPF 1193182
472 bd
.which
= WSKBD_BELL_DOPERIOD
;
473 bd
.period
= d
>> 16; /* ms */
478 bd
.which
|= WSKBD_BELL_DOPITCH
;
479 bd
.pitch
= PCVT_SYSBEEPF
/(d
& 0xffff); /* Hz */
482 bd
.which
= 0; /* default */
487 req
= WSKBDIO_SETLEDS
;
489 #define d (*(int *)data)
491 intarg
|= WSKBD_LED_CAPS
;
493 intarg
|= WSKBD_LED_NUM
;
495 intarg
|= WSKBD_LED_SCROLL
;
500 req
= WSKBDIO_GETLEDS
;
503 #ifdef WSDISPLAY_COMPAT_RAWKBD
505 req
= WSKBDIO_SETMODE
;
506 switch (*(int *)data
) {
511 intarg
= WSKBD_TRANSLATED
;
519 req
= WSKBDIO_GETMODE
;
525 res
= wsdisplay_internal_ioctl(sc
, scr
, req
, arg
, flag
, l
);
526 if (res
!= EPASSTHROUGH
)
531 #define d (*(int *)data)
533 if (intarg
& WSKBD_LED_CAPS
)
535 if (intarg
& WSKBD_LED_NUM
)
537 if (intarg
& WSKBD_LED_SCROLL
)
541 #ifdef WSDISPLAY_COMPAT_RAWKBD
543 *(int *)data
= (intarg
== WSKBD_RAW
? K_RAW
: K_XLATE
);