brintos

brintos / linux-shallow public Read only

0
0
Text · 3.6 KiB · 72b671f Raw
167 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*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 value15 */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 given29 * 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	else90		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_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 123struct usb_host_interface *124snd_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 134int 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 155struct 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