linux/sound/usb/helper.c
<<
>>
Prefs
   1/*
   2 *   This program is free software; you can redistribute it and/or modify
   3 *   it under the terms of the GNU General Public License as published by
   4 *   the Free Software Foundation; either version 2 of the License, or
   5 *   (at your option) any later version.
   6 *
   7 *   This program is distributed in the hope that it will be useful,
   8 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   9 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  10 *   GNU General Public License for more details.
  11 *
  12 *   You should have received a copy of the GNU General Public License
  13 *   along with this program; if not, write to the Free Software
  14 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  15 *
  16 */
  17
  18#include <linux/init.h>
  19#include <linux/slab.h>
  20#include <linux/usb.h>
  21
  22#include "usbaudio.h"
  23#include "helper.h"
  24#include "quirks.h"
  25
  26/*
  27 * combine bytes and get an integer value
  28 */
  29unsigned int snd_usb_combine_bytes(unsigned char *bytes, int size)
  30{
  31        switch (size) {
  32        case 1:  return *bytes;
  33        case 2:  return combine_word(bytes);
  34        case 3:  return combine_triple(bytes);
  35        case 4:  return combine_quad(bytes);
  36        default: return 0;
  37        }
  38}
  39
  40/*
  41 * parse descriptor buffer and return the pointer starting the given
  42 * descriptor type.
  43 */
  44void *snd_usb_find_desc(void *descstart, int desclen, void *after, u8 dtype)
  45{
  46        u8 *p, *end, *next;
  47
  48        p = descstart;
  49        end = p + desclen;
  50        for (; p < end;) {
  51                if (p[0] < 2)
  52                        return NULL;
  53                next = p + p[0];
  54                if (next > end)
  55                        return NULL;
  56                if (p[1] == dtype && (!after || (void *)p > after)) {
  57                        return p;
  58                }
  59                p = next;
  60        }
  61        return NULL;
  62}
  63
  64/*
  65 * find a class-specified interface descriptor with the given subtype.
  66 */
  67void *snd_usb_find_csint_desc(void *buffer, int buflen, void *after, u8 dsubtype)
  68{
  69        unsigned char *p = after;
  70
  71        while ((p = snd_usb_find_desc(buffer, buflen, p,
  72                                      USB_DT_CS_INTERFACE)) != NULL) {
  73                if (p[0] >= 3 && p[2] == dsubtype)
  74                        return p;
  75        }
  76        return NULL;
  77}
  78
  79/*
  80 * Wrapper for usb_control_msg().
  81 * Allocates a temp buffer to prevent dmaing from/to the stack.
  82 */
  83int snd_usb_ctl_msg(struct usb_device *dev, unsigned int pipe, __u8 request,
  84                    __u8 requesttype, __u16 value, __u16 index, void *data,
  85                    __u16 size)
  86{
  87        int err;
  88        void *buf = NULL;
  89        int timeout;
  90
  91        if (size > 0) {
  92                buf = kmemdup(data, size, GFP_KERNEL);
  93                if (!buf)
  94                        return -ENOMEM;
  95        }
  96
  97        if (requesttype & USB_DIR_IN)
  98                timeout = USB_CTRL_GET_TIMEOUT;
  99        else
 100                timeout = USB_CTRL_SET_TIMEOUT;
 101
 102        err = usb_control_msg(dev, pipe, request, requesttype,
 103                              value, index, buf, size, timeout);
 104
 105        if (size > 0) {
 106                memcpy(data, buf, size);
 107                kfree(buf);
 108        }
 109
 110        snd_usb_ctl_msg_quirk(dev, pipe, request, requesttype,
 111                              value, index, data, size);
 112
 113        return err;
 114}
 115
 116unsigned char snd_usb_parse_datainterval(struct snd_usb_audio *chip,
 117                                         struct usb_host_interface *alts)
 118{
 119        switch (snd_usb_get_speed(chip->dev)) {
 120        case USB_SPEED_HIGH:
 121        case USB_SPEED_WIRELESS:
 122        case USB_SPEED_SUPER:
 123                if (get_endpoint(alts, 0)->bInterval >= 1 &&
 124                    get_endpoint(alts, 0)->bInterval <= 4)
 125                        return get_endpoint(alts, 0)->bInterval - 1;
 126                break;
 127        default:
 128                break;
 129        }
 130        return 0;
 131}
 132
 133