xref: /linux/sound/usb/helper.c (revision c7546e2c3cb739a3c1a2f5acaf9bb629d401afe5)
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 /*
67  * Wrapper for usb_control_msg().
68  * Allocates a temp buffer to prevent dmaing from/to the stack.
69  */
70 int 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 
106 unsigned 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_SUPER:
112 	case USB_SPEED_SUPER_PLUS:
113 		if (get_endpoint(alts, 0)->bInterval >= 1 &&
114 		    get_endpoint(alts, 0)->bInterval <= 4)
115 			return get_endpoint(alts, 0)->bInterval - 1;
116 		break;
117 	default:
118 		break;
119 	}
120 	return 0;
121 }
122 
123 struct usb_host_interface *
124 snd_usb_get_host_interface(struct snd_usb_audio *chip, int ifnum, int altsetting)
125 {
126 	struct usb_interface *iface;
127 
128 	iface = usb_ifnum_to_if(chip->dev, ifnum);
129 	if (!iface)
130 		return NULL;
131 	return usb_altnum_to_altsetting(iface, altsetting);
132 }
133 
134 int snd_usb_add_ctrl_interface_link(struct snd_usb_audio *chip, int ifnum,
135 		int ctrlif)
136 {
137 	struct usb_device *dev = chip->dev;
138 	struct usb_host_interface *host_iface;
139 
140 	if (chip->num_intf_to_ctrl >= MAX_CARD_INTERFACES) {
141 		dev_info(&dev->dev, "Too many interfaces assigned to the single USB-audio card\n");
142 		return -EINVAL;
143 	}
144 
145 	/* find audiocontrol interface */
146 	host_iface = &usb_ifnum_to_if(dev, ctrlif)->altsetting[0];
147 
148 	chip->intf_to_ctrl[chip->num_intf_to_ctrl].interface = ifnum;
149 	chip->intf_to_ctrl[chip->num_intf_to_ctrl].ctrl_intf = host_iface;
150 	chip->num_intf_to_ctrl++;
151 
152 	return 0;
153 }
154 
155 struct usb_host_interface *snd_usb_find_ctrl_interface(struct snd_usb_audio *chip,
156 							int ifnum)
157 {
158 	int i;
159 
160 	for (i = 0; i < chip->num_intf_to_ctrl; ++i)
161 		if (chip->intf_to_ctrl[i].interface == ifnum)
162 			return chip->intf_to_ctrl[i].ctrl_intf;
163 
164 	/* Fallback to first audiocontrol interface */
165 	return chip->ctrl_intf;
166 }
167