139230Sgibbs/* $FreeBSD: stable/10/sys/dev/sound/usb/uaudio_pcm.c 359890 2020-04-13 16:34:21Z hselasky $ */ 282168Sken 339230Sgibbs/*- 439230Sgibbs * Copyright (c) 2000-2002 Hiroyuki Aizu <aizu@navi.org> 539230Sgibbs * Copyright (c) 2006 Hans Petter Selasky 639230Sgibbs * 739230Sgibbs * Redistribution and use in source and binary forms, with or without 839230Sgibbs * modification, are permitted provided that the following conditions 939230Sgibbs * are met: 1039230Sgibbs * 1. Redistributions of source code must retain the above copyright 1139230Sgibbs * notice, this list of conditions and the following disclaimer. 1239230Sgibbs * 2. Redistributions in binary form must reproduce the above copyright 1339230Sgibbs * notice, this list of conditions and the following disclaimer in the 1439230Sgibbs * documentation and/or other materials provided with the distribution. 1539230Sgibbs * 1639230Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1739230Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1839230Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1939230Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2039230Sgibbs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2139230Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2239230Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2339230Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2439230Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2539230Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2639230Sgibbs * SUCH DAMAGE. 2756561Scharnier */ 2856561Scharnier 2939230Sgibbs 3039230Sgibbs#ifdef HAVE_KERNEL_OPTION_HEADERS 3139230Sgibbs#include "opt_snd.h" 3239230Sgibbs#endif 3339230Sgibbs 341553Srgrimes#include <dev/sound/pcm/sound.h> 351553Srgrimes#include <dev/sound/chip.h> 361553Srgrimes#include <dev/sound/usb/uaudio.h> 371553Srgrimes 381553Srgrimes#include "mixer_if.h" 391553Srgrimes 401553Srgrimes/************************************************************/ 411553Srgrimesstatic void * 421553Srgrimesua_chan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) 431553Srgrimes{ 441553Srgrimes return (uaudio_chan_init(devinfo, b, c, dir)); 451553Srgrimes} 461553Srgrimes 471553Srgrimesstatic int 481553Srgrimesua_chan_free(kobj_t obj, void *data) 491553Srgrimes{ 501553Srgrimes return (uaudio_chan_free(data)); 511553Srgrimes} 521553Srgrimes 531553Srgrimesstatic int 541553Srgrimesua_chan_setformat(kobj_t obj, void *data, uint32_t format) 551553Srgrimes{ 561553Srgrimes /* 571553Srgrimes * At this point, no need to query as we 581553Srgrimes * shouldn't select an unsorted format 591553Srgrimes */ 601553Srgrimes return (uaudio_chan_set_param_format(data, format)); 611553Srgrimes} 6239230Sgibbs 6339230Sgibbsstatic uint32_t 6439230Sgibbsua_chan_setspeed(kobj_t obj, void *data, uint32_t speed) 6539230Sgibbs{ 6639230Sgibbs return (uaudio_chan_set_param_speed(data, speed)); 6739230Sgibbs} 6839230Sgibbs 6939230Sgibbsstatic uint32_t 7039230Sgibbsua_chan_setblocksize(kobj_t obj, void *data, uint32_t blocksize) 7139230Sgibbs{ 7239230Sgibbs return (uaudio_chan_set_param_blocksize(data, blocksize)); 7339230Sgibbs} 7439230Sgibbs 7539230Sgibbsstatic int 7639230Sgibbsua_chan_setfragments(kobj_t obj, void *data, uint32_t blocksize, uint32_t blockcount) 7739230Sgibbs{ 7839230Sgibbs return (uaudio_chan_set_param_fragments(data, blocksize, blockcount)); 7939230Sgibbs} 8039230Sgibbs 8139230Sgibbsstatic int 8239230Sgibbsua_chan_trigger(kobj_t obj, void *data, int go) 8339230Sgibbs{ 8439230Sgibbs if (PCMTRIG_COMMON(go)) { 8539230Sgibbs if (go == PCMTRIG_START) { 8639230Sgibbs uaudio_chan_start(data); 8739230Sgibbs } else { 8839230Sgibbs uaudio_chan_stop(data); 8939230Sgibbs } 9039230Sgibbs } 9139230Sgibbs return (0); 9239230Sgibbs} 9339230Sgibbs 9439230Sgibbsstatic uint32_t 9539230Sgibbsua_chan_getptr(kobj_t obj, void *data) 9639230Sgibbs{ 971553Srgrimes return (uaudio_chan_getptr(data)); 981553Srgrimes} 991553Srgrimes 10039230Sgibbsstatic struct pcmchan_caps * 101111008Sphkua_chan_getcaps(kobj_t obj, void *data) 10281134Stmm{ 1031553Srgrimes return (uaudio_chan_getcaps(data)); 104228661Sdim} 105228661Sdim 1061553Srgrimesstatic struct pcmchan_matrix * 1071553Srgrimesua_chan_getmatrix(kobj_t obj, void *data, uint32_t format) 108228661Sdim{ 1091553Srgrimes return (uaudio_chan_getmatrix(data, format)); 110228661Sdim} 111228661Sdim 112102067Sbdestatic kobj_method_t ua_chan_methods[] = { 113293696Sasomers KOBJMETHOD(channel_init, ua_chan_init), 1141553Srgrimes KOBJMETHOD(channel_free, ua_chan_free), 1151553Srgrimes KOBJMETHOD(channel_setformat, ua_chan_setformat), 1161553Srgrimes KOBJMETHOD(channel_setspeed, ua_chan_setspeed), 117175562Skeramida KOBJMETHOD(channel_setblocksize, ua_chan_setblocksize), 1181553Srgrimes KOBJMETHOD(channel_setfragments, ua_chan_setfragments), 1191553Srgrimes KOBJMETHOD(channel_trigger, ua_chan_trigger), 120296995Sasomers KOBJMETHOD(channel_getptr, ua_chan_getptr), 12139230Sgibbs KOBJMETHOD(channel_getcaps, ua_chan_getcaps), 122296995Sasomers KOBJMETHOD(channel_getmatrix, ua_chan_getmatrix), 123296995Sasomers KOBJMETHOD_END 12439230Sgibbs}; 125296995Sasomers 126296995SasomersCHANNEL_DECLARE(ua_chan); 127181881Sjhb 128296995Sasomers/************************************************************/ 129296995Sasomersstatic int 130181881Sjhbua_mixer_init(struct snd_mixer *m) 131296995Sasomers{ 132296995Sasomers return (uaudio_mixer_init_sub(mix_getdevinfo(m), m)); 1331553Srgrimes} 1341553Srgrimes 135175562Skeramidastatic int 136175562Skeramidaua_mixer_set(struct snd_mixer *m, unsigned type, unsigned left, unsigned right) 137296995Sasomers{ 138296995Sasomers struct mtx *mtx = mixer_get_lock(m); 139296995Sasomers uint8_t do_unlock; 140296995Sasomers 141296995Sasomers if (mtx_owned(mtx)) { 142296995Sasomers do_unlock = 0; 143296995Sasomers } else { 144296995Sasomers do_unlock = 1; 145296995Sasomers mtx_lock(mtx); 146296995Sasomers } 147296995Sasomers uaudio_mixer_set(mix_getdevinfo(m), m, type, left, right); 1481553Srgrimes if (do_unlock) { 14939230Sgibbs mtx_unlock(mtx); 15039230Sgibbs } 15183965Sguido return (left | (right << 8)); 152175562Skeramida} 153293696Sasomers 154293696Sasomersstatic uint32_t 155175562Skeramidaua_mixer_setrecsrc(struct snd_mixer *m, uint32_t src) 15683965Sguido{ 15782168Sken struct mtx *mtx = mixer_get_lock(m); 15839230Sgibbs int retval; 15982168Sken uint8_t do_unlock; 16082168Sken 1611553Srgrimes if (mtx_owned(mtx)) { 16239230Sgibbs do_unlock = 0; 16339230Sgibbs } else { 16439230Sgibbs do_unlock = 1; 16539230Sgibbs mtx_lock(mtx); 16639230Sgibbs } 16739230Sgibbs retval = uaudio_mixer_setrecsrc(mix_getdevinfo(m), m, src); 16839230Sgibbs if (do_unlock) { 16939230Sgibbs mtx_unlock(mtx); 17039230Sgibbs } 171157800Smaxim return (retval); 17256561Scharnier} 17356561Scharnier 17439230Sgibbsstatic int 1751553Srgrimesua_mixer_uninit(struct snd_mixer *m) 1761553Srgrimes{ 17739230Sgibbs return (uaudio_mixer_uninit_sub(mix_getdevinfo(m), m)); 1781553Srgrimes} 179157802Smaxim 18039230Sgibbsstatic kobj_method_t ua_mixer_methods[] = { 18139230Sgibbs KOBJMETHOD(mixer_init, ua_mixer_init), 18239230Sgibbs KOBJMETHOD(mixer_uninit, ua_mixer_uninit), 18339230Sgibbs KOBJMETHOD(mixer_set, ua_mixer_set), 184293696Sasomers KOBJMETHOD(mixer_setrecsrc, ua_mixer_setrecsrc), 18539230Sgibbs KOBJMETHOD_END 186157801Smaxim}; 18781134Stmm 18839498SkenMIXER_DECLARE(ua_mixer); 18939230Sgibbs/************************************************************/ 19039498Sken 19139498Sken 19239230Sgibbsstatic int 19339230Sgibbsua_probe(device_t dev) 194208389Ssbruno{ 19582168Sken struct sndcard_func *func; 1961553Srgrimes 19739230Sgibbs /* the parent device has already been probed */ 19839230Sgibbs 19939230Sgibbs func = device_get_ivars(dev); 200157800Smaxim 20139230Sgibbs if ((func == NULL) || 20239230Sgibbs (func->func != SCF_PCM)) { 20339230Sgibbs return (ENXIO); 20439230Sgibbs } 20539230Sgibbs device_set_desc(dev, "USB audio"); 20639230Sgibbs 20739230Sgibbs return (BUS_PROBE_DEFAULT); 20839230Sgibbs} 20939230Sgibbs 21039230Sgibbsstatic int 21139230Sgibbsua_attach(device_t dev) 21239230Sgibbs{ 21339230Sgibbs return (uaudio_attach_sub(dev, &ua_mixer_class, &ua_chan_class)); 21439230Sgibbs} 21539230Sgibbs 21639230Sgibbsstatic int 21739387Skenua_detach(device_t dev) 21839387Sken{ 21939387Sken return (uaudio_detach_sub(dev)); 22039371Sdillon} 22139371Sdillon 22239371Sdillon/************************************************************/ 22339230Sgibbs 22439230Sgibbsstatic device_method_t ua_pcm_methods[] = { 22539230Sgibbs /* Device interface */ 22639230Sgibbs DEVMETHOD(device_probe, ua_probe), 22739230Sgibbs DEVMETHOD(device_attach, ua_attach), 22839230Sgibbs DEVMETHOD(device_detach, ua_detach), 22939230Sgibbs 23056483Scharnier DEVMETHOD_END 23139230Sgibbs}; 23239230Sgibbs 23339230Sgibbsstatic driver_t ua_pcm_driver = { 23439230Sgibbs "pcm", 23539230Sgibbs ua_pcm_methods, 23639230Sgibbs PCM_SOFTC_SIZE, 23739230Sgibbs}; 23839230Sgibbs 23939230SgibbsDRIVER_MODULE(ua_pcm, uaudio, ua_pcm_driver, pcm_devclass, 0, 0); 24039230SgibbsMODULE_DEPEND(ua_pcm, uaudio, 1, 1, 1); 241157801SmaximMODULE_DEPEND(ua_pcm, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); 24281134StmmMODULE_VERSION(ua_pcm, 1); 24339230Sgibbs