Date: Wed, 6 Feb 2013 23:42:05 +0000 (UTC) From: Attilio Rao <attilio@FreeBSD.org> To: src-committers@freebsd.org, svn-src-user@freebsd.org Subject: svn commit: r246444 - in user/attilio/vmc-playground/sys: dev/sound/pcm dev/sound/usb fs/nfs kern nfsclient sys Message-ID: <201302062342.r16Ng5xc013378@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: attilio Date: Wed Feb 6 23:42:04 2013 New Revision: 246444 URL: http://svnweb.freebsd.org/changeset/base/246444 Log: Merge from vmcontention Modified: user/attilio/vmc-playground/sys/dev/sound/pcm/mixer.c user/attilio/vmc-playground/sys/dev/sound/pcm/mixer.h user/attilio/vmc-playground/sys/dev/sound/usb/uaudio.c user/attilio/vmc-playground/sys/fs/nfs/nfs_commonkrpc.c user/attilio/vmc-playground/sys/kern/kern_sig.c user/attilio/vmc-playground/sys/kern/subr_sleepqueue.c user/attilio/vmc-playground/sys/kern/vfs_acl.c user/attilio/vmc-playground/sys/nfsclient/nfs_krpc.c user/attilio/vmc-playground/sys/sys/signalvar.h Directory Properties: user/attilio/vmc-playground/ (props changed) user/attilio/vmc-playground/sys/ (props changed) Modified: user/attilio/vmc-playground/sys/dev/sound/pcm/mixer.c ============================================================================== --- user/attilio/vmc-playground/sys/dev/sound/pcm/mixer.c Wed Feb 6 23:30:36 2013 (r246443) +++ user/attilio/vmc-playground/sys/dev/sound/pcm/mixer.c Wed Feb 6 23:42:04 2013 (r246444) @@ -1492,3 +1492,30 @@ mixer_get_lock(struct snd_mixer *m) } return (m->lock); } + +int +mix_get_locked(struct snd_mixer *m, u_int dev, int *pleft, int *pright) +{ + int level; + + level = mixer_get(m, dev); + if (level < 0) { + *pright = *pleft = -1; + return (-1); + } + + *pleft = level & 0xFF; + *pright = (level >> 8) & 0xFF; + + return (0); +} + +int +mix_set_locked(struct snd_mixer *m, u_int dev, int left, int right) +{ + int level; + + level = (left & 0xFF) | ((right & 0xFF) << 8); + + return (mixer_set(m, dev, level)); +} Modified: user/attilio/vmc-playground/sys/dev/sound/pcm/mixer.h ============================================================================== --- user/attilio/vmc-playground/sys/dev/sound/pcm/mixer.h Wed Feb 6 23:30:36 2013 (r246443) +++ user/attilio/vmc-playground/sys/dev/sound/pcm/mixer.h Wed Feb 6 23:42:04 2013 (r246444) @@ -45,6 +45,8 @@ void mixer_hwvol_step(device_t dev, int int mixer_busy(struct snd_mixer *m); +int mix_get_locked(struct snd_mixer *m, u_int dev, int *pleft, int *pright); +int mix_set_locked(struct snd_mixer *m, u_int dev, int left, int right); int mix_set(struct snd_mixer *m, u_int dev, u_int left, u_int right); int mix_get(struct snd_mixer *m, u_int dev); int mix_setrecsrc(struct snd_mixer *m, u_int32_t src); Modified: user/attilio/vmc-playground/sys/dev/sound/usb/uaudio.c ============================================================================== --- user/attilio/vmc-playground/sys/dev/sound/usb/uaudio.c Wed Feb 6 23:30:36 2013 (r246443) +++ user/attilio/vmc-playground/sys/dev/sound/usb/uaudio.c Wed Feb 6 23:42:04 2013 (r246444) @@ -71,6 +71,7 @@ __FBSDID("$FreeBSD$"); #include <dev/usb/usb.h> #include <dev/usb/usbdi.h> #include <dev/usb/usbdi_util.h> +#include <dev/usb/usbhid.h> #include <dev/usb/usb_request.h> #define USB_DEBUG_VAR uaudio_debug @@ -277,16 +278,37 @@ struct uaudio_search_result { uint8_t is_input; }; +enum { + UAUDIO_HID_RX_TRANSFER, + UAUDIO_HID_N_TRANSFER, +}; + +struct uaudio_hid { + struct usb_xfer *xfer[UAUDIO_HID_N_TRANSFER]; + struct hid_location volume_up_loc; + struct hid_location volume_down_loc; + uint32_t flags; +#define UAUDIO_HID_VALID 0x0001 +#define UAUDIO_HID_HAS_ID 0x0002 +#define UAUDIO_HID_HAS_VOLUME_UP 0x0004 +#define UAUDIO_HID_HAS_VOLUME_DOWN 0x0008 + uint8_t iface_index; + uint8_t volume_up_id; + uint8_t volume_down_id; +}; + struct uaudio_softc { struct sbuf sc_sndstat; struct sndcard_func sc_sndcard_func; struct uaudio_chan sc_rec_chan; struct uaudio_chan sc_play_chan; struct umidi_chan sc_midi_chan; + struct uaudio_hid sc_hid; struct uaudio_search_result sc_mixer_clocks; struct uaudio_mixer_node sc_mixer_node; struct mtx *sc_mixer_lock; + struct snd_mixer *sc_mixer_dev; struct usb_device *sc_udev; struct usb_xfer *sc_mixer_xfer[1]; struct uaudio_mixer_node *sc_mixer_root; @@ -407,6 +429,7 @@ static usb_callback_t uaudio_chan_record static usb_callback_t uaudio_mixer_write_cfg_callback; static usb_callback_t umidi_bulk_read_callback; static usb_callback_t umidi_bulk_write_callback; +static usb_callback_t uaudio_hid_rx_callback; /* ==== USB mixer ==== */ @@ -500,6 +523,9 @@ static void umidi_close(struct usb_fifo static void umidi_init(device_t dev); static int umidi_probe(device_t dev); static int umidi_detach(device_t dev); +static int uaudio_hid_probe(struct uaudio_softc *sc, + struct usb_attach_arg *uaa); +static void uaudio_hid_detach(struct uaudio_softc *sc); #ifdef USB_DEBUG static void uaudio_chan_dump_ep_desc( @@ -624,6 +650,18 @@ static const struct usb_config }, }; +static const struct usb_config + uaudio_hid_config[UAUDIO_HID_N_TRANSFER] = { + [UAUDIO_HID_RX_TRANSFER] = { + .type = UE_INTERRUPT, + .endpoint = UE_ADDR_ANY, + .direction = UE_DIR_IN, + .bufsize = 0, /* use wMaxPacketSize */ + .flags = {.short_xfer_ok = 1,}, + .callback = &uaudio_hid_rx_callback, + }, +}; + static devclass_t uaudio_devclass; static device_method_t uaudio_methods[] = { @@ -896,7 +934,7 @@ uaudio_attach(device_t dev) } device_printf(dev, "MIDI sequencer.\n"); } else { - device_printf(dev, "No midi sequencer.\n"); + device_printf(dev, "No MIDI sequencer.\n"); } DPRINTF("doing child attach\n"); @@ -926,6 +964,12 @@ uaudio_attach(device_t dev) goto detach; } + if (uaudio_hid_probe(sc, uaa) == 0) { + device_printf(dev, "HID volume keys found.\n"); + } else { + device_printf(dev, "No HID volume keys found.\n"); + } + /* reload all mixer settings */ uaudio_mixer_reload_all(sc); @@ -1034,6 +1078,8 @@ uaudio_detach(device_t dev) if (sc->sc_rec_chan.valid) usbd_transfer_unsetup(sc->sc_rec_chan.xfer, UAUDIO_NCHANBUFS + 1); + uaudio_hid_detach(sc); + if (bus_generic_detach(dev) != 0) { DPRINTF("detach failed!\n"); } @@ -1213,6 +1259,18 @@ uaudio_chan_fill_info_sub(struct uaudio_ alt_index++; } + if ((!(sc->sc_hid.flags & UAUDIO_HID_VALID)) && + (id->bInterfaceClass == UICLASS_HID) && + (id->bInterfaceSubClass == 0) && + (id->bInterfaceProtocol == 0) && + (alt_index == 0) && + usbd_get_iface(udev, curidx) != NULL) { + DPRINTF("Found HID interface at %d\n", + curidx); + sc->sc_hid.flags |= UAUDIO_HID_VALID; + sc->sc_hid.iface_index = curidx; + } + uma_if_class = ((id->bInterfaceClass == UICLASS_AUDIO) || ((id->bInterfaceClass == UICLASS_VENDOR) && @@ -2490,6 +2548,9 @@ uaudio_mixer_reload_all(struct uaudio_so pmc->update[chan / 8] |= (1 << (chan % 8)); } usbd_transfer_start(sc->sc_mixer_xfer[0]); + + /* start HID volume keys, if any */ + usbd_transfer_start(sc->sc_hid.xfer[0]); mtx_unlock(sc->sc_mixer_lock); } @@ -4818,6 +4879,7 @@ uaudio_mixer_init_sub(struct uaudio_soft DPRINTF("\n"); sc->sc_mixer_lock = mixer_get_lock(m); + sc->sc_mixer_dev = m; if (usbd_transfer_setup(sc->sc_udev, &sc->sc_mixer_iface_index, sc->sc_mixer_xfer, uaudio_mixer_config, 1, sc, @@ -5452,6 +5514,162 @@ umidi_detach(device_t dev) return (0); } +static void +uaudio_hid_rx_callback(struct usb_xfer *xfer, usb_error_t error) +{ + struct uaudio_softc *sc = usbd_xfer_softc(xfer); + const uint8_t *buffer = usbd_xfer_get_frame_buffer(xfer, 0); + struct snd_mixer *m; + int v; + int v_l; + int v_r; + uint8_t id; + int actlen; + + usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); + + switch (USB_GET_STATE(xfer)) { + case USB_ST_TRANSFERRED: + DPRINTF("actlen=%d\n", actlen); + + if (actlen != 0 && + (sc->sc_hid.flags & UAUDIO_HID_HAS_ID)) { + id = *buffer; + buffer++; + actlen--; + } else { + id = 0; + } + + m = sc->sc_mixer_dev; + + if ((sc->sc_hid.flags & UAUDIO_HID_HAS_VOLUME_UP) && + (sc->sc_hid.volume_up_id == id) && + hid_get_data(buffer, actlen, + &sc->sc_hid.volume_up_loc)) { + + DPRINTF("Volume Up\n"); + + v = mix_get_locked(m, SOUND_MIXER_PCM, &v_l, &v_r); + if (v == 0) { + v = ((v_l + v_r) / 2) + 5; + if (v > 100) + v = 100; + mix_set_locked(m, SOUND_MIXER_PCM, v, v); + } + } + + if ((sc->sc_hid.flags & UAUDIO_HID_HAS_VOLUME_DOWN) && + (sc->sc_hid.volume_down_id == id) && + hid_get_data(buffer, actlen, + &sc->sc_hid.volume_down_loc)) { + + DPRINTF("Volume Down\n"); + + v = mix_get_locked(m, SOUND_MIXER_PCM, &v_l, &v_r); + if (v == 0) { + v = ((v_l + v_r) / 2) - 5; + if (v < 0) + v = 0; + mix_set_locked(m, SOUND_MIXER_PCM, v, v); + } + } + + case USB_ST_SETUP: +tr_setup: + /* check if we can put more data into the FIFO */ + usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); + usbd_transfer_submit(xfer); + break; + + default: /* Error */ + if (error != USB_ERR_CANCELLED) { + /* try clear stall first */ + usbd_xfer_set_stall(xfer); + goto tr_setup; + } + break; + } +} + +static int +uaudio_hid_probe(struct uaudio_softc *sc, + struct usb_attach_arg *uaa) +{ + void *d_ptr; + uint32_t flags; + uint16_t d_len; + uint8_t id; + int error; + + if (!(sc->sc_hid.flags & UAUDIO_HID_VALID)) + return (-1); + + if (sc->sc_mixer_lock == NULL) + return (-1); + + /* Get HID descriptor */ + error = usbd_req_get_hid_desc(uaa->device, NULL, &d_ptr, + &d_len, M_TEMP, sc->sc_hid.iface_index); + + if (error) { + DPRINTF("error reading report description\n"); + return (-1); + } + + /* check if there is an ID byte */ + hid_report_size(d_ptr, d_len, hid_input, &id); + + if (id != 0) + sc->sc_hid.flags |= UAUDIO_HID_HAS_ID; + + if (hid_locate(d_ptr, d_len, + HID_USAGE2(HUP_CONSUMER, 0xE9 /* Volume Increment */), + hid_input, 0, &sc->sc_hid.volume_up_loc, &flags, + &sc->sc_hid.volume_up_id)) { + if (flags & HIO_VARIABLE) + sc->sc_hid.flags |= UAUDIO_HID_HAS_VOLUME_UP; + DPRINTFN(1, "Found Volume Up key\n"); + } + + if (hid_locate(d_ptr, d_len, + HID_USAGE2(HUP_CONSUMER, 0xEA /* Volume Decrement */), + hid_input, 0, &sc->sc_hid.volume_down_loc, &flags, + &sc->sc_hid.volume_down_id)) { + if (flags & HIO_VARIABLE) + sc->sc_hid.flags |= UAUDIO_HID_HAS_VOLUME_DOWN; + DPRINTFN(1, "Found Volume Down key\n"); + } + + free(d_ptr, M_TEMP); + + if (!(sc->sc_hid.flags & (UAUDIO_HID_HAS_VOLUME_UP | + UAUDIO_HID_HAS_VOLUME_DOWN))) { + DPRINTFN(1, "Did not find any volume related keys\n"); + return (-1); + } + + /* prevent the uhid driver from attaching */ + usbd_set_parent_iface(uaa->device, sc->sc_hid.iface_index, + sc->sc_mixer_iface_index); + + /* allocate USB transfers */ + error = usbd_transfer_setup(uaa->device, &sc->sc_hid.iface_index, + sc->sc_hid.xfer, uaudio_hid_config, UAUDIO_HID_N_TRANSFER, + sc, sc->sc_mixer_lock); + if (error) { + DPRINTF("error=%s\n", usbd_errstr(error)); + return (-1); + } + return (0); +} + +static void +uaudio_hid_detach(struct uaudio_softc *sc) +{ + usbd_transfer_unsetup(sc->sc_hid.xfer, UAUDIO_HID_N_TRANSFER); +} + DRIVER_MODULE(uaudio, uhub, uaudio_driver, uaudio_devclass, NULL, 0); MODULE_DEPEND(uaudio, usb, 1, 1, 1); MODULE_DEPEND(uaudio, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); Modified: user/attilio/vmc-playground/sys/fs/nfs/nfs_commonkrpc.c ============================================================================== --- user/attilio/vmc-playground/sys/fs/nfs/nfs_commonkrpc.c Wed Feb 6 23:30:36 2013 (r246443) +++ user/attilio/vmc-playground/sys/fs/nfs/nfs_commonkrpc.c Wed Feb 6 23:42:04 2013 (r246444) @@ -1031,7 +1031,6 @@ int newnfs_sig_set[] = { SIGTERM, SIGHUP, SIGKILL, - SIGSTOP, SIGQUIT }; @@ -1052,7 +1051,7 @@ nfs_sig_pending(sigset_t set) /* * The set/restore sigmask functions are used to (temporarily) overwrite - * the process p_sigmask during an RPC call (for example). These are also + * the thread td_sigmask during an RPC call (for example). These are also * used in other places in the NFS client that might tsleep(). */ void @@ -1081,8 +1080,10 @@ newnfs_set_sigmask(struct thread *td, si SIGDELSET(newset, newnfs_sig_set[i]); } mtx_unlock(&p->p_sigacts->ps_mtx); + sigdeferstop(td); + kern_sigprocmask(td, SIG_SETMASK, &newset, oldset, + SIGPROCMASK_PROC_LOCKED); PROC_UNLOCK(p); - kern_sigprocmask(td, SIG_SETMASK, &newset, oldset, 0); } void @@ -1091,6 +1092,7 @@ newnfs_restore_sigmask(struct thread *td if (td == NULL) td = curthread; /* XXX */ kern_sigprocmask(td, SIG_SETMASK, set, NULL, 0); + sigallowstop(td); } /* Modified: user/attilio/vmc-playground/sys/kern/kern_sig.c ============================================================================== --- user/attilio/vmc-playground/sys/kern/kern_sig.c Wed Feb 6 23:30:36 2013 (r246443) +++ user/attilio/vmc-playground/sys/kern/kern_sig.c Wed Feb 6 23:42:04 2013 (r246444) @@ -2364,6 +2364,13 @@ tdsigwakeup(struct thread *td, int sig, } /* + * Don't awaken a sleeping thread for SIGSTOP if the + * STOP signal is deferred. + */ + if ((prop & SA_STOP) && (td->td_flags & TDF_SBDRY)) + goto out; + + /* * Give low priority threads a better chance to run. */ if (td->td_priority > PUSER) @@ -2404,12 +2411,13 @@ sig_suspend_threads(struct thread *td, s if ((TD_IS_SLEEPING(td2) || TD_IS_SWAPPED(td2)) && (td2->td_flags & TDF_SINTR)) { if (td2->td_flags & TDF_SBDRY) { - if (TD_IS_SUSPENDED(td2)) - wakeup_swapper |= - thread_unsuspend_one(td2); - if (TD_ON_SLEEPQ(td2)) - wakeup_swapper |= - sleepq_abort(td2, ERESTART); + /* + * Once a thread is asleep with + * TDF_SBDRY set, it should never + * become suspended due to this check. + */ + KASSERT(!TD_IS_SUSPENDED(td2), + ("thread with deferred stops suspended")); } else if (!TD_IS_SUSPENDED(td2)) { thread_suspend_one(td2); } @@ -2529,6 +2537,34 @@ tdsigcleanup(struct thread *td) } +/* Defer the delivery of SIGSTOP for the current thread. */ +void +sigdeferstop(struct thread *td) +{ + + KASSERT(!(td->td_flags & TDF_SBDRY), + ("attempt to set TDF_SBDRY recursively")); + thread_lock(td); + td->td_flags |= TDF_SBDRY; + thread_unlock(td); +} + +/* + * Permit the delivery of SIGSTOP for the current thread. This does + * not immediately suspend if a stop was posted. Instead, the thread + * will suspend either via ast() or a subsequent interruptible sleep. + */ +void +sigallowstop(struct thread *td) +{ + + KASSERT(td->td_flags & TDF_SBDRY, + ("attempt to clear already-cleared TDF_SBDRY")); + thread_lock(td); + td->td_flags &= ~TDF_SBDRY; + thread_unlock(td); +} + /* * If the current process has received a signal (should be caught or cause * termination, should interrupt current syscall), return the signal number. @@ -2561,7 +2597,7 @@ issignal(struct thread *td, int stop_all SIGSETOR(sigpending, p->p_sigqueue.sq_signals); SIGSETNAND(sigpending, td->td_sigmask); - if (p->p_flag & P_PPWAIT) + if (p->p_flag & P_PPWAIT || td->td_flags & TDF_SBDRY) SIG_STOPSIGMASK(sigpending); if (SIGISEMPTY(sigpending)) /* no signal to send */ return (0); @@ -2677,10 +2713,6 @@ issignal(struct thread *td, int stop_all (p->p_pgrp->pg_jobc == 0 && prop & SA_TTYSTOP)) break; /* == ignore */ - - /* Ignore, but do not drop the stop signal. */ - if (stop_allowed != SIG_STOP_ALLOWED) - return (sig); mtx_unlock(&ps->ps_mtx); WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &p->p_mtx.lock_object, "Catching SIGSTOP"); Modified: user/attilio/vmc-playground/sys/kern/subr_sleepqueue.c ============================================================================== --- user/attilio/vmc-playground/sys/kern/subr_sleepqueue.c Wed Feb 6 23:30:36 2013 (r246443) +++ user/attilio/vmc-playground/sys/kern/subr_sleepqueue.c Wed Feb 6 23:42:04 2013 (r246444) @@ -352,8 +352,6 @@ sleepq_add(void *wchan, struct lock_obje if (flags & SLEEPQ_INTERRUPTIBLE) { td->td_flags |= TDF_SINTR; td->td_flags &= ~TDF_SLEEPABORT; - if (flags & SLEEPQ_STOP_ON_BDRY) - td->td_flags |= TDF_SBDRY; } thread_unlock(td); } @@ -600,7 +598,7 @@ sleepq_check_signals(void) /* We are no longer in an interruptible sleep. */ if (td->td_flags & TDF_SINTR) - td->td_flags &= ~(TDF_SINTR | TDF_SBDRY); + td->td_flags &= ~TDF_SINTR; if (td->td_flags & TDF_SLEEPABORT) { td->td_flags &= ~TDF_SLEEPABORT; @@ -747,7 +745,7 @@ sleepq_resume_thread(struct sleepqueue * td->td_wmesg = NULL; td->td_wchan = NULL; - td->td_flags &= ~(TDF_SINTR | TDF_SBDRY); + td->td_flags &= ~TDF_SINTR; CTR3(KTR_PROC, "sleepq_wakeup: thread %p (pid %ld, %s)", (void *)td, (long)td->td_proc->p_pid, td->td_name); Modified: user/attilio/vmc-playground/sys/kern/vfs_acl.c ============================================================================== --- user/attilio/vmc-playground/sys/kern/vfs_acl.c Wed Feb 6 23:30:36 2013 (r246443) +++ user/attilio/vmc-playground/sys/kern/vfs_acl.c Wed Feb 6 23:42:04 2013 (r246444) @@ -247,7 +247,7 @@ vacl_get_acl(struct thread *td, struct v struct acl *inkernelacl; int error; - inkernelacl = acl_alloc(M_WAITOK); + inkernelacl = acl_alloc(M_WAITOK | M_ZERO); vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); #ifdef MAC error = mac_vnode_check_getacl(td->td_ucred, vp, type); Modified: user/attilio/vmc-playground/sys/nfsclient/nfs_krpc.c ============================================================================== --- user/attilio/vmc-playground/sys/nfsclient/nfs_krpc.c Wed Feb 6 23:30:36 2013 (r246443) +++ user/attilio/vmc-playground/sys/nfsclient/nfs_krpc.c Wed Feb 6 23:42:04 2013 (r246444) @@ -699,7 +699,6 @@ int nfs_sig_set[] = { SIGTERM, SIGHUP, SIGKILL, - SIGSTOP, SIGQUIT }; @@ -720,7 +719,7 @@ nfs_sig_pending(sigset_t set) /* * The set/restore sigmask functions are used to (temporarily) overwrite - * the process p_sigmask during an RPC call (for example). These are also + * the thread td_sigmask during an RPC call (for example). These are also * used in other places in the NFS client that might tsleep(). */ void @@ -749,8 +748,10 @@ nfs_set_sigmask(struct thread *td, sigse SIGDELSET(newset, nfs_sig_set[i]); } mtx_unlock(&p->p_sigacts->ps_mtx); + sigdeferstop(td); + kern_sigprocmask(td, SIG_SETMASK, &newset, oldset, + SIGPROCMASK_PROC_LOCKED); PROC_UNLOCK(p); - kern_sigprocmask(td, SIG_SETMASK, &newset, oldset, 0); } void @@ -759,6 +760,7 @@ nfs_restore_sigmask(struct thread *td, s if (td == NULL) td = curthread; /* XXX */ kern_sigprocmask(td, SIG_SETMASK, set, NULL, 0); + sigallowstop(td); } /* Modified: user/attilio/vmc-playground/sys/sys/signalvar.h ============================================================================== --- user/attilio/vmc-playground/sys/sys/signalvar.h Wed Feb 6 23:30:36 2013 (r246443) +++ user/attilio/vmc-playground/sys/sys/signalvar.h Wed Feb 6 23:42:04 2013 (r246444) @@ -328,6 +328,8 @@ extern struct mtx sigio_lock; #define SIGPROCMASK_PS_LOCKED 0x0004 int cursig(struct thread *td, int stop_allowed); +void sigdeferstop(struct thread *td); +void sigallowstop(struct thread *td); void execsigs(struct proc *p); void gsignal(int pgid, int sig, ksiginfo_t *ksi); void killproc(struct proc *p, char *why);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201302062342.r16Ng5xc013378>