Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  */
0004 
0005 #include <linux/init.h>
0006 #include <linux/usb.h>
0007 
0008 #include <sound/core.h>
0009 #include <sound/info.h>
0010 #include <sound/pcm.h>
0011 
0012 #include "usbaudio.h"
0013 #include "helper.h"
0014 #include "card.h"
0015 #include "endpoint.h"
0016 #include "proc.h"
0017 
0018 /* convert our full speed USB rate into sampling rate in Hz */
0019 static inline unsigned get_full_speed_hz(unsigned int usb_rate)
0020 {
0021     return (usb_rate * 125 + (1 << 12)) >> 13;
0022 }
0023 
0024 /* convert our high speed USB rate into sampling rate in Hz */
0025 static inline unsigned get_high_speed_hz(unsigned int usb_rate)
0026 {
0027     return (usb_rate * 125 + (1 << 9)) >> 10;
0028 }
0029 
0030 /*
0031  * common proc files to show the usb device info
0032  */
0033 static void proc_audio_usbbus_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
0034 {
0035     struct snd_usb_audio *chip = entry->private_data;
0036     if (!atomic_read(&chip->shutdown))
0037         snd_iprintf(buffer, "%03d/%03d\n", chip->dev->bus->busnum, chip->dev->devnum);
0038 }
0039 
0040 static void proc_audio_usbid_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
0041 {
0042     struct snd_usb_audio *chip = entry->private_data;
0043     if (!atomic_read(&chip->shutdown))
0044         snd_iprintf(buffer, "%04x:%04x\n", 
0045                 USB_ID_VENDOR(chip->usb_id),
0046                 USB_ID_PRODUCT(chip->usb_id));
0047 }
0048 
0049 void snd_usb_audio_create_proc(struct snd_usb_audio *chip)
0050 {
0051     snd_card_ro_proc_new(chip->card, "usbbus", chip,
0052                  proc_audio_usbbus_read);
0053     snd_card_ro_proc_new(chip->card, "usbid", chip,
0054                  proc_audio_usbid_read);
0055 }
0056 
0057 static const char * const channel_labels[] = {
0058     [SNDRV_CHMAP_NA]    = "N/A",
0059     [SNDRV_CHMAP_MONO]  = "MONO",
0060     [SNDRV_CHMAP_FL]    = "FL",
0061     [SNDRV_CHMAP_FR]    = "FR",
0062     [SNDRV_CHMAP_FC]    = "FC",
0063     [SNDRV_CHMAP_LFE]   = "LFE",
0064     [SNDRV_CHMAP_RL]    = "RL",
0065     [SNDRV_CHMAP_RR]    = "RR",
0066     [SNDRV_CHMAP_FLC]   = "FLC",
0067     [SNDRV_CHMAP_FRC]   = "FRC",
0068     [SNDRV_CHMAP_RC]    = "RC",
0069     [SNDRV_CHMAP_SL]    = "SL",
0070     [SNDRV_CHMAP_SR]    = "SR",
0071     [SNDRV_CHMAP_TC]    = "TC",
0072     [SNDRV_CHMAP_TFL]   = "TFL",
0073     [SNDRV_CHMAP_TFC]   = "TFC",
0074     [SNDRV_CHMAP_TFR]   = "TFR",
0075     [SNDRV_CHMAP_TRL]   = "TRL",
0076     [SNDRV_CHMAP_TRC]   = "TRC",
0077     [SNDRV_CHMAP_TRR]   = "TRR",
0078     [SNDRV_CHMAP_TFLC]  = "TFLC",
0079     [SNDRV_CHMAP_TFRC]  = "TFRC",
0080     [SNDRV_CHMAP_LLFE]  = "LLFE",
0081     [SNDRV_CHMAP_RLFE]  = "RLFE",
0082     [SNDRV_CHMAP_TSL]   = "TSL",
0083     [SNDRV_CHMAP_TSR]   = "TSR",
0084     [SNDRV_CHMAP_BC]    = "BC",
0085     [SNDRV_CHMAP_RLC]   = "RLC",
0086     [SNDRV_CHMAP_RRC]   = "RRC",
0087 };
0088 
0089 /*
0090  * proc interface for list the supported pcm formats
0091  */
0092 static void proc_dump_substream_formats(struct snd_usb_substream *subs, struct snd_info_buffer *buffer)
0093 {
0094     struct audioformat *fp;
0095     static const char * const sync_types[4] = {
0096         "NONE", "ASYNC", "ADAPTIVE", "SYNC"
0097     };
0098 
0099     list_for_each_entry(fp, &subs->fmt_list, list) {
0100         snd_pcm_format_t fmt;
0101 
0102         snd_iprintf(buffer, "  Interface %d\n", fp->iface);
0103         snd_iprintf(buffer, "    Altset %d\n", fp->altsetting);
0104         snd_iprintf(buffer, "    Format:");
0105         pcm_for_each_format(fmt)
0106             if (fp->formats & pcm_format_to_bits(fmt))
0107                 snd_iprintf(buffer, " %s",
0108                         snd_pcm_format_name(fmt));
0109         snd_iprintf(buffer, "\n");
0110         snd_iprintf(buffer, "    Channels: %d\n", fp->channels);
0111         snd_iprintf(buffer, "    Endpoint: 0x%02x (%d %s) (%s)\n",
0112                 fp->endpoint,
0113                 fp->endpoint & USB_ENDPOINT_NUMBER_MASK,
0114                 fp->endpoint & USB_DIR_IN ? "IN" : "OUT",
0115                 sync_types[(fp->ep_attr & USB_ENDPOINT_SYNCTYPE) >> 2]);
0116         if (fp->rates & SNDRV_PCM_RATE_CONTINUOUS) {
0117             snd_iprintf(buffer, "    Rates: %d - %d (continuous)\n",
0118                     fp->rate_min, fp->rate_max);
0119         } else {
0120             unsigned int i;
0121             snd_iprintf(buffer, "    Rates: ");
0122             for (i = 0; i < fp->nr_rates; i++) {
0123                 if (i > 0)
0124                     snd_iprintf(buffer, ", ");
0125                 snd_iprintf(buffer, "%d", fp->rate_table[i]);
0126             }
0127             snd_iprintf(buffer, "\n");
0128         }
0129         if (subs->speed != USB_SPEED_FULL)
0130             snd_iprintf(buffer, "    Data packet interval: %d us\n",
0131                     125 * (1 << fp->datainterval));
0132         snd_iprintf(buffer, "    Bits: %d\n", fp->fmt_bits);
0133 
0134         if (fp->dsd_raw)
0135             snd_iprintf(buffer, "    DSD raw: DOP=%d, bitrev=%d\n",
0136                     fp->dsd_dop, fp->dsd_bitrev);
0137 
0138         if (fp->chmap) {
0139             const struct snd_pcm_chmap_elem *map = fp->chmap;
0140             int c;
0141 
0142             snd_iprintf(buffer, "    Channel map:");
0143             for (c = 0; c < map->channels; c++) {
0144                 if (map->map[c] >= ARRAY_SIZE(channel_labels) ||
0145                     !channel_labels[map->map[c]])
0146                     snd_iprintf(buffer, " --");
0147                 else
0148                     snd_iprintf(buffer, " %s",
0149                             channel_labels[map->map[c]]);
0150             }
0151             snd_iprintf(buffer, "\n");
0152         }
0153 
0154         if (fp->sync_ep) {
0155             snd_iprintf(buffer, "    Sync Endpoint: 0x%02x (%d %s)\n",
0156                     fp->sync_ep,
0157                     fp->sync_ep & USB_ENDPOINT_NUMBER_MASK,
0158                     fp->sync_ep & USB_DIR_IN ? "IN" : "OUT");
0159             snd_iprintf(buffer, "    Sync EP Interface: %d\n",
0160                     fp->sync_iface);
0161             snd_iprintf(buffer, "    Sync EP Altset: %d\n",
0162                     fp->sync_altsetting);
0163             snd_iprintf(buffer, "    Implicit Feedback Mode: %s\n",
0164                     fp->implicit_fb ? "Yes" : "No");
0165         }
0166 
0167         // snd_iprintf(buffer, "    Max Packet Size = %d\n", fp->maxpacksize);
0168         // snd_iprintf(buffer, "    EP Attribute = %#x\n", fp->attributes);
0169     }
0170 }
0171 
0172 static void proc_dump_ep_status(struct snd_usb_substream *subs,
0173                 struct snd_usb_endpoint *data_ep,
0174                 struct snd_usb_endpoint *sync_ep,
0175                 struct snd_info_buffer *buffer)
0176 {
0177     if (!data_ep)
0178         return;
0179     snd_iprintf(buffer, "    Packet Size = %d\n", data_ep->curpacksize);
0180     snd_iprintf(buffer, "    Momentary freq = %u Hz (%#x.%04x)\n",
0181             subs->speed == USB_SPEED_FULL
0182             ? get_full_speed_hz(data_ep->freqm)
0183             : get_high_speed_hz(data_ep->freqm),
0184             data_ep->freqm >> 16, data_ep->freqm & 0xffff);
0185     if (sync_ep && data_ep->freqshift != INT_MIN) {
0186         int res = 16 - data_ep->freqshift;
0187         snd_iprintf(buffer, "    Feedback Format = %d.%d\n",
0188                 (sync_ep->syncmaxsize > 3 ? 32 : 24) - res, res);
0189     }
0190 }
0191 
0192 static void proc_dump_substream_status(struct snd_usb_audio *chip,
0193                        struct snd_usb_substream *subs,
0194                        struct snd_info_buffer *buffer)
0195 {
0196     mutex_lock(&chip->mutex);
0197     if (subs->running) {
0198         snd_iprintf(buffer, "  Status: Running\n");
0199         if (subs->cur_audiofmt) {
0200             snd_iprintf(buffer, "    Interface = %d\n", subs->cur_audiofmt->iface);
0201             snd_iprintf(buffer, "    Altset = %d\n", subs->cur_audiofmt->altsetting);
0202         }
0203         proc_dump_ep_status(subs, subs->data_endpoint, subs->sync_endpoint, buffer);
0204     } else {
0205         snd_iprintf(buffer, "  Status: Stop\n");
0206     }
0207     mutex_unlock(&chip->mutex);
0208 }
0209 
0210 static void proc_pcm_format_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
0211 {
0212     struct snd_usb_stream *stream = entry->private_data;
0213     struct snd_usb_audio *chip = stream->chip;
0214 
0215     snd_iprintf(buffer, "%s : %s\n", chip->card->longname, stream->pcm->name);
0216 
0217     if (stream->substream[SNDRV_PCM_STREAM_PLAYBACK].num_formats) {
0218         snd_iprintf(buffer, "\nPlayback:\n");
0219         proc_dump_substream_status(chip, &stream->substream[SNDRV_PCM_STREAM_PLAYBACK], buffer);
0220         proc_dump_substream_formats(&stream->substream[SNDRV_PCM_STREAM_PLAYBACK], buffer);
0221     }
0222     if (stream->substream[SNDRV_PCM_STREAM_CAPTURE].num_formats) {
0223         snd_iprintf(buffer, "\nCapture:\n");
0224         proc_dump_substream_status(chip, &stream->substream[SNDRV_PCM_STREAM_CAPTURE], buffer);
0225         proc_dump_substream_formats(&stream->substream[SNDRV_PCM_STREAM_CAPTURE], buffer);
0226     }
0227 }
0228 
0229 void snd_usb_proc_pcm_format_add(struct snd_usb_stream *stream)
0230 {
0231     char name[32];
0232     struct snd_card *card = stream->chip->card;
0233 
0234     sprintf(name, "stream%d", stream->pcm_index);
0235     snd_card_ro_proc_new(card, name, stream, proc_pcm_format_read);
0236 }
0237