root/sound/usb/helper.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. snd_usb_combine_bytes
  2. snd_usb_find_desc
  3. snd_usb_find_csint_desc
  4. snd_usb_pipe_sanity_check
  5. snd_usb_ctl_msg
  6. snd_usb_parse_datainterval

   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  */
  16 unsigned 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  */
  31 void *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  */
  54 void *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 /* check the validity of pipe and EP types */
  67 int snd_usb_pipe_sanity_check(struct usb_device *dev, unsigned int pipe)
  68 {
  69         static const int pipetypes[4] = {
  70                 PIPE_CONTROL, PIPE_ISOCHRONOUS, PIPE_BULK, PIPE_INTERRUPT
  71         };
  72         struct usb_host_endpoint *ep;
  73 
  74         ep = usb_pipe_endpoint(dev, pipe);
  75         if (!ep || usb_pipetype(pipe) != pipetypes[usb_endpoint_type(&ep->desc)])
  76                 return -EINVAL;
  77         return 0;
  78 }
  79 
  80 /*
  81  * Wrapper for usb_control_msg().
  82  * Allocates a temp buffer to prevent dmaing from/to the stack.
  83  */
  84 int snd_usb_ctl_msg(struct usb_device *dev, unsigned int pipe, __u8 request,
  85                     __u8 requesttype, __u16 value, __u16 index, void *data,
  86                     __u16 size)
  87 {
  88         int err;
  89         void *buf = NULL;
  90         int timeout;
  91 
  92         if (snd_usb_pipe_sanity_check(dev, pipe))
  93                 return -EINVAL;
  94 
  95         if (size > 0) {
  96                 buf = kmemdup(data, size, GFP_KERNEL);
  97                 if (!buf)
  98                         return -ENOMEM;
  99         }
 100 
 101         if (requesttype & USB_DIR_IN)
 102                 timeout = USB_CTRL_GET_TIMEOUT;
 103         else
 104                 timeout = USB_CTRL_SET_TIMEOUT;
 105 
 106         err = usb_control_msg(dev, pipe, request, requesttype,
 107                               value, index, buf, size, timeout);
 108 
 109         if (size > 0) {
 110                 memcpy(data, buf, size);
 111                 kfree(buf);
 112         }
 113 
 114         snd_usb_ctl_msg_quirk(dev, pipe, request, requesttype,
 115                               value, index, data, size);
 116 
 117         return err;
 118 }
 119 
 120 unsigned char snd_usb_parse_datainterval(struct snd_usb_audio *chip,
 121                                          struct usb_host_interface *alts)
 122 {
 123         switch (snd_usb_get_speed(chip->dev)) {
 124         case USB_SPEED_HIGH:
 125         case USB_SPEED_WIRELESS:
 126         case USB_SPEED_SUPER:
 127         case USB_SPEED_SUPER_PLUS:
 128                 if (get_endpoint(alts, 0)->bInterval >= 1 &&
 129                     get_endpoint(alts, 0)->bInterval <= 4)
 130                         return get_endpoint(alts, 0)->bInterval - 1;
 131                 break;
 132         default:
 133                 break;
 134         }
 135         return 0;
 136 }
 137 

/* [<][>][^][v][top][bottom][index][help] */