The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/sound/usb/uaudio_pcm.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /* $FreeBSD$ */
    2 
    3 /*-
    4  * Copyright (c) 2000-2002 Hiroyuki Aizu <aizu@navi.org>
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  */
   27 
   28 
   29 #include <sys/soundcard.h>
   30 #include <dev/sound/pcm/sound.h>
   31 #include <dev/sound/chip.h>
   32 
   33 #include <dev/sound/usb/uaudio.h>
   34 
   35 #include "mixer_if.h"
   36 
   37 struct ua_info;
   38 
   39 struct ua_chinfo {
   40         struct ua_info *parent;
   41         struct pcm_channel *channel;
   42         struct snd_dbuf *buffer;
   43         int dir, hwch;
   44         u_int32_t fmt, spd, blksz;      /* XXXXX */
   45 };
   46 
   47 struct ua_info {
   48         device_t sc_dev;
   49         struct ua_chinfo pch, rch;
   50         bus_dma_tag_t   parent_dmat;
   51 };
   52 
   53 static u_int32_t ua_playfmt[8*2+1]; /* 8 format * (stereo or mono) + endptr */
   54 
   55 static struct pcmchan_caps ua_playcaps = {8000, 48000, ua_playfmt, 0};
   56 
   57 static u_int32_t ua_recfmt[8*2+1]; /* 8 format * (stereo or mono) + endptr */
   58 
   59 static struct pcmchan_caps ua_reccaps = {8000, 48000, ua_recfmt, 0};
   60 
   61 #define UAUDIO_PCM_BUFF_SIZE    16*1024
   62 
   63 /************************************************************/
   64 static void *
   65 ua_chan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
   66 {
   67         device_t pa_dev;
   68         u_char *buf,*end;
   69 
   70         struct ua_info *sc = devinfo;
   71         struct ua_chinfo *ch = (dir == PCMDIR_PLAY)? &sc->pch : &sc->rch;
   72 
   73         ch->parent = sc;
   74         ch->channel = c;
   75         ch->buffer = b;
   76         ch->dir = dir;
   77 
   78         pa_dev = device_get_parent(sc->sc_dev);
   79         /* Create ua_playfmt[] & ua_recfmt[] */
   80         uaudio_query_formats(pa_dev, (u_int32_t *)&ua_playfmt, (u_int32_t *)&ua_recfmt);
   81         if (dir == PCMDIR_PLAY) {
   82                 if (ua_playfmt[0] == 0) {
   83                         printf("play channel supported format list invalid\n");
   84                         return NULL;
   85                 }
   86         } else {
   87                 if (ua_recfmt[0] == 0) {
   88                         printf("record channel supported format list invalid\n");
   89                         return NULL;
   90                 }
   91 
   92         }
   93 
   94         /* allocate PCM side DMA buffer */
   95         if (sndbuf_alloc(ch->buffer, sc->parent_dmat, UAUDIO_PCM_BUFF_SIZE) != 0) {
   96             return NULL;
   97         }
   98 
   99         buf = end = sndbuf_getbuf(b);
  100         end += sndbuf_getsize(b);
  101         uaudio_chan_set_param_pcm_dma_buff(pa_dev, buf, end, ch->channel, dir);
  102 
  103         ch->dir = dir;
  104 #ifndef NO_RECORDING
  105         ch->hwch = 1;
  106         if (dir == PCMDIR_PLAY)
  107                 ch->hwch = 2;
  108 #else
  109         ch->hwch = 2;
  110 #endif
  111 
  112         return ch;
  113 }
  114 
  115 static int
  116 ua_chan_setformat(kobj_t obj, void *data, u_int32_t format)
  117 {
  118         device_t pa_dev;
  119         struct ua_info *ua;
  120 
  121         struct ua_chinfo *ch = data;
  122 
  123         ua = ch->parent;
  124         pa_dev = device_get_parent(ua->sc_dev);
  125         uaudio_chan_set_param_format(pa_dev, format, ch->dir);
  126 
  127         ch->fmt = format;
  128         return 0;
  129 }
  130 
  131 static int
  132 ua_chan_setspeed(kobj_t obj, void *data, u_int32_t speed)
  133 {
  134         device_t pa_dev;
  135         struct ua_info *ua;
  136 
  137         struct ua_chinfo *ch = data;
  138         ch->spd = speed;
  139 
  140         ua = ch->parent;
  141         pa_dev = device_get_parent(ua->sc_dev);
  142         uaudio_chan_set_param_speed(pa_dev, speed, ch->dir);
  143 
  144         return ch->spd;
  145 }
  146 
  147 static int
  148 ua_chan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
  149 {
  150         device_t pa_dev;
  151         struct ua_info *ua;
  152         struct ua_chinfo *ch = data;
  153         /* ch->blksz = blocksize; */
  154         if (blocksize) {
  155                 ch->blksz = blocksize;
  156         } else {
  157                 ch->blksz = UAUDIO_PCM_BUFF_SIZE/2;
  158         }
  159 
  160         /* XXXXX */
  161         ua = ch->parent;
  162         pa_dev = device_get_parent(ua->sc_dev);
  163         uaudio_chan_set_param_blocksize(pa_dev, blocksize, ch->dir);
  164 
  165         return ch->blksz;
  166 }
  167 
  168 static int
  169 ua_chan_trigger(kobj_t obj, void *data, int go)
  170 {
  171         device_t pa_dev;
  172         struct ua_info *ua;
  173         struct ua_chinfo *ch = data;
  174 
  175         if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD)
  176                 return 0;
  177 
  178         ua = ch->parent;
  179         pa_dev = device_get_parent(ua->sc_dev);
  180 
  181         /* XXXXX */
  182         if (ch->dir == PCMDIR_PLAY) {
  183                 if (go == PCMTRIG_START) {
  184                         uaudio_trigger_output(pa_dev);
  185                 } else {
  186                         uaudio_halt_out_dma(pa_dev);
  187                 }
  188         } else {
  189 #ifndef NO_RECORDING
  190                 if (go == PCMTRIG_START)
  191                         uaudio_trigger_input(pa_dev);
  192                 else
  193                         uaudio_halt_in_dma(pa_dev);
  194 #endif
  195         }
  196 
  197         return 0;
  198 }
  199 
  200 static int
  201 ua_chan_getptr(kobj_t obj, void *data)
  202 {
  203         device_t pa_dev;
  204         struct ua_info *ua;
  205         struct ua_chinfo *ch = data;
  206 
  207         ua = ch->parent;
  208         pa_dev = device_get_parent(ua->sc_dev);
  209 
  210         return uaudio_chan_getptr(pa_dev, ch->dir);
  211 }
  212 
  213 static struct pcmchan_caps *
  214 ua_chan_getcaps(kobj_t obj, void *data)
  215 {
  216         struct ua_chinfo *ch = data;
  217 
  218         return (ch->dir == PCMDIR_PLAY) ? &ua_playcaps : & ua_reccaps;
  219 }
  220 
  221 static kobj_method_t ua_chan_methods[] = {
  222         KOBJMETHOD(channel_init,                ua_chan_init),
  223         KOBJMETHOD(channel_setformat,           ua_chan_setformat),
  224         KOBJMETHOD(channel_setspeed,            ua_chan_setspeed),
  225         KOBJMETHOD(channel_setblocksize,        ua_chan_setblocksize),
  226         KOBJMETHOD(channel_trigger,             ua_chan_trigger),
  227         KOBJMETHOD(channel_getptr,              ua_chan_getptr),
  228         KOBJMETHOD(channel_getcaps,             ua_chan_getcaps),
  229         { 0, 0 }
  230 };
  231 
  232 CHANNEL_DECLARE(ua_chan);
  233 
  234 /************************************************************/
  235 static int
  236 ua_mixer_init(struct snd_mixer *m)
  237 {
  238         u_int32_t mask;
  239         device_t pa_dev;
  240         struct ua_info *ua = mix_getdevinfo(m);
  241 
  242         pa_dev = device_get_parent(ua->sc_dev);
  243 
  244         mask = uaudio_query_mix_info(pa_dev);
  245         mix_setdevs(m,  mask);
  246 
  247         mask = uaudio_query_recsrc_info(pa_dev);
  248         mix_setrecdevs(m, mask);
  249 
  250         return 0;
  251 }
  252 
  253 static int
  254 ua_mixer_set(struct snd_mixer *m, unsigned type, unsigned left, unsigned right)
  255 {
  256         device_t pa_dev;
  257         struct ua_info *ua = mix_getdevinfo(m);
  258 
  259         pa_dev = device_get_parent(ua->sc_dev);
  260         uaudio_mixer_set(pa_dev, type, left, right);
  261 
  262         return left | (right << 8);
  263 }
  264 
  265 static int
  266 ua_mixer_setrecsrc(struct snd_mixer *m, u_int32_t src)
  267 {
  268         device_t pa_dev;
  269         struct ua_info *ua = mix_getdevinfo(m);
  270 
  271         pa_dev = device_get_parent(ua->sc_dev);
  272         return uaudio_mixer_setrecsrc(pa_dev, src);
  273 }
  274 
  275 static kobj_method_t ua_mixer_methods[] = {
  276         KOBJMETHOD(mixer_init,          ua_mixer_init),
  277         KOBJMETHOD(mixer_set,           ua_mixer_set),
  278         KOBJMETHOD(mixer_setrecsrc,     ua_mixer_setrecsrc),
  279 
  280         { 0, 0 }
  281 };
  282 MIXER_DECLARE(ua_mixer);
  283 /************************************************************/
  284 
  285 
  286 static int
  287 ua_probe(device_t dev)
  288 {
  289         char *s;
  290         struct sndcard_func *func;
  291 
  292         /* The parent device has already been probed. */
  293 
  294         func = device_get_ivars(dev);
  295         if (func == NULL || func->func != SCF_PCM)
  296                 return (ENXIO);
  297 
  298         s = "USB Audio";
  299 
  300         device_set_desc(dev, s);
  301         return 0;
  302 }
  303 
  304 static int
  305 ua_attach(device_t dev)
  306 {
  307         struct ua_info *ua;
  308         char status[SND_STATUSLEN];
  309         unsigned int bufsz;
  310 
  311         ua = (struct ua_info *)malloc(sizeof *ua, M_DEVBUF, M_NOWAIT);
  312         if (!ua)
  313                 return ENXIO;
  314         bzero(ua, sizeof *ua);
  315 
  316         ua->sc_dev = dev;
  317 
  318         bufsz = pcm_getbuffersize(dev, 4096, UAUDIO_PCM_BUFF_SIZE, 65536);
  319 
  320         if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0,
  321                                 /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
  322                                 /*highaddr*/BUS_SPACE_MAXADDR,
  323                                 /*filter*/NULL, /*filterarg*/NULL,
  324                                 /*maxsize*/bufsz, /*nsegments*/1,
  325                                 /*maxsegz*/0x4000, /*flags*/0,
  326                                 /*lockfunc*/busdma_lock_mutex,
  327                                 /*lockarg*/&Giant,
  328                                 &ua->parent_dmat) != 0) {
  329                 device_printf(dev, "unable to create dma tag\n");
  330                 goto bad;
  331         }
  332 
  333         if (mixer_init(dev, &ua_mixer_class, ua)) {
  334                 return(ENXIO);
  335         }
  336 
  337         snprintf(status, SND_STATUSLEN, "at addr ?");
  338 
  339 #ifndef NO_RECORDING
  340         if (pcm_register(dev, ua, 1, 1)) {
  341 #else
  342         if (pcm_register(dev, ua, 1, 0)) {
  343 #endif
  344                 return(ENXIO);
  345         }
  346 
  347         pcm_addchan(dev, PCMDIR_PLAY, &ua_chan_class, ua);
  348 #ifndef NO_RECORDING
  349         pcm_addchan(dev, PCMDIR_REC, &ua_chan_class, ua);
  350 #endif
  351         pcm_setstatus(dev, status);
  352 
  353         return 0;
  354 bad:
  355         if (ua->parent_dmat)
  356                 bus_dma_tag_destroy(ua->parent_dmat);
  357         free(ua, M_DEVBUF);
  358 
  359         return ENXIO;
  360 }
  361 
  362 static int
  363 ua_detach(device_t dev)
  364 {
  365         int r;
  366         struct ua_info *sc;
  367 
  368         r = pcm_unregister(dev);
  369         if (r)
  370                 return r;
  371 
  372         sc = pcm_getdevinfo(dev);
  373         bus_dma_tag_destroy(sc->parent_dmat);
  374         free(sc, M_DEVBUF);
  375 
  376         return 0;
  377 }
  378 
  379 /************************************************************/
  380 
  381 static device_method_t ua_pcm_methods[] = {
  382         /* Device interface */
  383         DEVMETHOD(device_probe,         ua_probe),
  384         DEVMETHOD(device_attach,        ua_attach),
  385         DEVMETHOD(device_detach,        ua_detach),
  386 
  387         { 0, 0 }
  388 };
  389 
  390 static driver_t ua_pcm_driver = {
  391         "pcm",
  392         ua_pcm_methods,
  393         PCM_SOFTC_SIZE,
  394 };
  395 
  396 
  397 DRIVER_MODULE(ua_pcm, uaudio, ua_pcm_driver, pcm_devclass, 0, 0);
  398 MODULE_DEPEND(ua_pcm, uaudio, 1, 1, 1);
  399 MODULE_DEPEND(ua_pcm, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
  400 MODULE_VERSION(ua_pcm, 1);

Cache object: 77d112f06626fa08797b74d2694d3387


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.