hc
2024-08-16 62c46c9150c4afde7e5b25436263fddf79d66f0b
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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
/*
 * u_uac.h - Utility definitions for UAC function
 *
 * Copyright (C) 2016 Ruslan Bilovol <ruslan.bilovol@gmail.com>
 * Copyright (C) 2017 Julian Scheel <julian@juss.de>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */
 
#ifndef __U_UAC_H
#define __U_UAC_H
 
#include <linux/usb/composite.h>
#include "u_audio.h"
 
#define UAC_DEF_CCHMASK        0x3
#define UAC_DEF_CSRATE        48000
#define UAC_DEF_CSSIZE        2
#define UAC_DEF_CFU        0
#define UAC_DEF_PCHMASK        0x3
#define UAC_DEF_PSRATE        48000
#define UAC_DEF_PSSIZE        2
#define UAC_DEF_PFU        0
#define UAC_DEF_REQ_NUM        2
 
#define UAC1_OUT_EP_MAX_PACKET_SIZE 200
 
#define EPIN_EN(_opts) ((_opts)->p_chmask != 0)
#define EPOUT_EN(_opts) ((_opts)->c_chmask != 0)
#define EPIN_FU(_opts) ((_opts)->p_feature_unit != 0)
#define EPOUT_FU(_opts) ((_opts)->c_feature_unit != 0)
 
struct f_uac_opts {
   struct usb_function_instance    func_inst;
   int                c_chmask;
   int                c_srate[UAC_MAX_RATES];
   int                c_srate_active;
   int                c_ssize;
   int                c_feature_unit;
   int                p_chmask;
   int                p_srate[UAC_MAX_RATES];
   int                p_srate_active;
   int                p_ssize;
   int                p_feature_unit;
   int                req_number;
   unsigned            bound:1;
 
   struct mutex            lock;
   int                refcnt;
};
 
#define UAC_ATTRIBUTE(name)                        \
static ssize_t f_uac_opts_##name##_show(                \
                     struct config_item *item,    \
                     char *page)            \
{                                    \
   struct f_uac_opts *opts = to_f_uac_opts(item);        \
   int result;                            \
                                   \
   mutex_lock(&opts->lock);                    \
   result = sprintf(page, "%u\n", opts->name);            \
   mutex_unlock(&opts->lock);                    \
                                   \
   return result;                            \
}                                    \
                                   \
static ssize_t f_uac_opts_##name##_store(                \
                     struct config_item *item,    \
                     const char *page, size_t len)    \
{                                    \
   struct f_uac_opts *opts = to_f_uac_opts(item);        \
   int ret;                            \
   u32 num;                            \
                                   \
   mutex_lock(&opts->lock);                    \
   if (opts->refcnt) {                        \
       ret = -EBUSY;                        \
       goto end;                        \
   }                                \
                                   \
   ret = kstrtou32(page, 0, &num);                    \
   if (ret)                            \
       goto end;                        \
                                   \
   opts->name = num;                        \
   ret = len;                            \
                                   \
end:                                    \
   mutex_unlock(&opts->lock);                    \
   return ret;                            \
}                                    \
                                   \
CONFIGFS_ATTR(f_uac_opts_, name)
 
#define UAC_RATE_ATTRIBUTE(name)                    \
static ssize_t f_uac_opts_##name##_show(struct config_item *item,    \
                    char *page)            \
{                                    \
   struct f_uac_opts *opts = to_f_uac_opts(item);            \
   int result = 0;                            \
   int i;                                \
                                   \
   mutex_lock(&opts->lock);                    \
   page[0] = '\0';                            \
   for (i = 0; i < UAC_MAX_RATES; i++) {                \
       if (opts->name[i] == 0)                    \
           continue;                    \
       result += sprintf(page + strlen(page), "%u,",        \
               opts->name[i]);                \
   }                                \
   if (strlen(page) > 0)                        \
       page[strlen(page) - 1] = '\n';                \
   mutex_unlock(&opts->lock);                    \
                                   \
   return result;                            \
}                                    \
                                   \
static ssize_t f_uac_opts_##name##_store(struct config_item *item,    \
                     const char *page, size_t len)    \
{                                    \
   struct f_uac_opts *opts = to_f_uac_opts(item);            \
   char *split_page = NULL;                    \
   int ret = -EINVAL;                        \
   char *token;                            \
   u32 num;                            \
   int i;                                \
                                   \
   mutex_lock(&opts->lock);                    \
   if (opts->refcnt) {                        \
       ret = -EBUSY;                        \
       goto end;                        \
   }                                \
                                   \
   i = 0;                                \
   memset(opts->name, 0x00, sizeof(opts->name));            \
   split_page = kstrdup(page, GFP_KERNEL);                \
   while ((token = strsep(&split_page, ",")) != NULL) {        \
       ret = kstrtou32(token, 0, &num);            \
       if (ret)                        \
           goto end;                    \
                                   \
       opts->name[i++] = num;                    \
       opts->name##_active = num;                \
       ret = len;                        \
   };                                \
                                   \
end:                                    \
   kfree(split_page);                        \
   mutex_unlock(&opts->lock);                    \
   return ret;                            \
}                                    \
                                   \
CONFIGFS_ATTR(f_uac_opts_, name)
 
struct f_uac {
   struct g_audio g_audio;
   u8 ac_intf, as_in_intf, as_out_intf;
   u8 ac_alt, as_in_alt, as_out_alt;    /* needed for get_alt() */
   int ctl_id;
 
   struct list_head cs;
   u8 set_cmd;
   u8 get_cmd;
   struct usb_audio_control *set_con;
   struct usb_audio_control *get_con;
};
 
static inline struct f_uac *func_to_uac(struct usb_function *f)
{
   return container_of(f, struct f_uac, g_audio.func);
}
 
static inline
struct f_uac_opts *g_audio_to_uac_opts(struct g_audio *agdev)
{
   return container_of(agdev->func.fi, struct f_uac_opts, func_inst);
}
 
static inline struct f_uac_opts *to_f_uac_opts(struct config_item *item)
{
   return container_of(to_config_group(item), struct f_uac_opts,
               func_inst.group);
}
 
static inline void f_uac_attr_release(struct config_item *item)
{
   struct f_uac_opts *opts = to_f_uac_opts(item);
 
   usb_put_function_instance(&opts->func_inst);
}
 
#endif /* __U_UAC_H */