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