linux/sound/usb/helper.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 */
   4
   5#include <linux/init.h>
   6#include <linux/slab.h>
   7#include <linux/usb.h>
   8
   9#include "usbaudio.h"
  10#include "helper.h"
  11#include "quirks.h"
  12
  13/*
  14 * combine bytes and get an integer value
  15 */
  16unsigned int snd_usb_combine_bytes(unsigned char *bytes, int size)
  17{
  18        switch (size) {
  19        case 1:  return *bytes;
  20        case 2:  return combine_word(bytes);
  21        case 3:  return combine_triple(bytes);
  22        case 4:  return combine_quad(bytes);
  23        default: return 0;
  24        }
  25}
  26
  27/*
  28 * parse descriptor buffer and return the pointer starting the given
  29 * descriptor type.
  30 */
  31void *snd_usb_find_desc(void *descstart, int desclen, void *after, u8 dtype)
  32{
  33        u8 *p, *end, *next;
  34
  35        p = descstart;
  36        end = p + desclen;
  37        for (; p < end;) {
  38                if (p[0] < 2)
  39                        return NULL;
  40                next = p + p[0];
  41                if (next > end)
  42                        return NULL;
  43                if (p[1] == dtype && (!after || (void *)p > after)) {
  44                        return p;
  45                }
  46                p = next;
  47        }
  48        return NULL;
  49}
  50
  51/*
  52 * find a class-specified interface descriptor with the given subtype.
  53 */
  54void *snd_usb_find_csint_desc(void *buffer, int buflen, void *after, u8 dsubtype)
  55{
  56        unsigned char *p = after;
  57
  58        while ((p = snd_usb_find_desc(buffer, buflen, p,
  59                                      USB_DT_CS_INTERFACE)) != NULL) {
  60                if (p[0] >= 3 && p[2] == dsubtype)
  61                        return p;
  62        }
  63        return NULL;
  64}
  65
  66/*
  67 * Wrapper for usb_control_msg().
  68 * Allocates a temp buffer to prevent dmaing from/to the stack.
  69 */
  70int snd_usb_ctl_msg(struct usb_device *dev, unsigned int pipe, __u8 request,
  71                    __u8 requesttype, __u16 value, __u16 index, void *data,
  72                    __u16 size)
  73{
  74        int err;
  75        void *buf = NULL;
  76        int timeout;
  77
  78        if (usb_pipe_type_check(dev, pipe))
  79                return -EINVAL;
  80
  81        if (size > 0) {
  82                buf = kmemdup(data, size, GFP_KERNEL);
  83                if (!buf)
  84                        return -ENOMEM;
  85        }
  86
  87        if (requesttype & USB_DIR_IN)
  88                timeout = USB_CTRL_GET_TIMEOUT;
  89        else
  90                timeout = USB_CTRL_SET_TIMEOUT;
  91
  92        err = usb_control_msg(dev, pipe, request, requesttype,
  93                              value, index, buf, size, timeout);
  94
  95        if (size > 0) {
  96                memcpy(data, buf, size);
  97                kfree(buf);
  98        }
  99
 100        snd_usb_ctl_msg_quirk(dev, pipe, request, requesttype,
 101                              value, index, data, size);
 102
 103        return err;
 104}
 105
 106unsigned char snd_usb_parse_datainterval(struct snd_usb_audio *chip,
 107                                         struct usb_host_interface *alts)
 108{
 109        switch (snd_usb_get_speed(chip->dev)) {
 110        case USB_SPEED_HIGH:
 111        case USB_SPEED_WIRELESS:
 112        case USB_SPEED_SUPER:
 113        case USB_SPEED_SUPER_PLUS:
 114                if (get_endpoint(alts, 0)->bInterval >= 1 &&
 115                    get_endpoint(alts, 0)->bInterval <= 4)
 116                        return get_endpoint(alts, 0)->bInterval - 1;
 117                break;
 118        default:
 119                break;
 120        }
 121        return 0;
 122}
 123
 124struct usb_host_interface *
 125snd_usb_get_host_interface(struct snd_usb_audio *chip, int ifnum, int altsetting)
 126{
 127        struct usb_interface *iface;
 128
 129        iface = usb_ifnum_to_if(chip->dev, ifnum);
 130        if (!iface)
 131                return NULL;
 132        return usb_altnum_to_altsetting(iface, altsetting);
 133}
 134