linux/sound/firewire/bebob/bebob_command.c
<<
>>
Prefs
   1/*
   2 * bebob_command.c - driver for BeBoB based devices
   3 *
   4 * Copyright (c) 2013-2014 Takashi Sakamoto
   5 *
   6 * Licensed under the terms of the GNU General Public License, version 2.
   7 */
   8
   9#include "./bebob.h"
  10
  11int avc_audio_set_selector(struct fw_unit *unit, unsigned int subunit_id,
  12                           unsigned int fb_id, unsigned int num)
  13{
  14        u8 *buf;
  15        int err;
  16
  17        buf = kzalloc(12, GFP_KERNEL);
  18        if (buf == NULL)
  19                return -ENOMEM;
  20
  21        buf[0]  = 0x00;         /* AV/C CONTROL */
  22        buf[1]  = 0x08 | (0x07 & subunit_id);   /* AUDIO SUBUNIT ID */
  23        buf[2]  = 0xb8;         /* FUNCTION BLOCK  */
  24        buf[3]  = 0x80;         /* type is 'selector'*/
  25        buf[4]  = 0xff & fb_id; /* function block id */
  26        buf[5]  = 0x10;         /* control attribute is CURRENT */
  27        buf[6]  = 0x02;         /* selector length is 2 */
  28        buf[7]  = 0xff & num;   /* input function block plug number */
  29        buf[8]  = 0x01;         /* control selector is SELECTOR_CONTROL */
  30
  31        err = fcp_avc_transaction(unit, buf, 12, buf, 12,
  32                                  BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) |
  33                                  BIT(6) | BIT(7) | BIT(8));
  34        if (err > 0 && err < 9)
  35                err = -EIO;
  36        else if (buf[0] == 0x08) /* NOT IMPLEMENTED */
  37                err = -ENOSYS;
  38        else if (buf[0] == 0x0a) /* REJECTED */
  39                err = -EINVAL;
  40        else if (err > 0)
  41                err = 0;
  42
  43        kfree(buf);
  44        return err;
  45}
  46
  47int avc_audio_get_selector(struct fw_unit *unit, unsigned int subunit_id,
  48                           unsigned int fb_id, unsigned int *num)
  49{
  50        u8 *buf;
  51        int err;
  52
  53        buf = kzalloc(12, GFP_KERNEL);
  54        if (buf == NULL)
  55                return -ENOMEM;
  56
  57        buf[0]  = 0x01;         /* AV/C STATUS */
  58        buf[1]  = 0x08 | (0x07 & subunit_id);   /* AUDIO SUBUNIT ID */
  59        buf[2]  = 0xb8;         /* FUNCTION BLOCK */
  60        buf[3]  = 0x80;         /* type is 'selector'*/
  61        buf[4]  = 0xff & fb_id; /* function block id */
  62        buf[5]  = 0x10;         /* control attribute is CURRENT */
  63        buf[6]  = 0x02;         /* selector length is 2 */
  64        buf[7]  = 0xff;         /* input function block plug number */
  65        buf[8]  = 0x01;         /* control selector is SELECTOR_CONTROL */
  66
  67        err = fcp_avc_transaction(unit, buf, 12, buf, 12,
  68                                  BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) |
  69                                  BIT(6) | BIT(8));
  70        if (err > 0 && err < 9)
  71                err = -EIO;
  72        else if (buf[0] == 0x08) /* NOT IMPLEMENTED */
  73                err = -ENOSYS;
  74        else if (buf[0] == 0x0a) /* REJECTED */
  75                err = -EINVAL;
  76        else if (buf[0] == 0x0b) /* IN TRANSITION */
  77                err = -EAGAIN;
  78        if (err < 0)
  79                goto end;
  80
  81        *num = buf[7];
  82        err = 0;
  83end:
  84        kfree(buf);
  85        return err;
  86}
  87
  88static inline void
  89avc_bridgeco_fill_extension_addr(u8 *buf, u8 *addr)
  90{
  91        buf[1] = addr[0];
  92        memcpy(buf + 4, addr + 1, 5);
  93}
  94
  95static inline void
  96avc_bridgeco_fill_plug_info_extension_command(u8 *buf, u8 *addr,
  97                                              unsigned int itype)
  98{
  99        buf[0] = 0x01;  /* AV/C STATUS */
 100        buf[2] = 0x02;  /* AV/C GENERAL PLUG INFO */
 101        buf[3] = 0xc0;  /* BridgeCo extension */
 102        avc_bridgeco_fill_extension_addr(buf, addr);
 103        buf[9] = itype; /* info type */
 104}
 105
 106int avc_bridgeco_get_plug_type(struct fw_unit *unit,
 107                               u8 addr[AVC_BRIDGECO_ADDR_BYTES],
 108                               enum avc_bridgeco_plug_type *type)
 109{
 110        u8 *buf;
 111        int err;
 112
 113        buf = kzalloc(12, GFP_KERNEL);
 114        if (buf == NULL)
 115                return -ENOMEM;
 116
 117        /* Info type is 'plug type'. */
 118        avc_bridgeco_fill_plug_info_extension_command(buf, addr, 0x00);
 119
 120        err = fcp_avc_transaction(unit, buf, 12, buf, 12,
 121                                  BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) |
 122                                  BIT(6) | BIT(7) | BIT(9));
 123        if ((err >= 0) && (err < 8))
 124                err = -EIO;
 125        else if (buf[0] == 0x08) /* NOT IMPLEMENTED */
 126                err = -ENOSYS;
 127        else if (buf[0] == 0x0a) /* REJECTED */
 128                err = -EINVAL;
 129        else if (buf[0] == 0x0b) /* IN TRANSITION */
 130                err = -EAGAIN;
 131        if (err < 0)
 132                goto end;
 133
 134        *type = buf[10];
 135        err = 0;
 136end:
 137        kfree(buf);
 138        return err;
 139}
 140
 141int avc_bridgeco_get_plug_ch_pos(struct fw_unit *unit,
 142                                 u8 addr[AVC_BRIDGECO_ADDR_BYTES],
 143                                 u8 *buf, unsigned int len)
 144{
 145        int err;
 146
 147        /* Info type is 'channel position'. */
 148        avc_bridgeco_fill_plug_info_extension_command(buf, addr, 0x03);
 149
 150        err = fcp_avc_transaction(unit, buf, 12, buf, 256,
 151                                  BIT(1) | BIT(2) | BIT(3) | BIT(4) |
 152                                  BIT(5) | BIT(6) | BIT(7) | BIT(9));
 153        if ((err >= 0) && (err < 8))
 154                err = -EIO;
 155        else if (buf[0] == 0x08) /* NOT IMPLEMENTED */
 156                err = -ENOSYS;
 157        else if (buf[0] == 0x0a) /* REJECTED */
 158                err = -EINVAL;
 159        else if (buf[0] == 0x0b) /* IN TRANSITION */
 160                err = -EAGAIN;
 161        if (err < 0)
 162                goto end;
 163
 164        /* Pick up specific data. */
 165        memmove(buf, buf + 10, err - 10);
 166        err = 0;
 167end:
 168        return err;
 169}
 170
 171int avc_bridgeco_get_plug_section_type(struct fw_unit *unit,
 172                                       u8 addr[AVC_BRIDGECO_ADDR_BYTES],
 173                                       unsigned int id, u8 *type)
 174{
 175        u8 *buf;
 176        int err;
 177
 178        /* section info includes charactors but this module don't need it */
 179        buf = kzalloc(12, GFP_KERNEL);
 180        if (buf == NULL)
 181                return -ENOMEM;
 182
 183        /* Info type is 'section info'. */
 184        avc_bridgeco_fill_plug_info_extension_command(buf, addr, 0x07);
 185        buf[10] = 0xff & ++id;  /* section id */
 186
 187        err = fcp_avc_transaction(unit, buf, 12, buf, 12,
 188                                  BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) |
 189                                  BIT(6) | BIT(7) | BIT(9) | BIT(10));
 190        if ((err >= 0) && (err < 8))
 191                err = -EIO;
 192        else if (buf[0] == 0x08) /* NOT IMPLEMENTED */
 193                err = -ENOSYS;
 194        else if (buf[0] == 0x0a) /* REJECTED */
 195                err = -EINVAL;
 196        else if (buf[0] == 0x0b) /* IN TRANSITION */
 197                err = -EAGAIN;
 198        if (err < 0)
 199                goto end;
 200
 201        *type = buf[11];
 202        err = 0;
 203end:
 204        kfree(buf);
 205        return err;
 206}
 207
 208int avc_bridgeco_get_plug_input(struct fw_unit *unit,
 209                                u8 addr[AVC_BRIDGECO_ADDR_BYTES], u8 input[7])
 210{
 211        int err;
 212        u8 *buf;
 213
 214        buf = kzalloc(18, GFP_KERNEL);
 215        if (buf == NULL)
 216                return -ENOMEM;
 217
 218        /* Info type is 'plug input'. */
 219        avc_bridgeco_fill_plug_info_extension_command(buf, addr, 0x05);
 220
 221        err = fcp_avc_transaction(unit, buf, 16, buf, 16,
 222                                  BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) |
 223                                  BIT(6) | BIT(7));
 224        if ((err >= 0) && (err < 8))
 225                err = -EIO;
 226        else if (buf[0] == 0x08) /* NOT IMPLEMENTED */
 227                err = -ENOSYS;
 228        else if (buf[0] == 0x0a) /* REJECTED */
 229                err = -EINVAL;
 230        else if (buf[0] == 0x0b) /* IN TRANSITION */
 231                err = -EAGAIN;
 232        if (err < 0)
 233                goto end;
 234
 235        memcpy(input, buf + 10, 5);
 236        err = 0;
 237end:
 238        kfree(buf);
 239        return err;
 240}
 241
 242int avc_bridgeco_get_plug_strm_fmt(struct fw_unit *unit,
 243                                   u8 addr[AVC_BRIDGECO_ADDR_BYTES], u8 *buf,
 244                                   unsigned int *len, unsigned int eid)
 245{
 246        int err;
 247
 248        /* check given buffer */
 249        if ((buf == NULL) || (*len < 12)) {
 250                err = -EINVAL;
 251                goto end;
 252        }
 253
 254        buf[0] = 0x01;  /* AV/C STATUS */
 255        buf[2] = 0x2f;  /* AV/C STREAM FORMAT SUPPORT */
 256        buf[3] = 0xc1;  /* Bridgeco extension - List Request */
 257        avc_bridgeco_fill_extension_addr(buf, addr);
 258        buf[10] = 0xff & eid;   /* Entry ID */
 259
 260        err = fcp_avc_transaction(unit, buf, 12, buf, *len,
 261                                  BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) |
 262                                  BIT(6) | BIT(7) | BIT(10));
 263        if ((err >= 0) && (err < 12))
 264                err = -EIO;
 265        else if (buf[0] == 0x08)        /* NOT IMPLEMENTED */
 266                err = -ENOSYS;
 267        else if (buf[0] == 0x0a)        /* REJECTED */
 268                err = -EINVAL;
 269        else if (buf[0] == 0x0b)        /* IN TRANSITION */
 270                err = -EAGAIN;
 271        else if (buf[10] != eid)
 272                err = -EIO;
 273        if (err < 0)
 274                goto end;
 275
 276        /* Pick up 'stream format info'. */
 277        memmove(buf, buf + 11, err - 11);
 278        *len = err - 11;
 279        err = 0;
 280end:
 281        return err;
 282}
 283