1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * u_uac.h - Utility definitions for UAC function
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Copyright (C) 2016 Ruslan Bilovol <ruslan.bilovol@gmail.com>
5*4882a593Smuzhiyun * Copyright (C) 2017 Julian Scheel <julian@juss.de>
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * This program is free software; you can redistribute it and/or modify
8*4882a593Smuzhiyun * it under the terms of the GNU General Public License version 2 as
9*4882a593Smuzhiyun * published by the Free Software Foundation.
10*4882a593Smuzhiyun */
11*4882a593Smuzhiyun
12*4882a593Smuzhiyun #ifndef __U_UAC_H
13*4882a593Smuzhiyun #define __U_UAC_H
14*4882a593Smuzhiyun
15*4882a593Smuzhiyun #include <linux/usb/composite.h>
16*4882a593Smuzhiyun #include "u_audio.h"
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun #define UAC_DEF_CCHMASK 0x3
19*4882a593Smuzhiyun #define UAC_DEF_CSRATE 48000
20*4882a593Smuzhiyun #define UAC_DEF_CSSIZE 2
21*4882a593Smuzhiyun #define UAC_DEF_CFU 0
22*4882a593Smuzhiyun #define UAC_DEF_PCHMASK 0x3
23*4882a593Smuzhiyun #define UAC_DEF_PSRATE 48000
24*4882a593Smuzhiyun #define UAC_DEF_PSSIZE 2
25*4882a593Smuzhiyun #define UAC_DEF_PFU 0
26*4882a593Smuzhiyun #define UAC_DEF_REQ_NUM 2
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun #define UAC1_OUT_EP_MAX_PACKET_SIZE 200
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun #define EPIN_EN(_opts) ((_opts)->p_chmask != 0)
31*4882a593Smuzhiyun #define EPOUT_EN(_opts) ((_opts)->c_chmask != 0)
32*4882a593Smuzhiyun #define EPIN_FU(_opts) ((_opts)->p_feature_unit != 0)
33*4882a593Smuzhiyun #define EPOUT_FU(_opts) ((_opts)->c_feature_unit != 0)
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun struct f_uac_opts {
36*4882a593Smuzhiyun struct usb_function_instance func_inst;
37*4882a593Smuzhiyun int c_chmask;
38*4882a593Smuzhiyun int c_srate[UAC_MAX_RATES];
39*4882a593Smuzhiyun int c_srate_active;
40*4882a593Smuzhiyun int c_ssize;
41*4882a593Smuzhiyun int c_feature_unit;
42*4882a593Smuzhiyun int p_chmask;
43*4882a593Smuzhiyun int p_srate[UAC_MAX_RATES];
44*4882a593Smuzhiyun int p_srate_active;
45*4882a593Smuzhiyun int p_ssize;
46*4882a593Smuzhiyun int p_feature_unit;
47*4882a593Smuzhiyun int req_number;
48*4882a593Smuzhiyun unsigned bound:1;
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun struct mutex lock;
51*4882a593Smuzhiyun int refcnt;
52*4882a593Smuzhiyun };
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun #define UAC_ATTRIBUTE(name) \
55*4882a593Smuzhiyun static ssize_t f_uac_opts_##name##_show( \
56*4882a593Smuzhiyun struct config_item *item, \
57*4882a593Smuzhiyun char *page) \
58*4882a593Smuzhiyun { \
59*4882a593Smuzhiyun struct f_uac_opts *opts = to_f_uac_opts(item); \
60*4882a593Smuzhiyun int result; \
61*4882a593Smuzhiyun \
62*4882a593Smuzhiyun mutex_lock(&opts->lock); \
63*4882a593Smuzhiyun result = sprintf(page, "%u\n", opts->name); \
64*4882a593Smuzhiyun mutex_unlock(&opts->lock); \
65*4882a593Smuzhiyun \
66*4882a593Smuzhiyun return result; \
67*4882a593Smuzhiyun } \
68*4882a593Smuzhiyun \
69*4882a593Smuzhiyun static ssize_t f_uac_opts_##name##_store( \
70*4882a593Smuzhiyun struct config_item *item, \
71*4882a593Smuzhiyun const char *page, size_t len) \
72*4882a593Smuzhiyun { \
73*4882a593Smuzhiyun struct f_uac_opts *opts = to_f_uac_opts(item); \
74*4882a593Smuzhiyun int ret; \
75*4882a593Smuzhiyun u32 num; \
76*4882a593Smuzhiyun \
77*4882a593Smuzhiyun mutex_lock(&opts->lock); \
78*4882a593Smuzhiyun if (opts->refcnt) { \
79*4882a593Smuzhiyun ret = -EBUSY; \
80*4882a593Smuzhiyun goto end; \
81*4882a593Smuzhiyun } \
82*4882a593Smuzhiyun \
83*4882a593Smuzhiyun ret = kstrtou32(page, 0, &num); \
84*4882a593Smuzhiyun if (ret) \
85*4882a593Smuzhiyun goto end; \
86*4882a593Smuzhiyun \
87*4882a593Smuzhiyun opts->name = num; \
88*4882a593Smuzhiyun ret = len; \
89*4882a593Smuzhiyun \
90*4882a593Smuzhiyun end: \
91*4882a593Smuzhiyun mutex_unlock(&opts->lock); \
92*4882a593Smuzhiyun return ret; \
93*4882a593Smuzhiyun } \
94*4882a593Smuzhiyun \
95*4882a593Smuzhiyun CONFIGFS_ATTR(f_uac_opts_, name)
96*4882a593Smuzhiyun
97*4882a593Smuzhiyun #define UAC_RATE_ATTRIBUTE(name) \
98*4882a593Smuzhiyun static ssize_t f_uac_opts_##name##_show(struct config_item *item, \
99*4882a593Smuzhiyun char *page) \
100*4882a593Smuzhiyun { \
101*4882a593Smuzhiyun struct f_uac_opts *opts = to_f_uac_opts(item); \
102*4882a593Smuzhiyun int result = 0; \
103*4882a593Smuzhiyun int i; \
104*4882a593Smuzhiyun \
105*4882a593Smuzhiyun mutex_lock(&opts->lock); \
106*4882a593Smuzhiyun page[0] = '\0'; \
107*4882a593Smuzhiyun for (i = 0; i < UAC_MAX_RATES; i++) { \
108*4882a593Smuzhiyun if (opts->name[i] == 0) \
109*4882a593Smuzhiyun continue; \
110*4882a593Smuzhiyun result += sprintf(page + strlen(page), "%u,", \
111*4882a593Smuzhiyun opts->name[i]); \
112*4882a593Smuzhiyun } \
113*4882a593Smuzhiyun if (strlen(page) > 0) \
114*4882a593Smuzhiyun page[strlen(page) - 1] = '\n'; \
115*4882a593Smuzhiyun mutex_unlock(&opts->lock); \
116*4882a593Smuzhiyun \
117*4882a593Smuzhiyun return result; \
118*4882a593Smuzhiyun } \
119*4882a593Smuzhiyun \
120*4882a593Smuzhiyun static ssize_t f_uac_opts_##name##_store(struct config_item *item, \
121*4882a593Smuzhiyun const char *page, size_t len) \
122*4882a593Smuzhiyun { \
123*4882a593Smuzhiyun struct f_uac_opts *opts = to_f_uac_opts(item); \
124*4882a593Smuzhiyun char *split_page = NULL; \
125*4882a593Smuzhiyun int ret = -EINVAL; \
126*4882a593Smuzhiyun char *token; \
127*4882a593Smuzhiyun u32 num; \
128*4882a593Smuzhiyun int i; \
129*4882a593Smuzhiyun \
130*4882a593Smuzhiyun mutex_lock(&opts->lock); \
131*4882a593Smuzhiyun if (opts->refcnt) { \
132*4882a593Smuzhiyun ret = -EBUSY; \
133*4882a593Smuzhiyun goto end; \
134*4882a593Smuzhiyun } \
135*4882a593Smuzhiyun \
136*4882a593Smuzhiyun i = 0; \
137*4882a593Smuzhiyun memset(opts->name, 0x00, sizeof(opts->name)); \
138*4882a593Smuzhiyun split_page = kstrdup(page, GFP_KERNEL); \
139*4882a593Smuzhiyun while ((token = strsep(&split_page, ",")) != NULL) { \
140*4882a593Smuzhiyun ret = kstrtou32(token, 0, &num); \
141*4882a593Smuzhiyun if (ret) \
142*4882a593Smuzhiyun goto end; \
143*4882a593Smuzhiyun \
144*4882a593Smuzhiyun opts->name[i++] = num; \
145*4882a593Smuzhiyun opts->name##_active = num; \
146*4882a593Smuzhiyun ret = len; \
147*4882a593Smuzhiyun }; \
148*4882a593Smuzhiyun \
149*4882a593Smuzhiyun end: \
150*4882a593Smuzhiyun kfree(split_page); \
151*4882a593Smuzhiyun mutex_unlock(&opts->lock); \
152*4882a593Smuzhiyun return ret; \
153*4882a593Smuzhiyun } \
154*4882a593Smuzhiyun \
155*4882a593Smuzhiyun CONFIGFS_ATTR(f_uac_opts_, name)
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun struct f_uac {
158*4882a593Smuzhiyun struct g_audio g_audio;
159*4882a593Smuzhiyun u8 ac_intf, as_in_intf, as_out_intf;
160*4882a593Smuzhiyun u8 ac_alt, as_in_alt, as_out_alt; /* needed for get_alt() */
161*4882a593Smuzhiyun int ctl_id;
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun struct list_head cs;
164*4882a593Smuzhiyun u8 set_cmd;
165*4882a593Smuzhiyun u8 get_cmd;
166*4882a593Smuzhiyun struct usb_audio_control *set_con;
167*4882a593Smuzhiyun struct usb_audio_control *get_con;
168*4882a593Smuzhiyun };
169*4882a593Smuzhiyun
func_to_uac(struct usb_function * f)170*4882a593Smuzhiyun static inline struct f_uac *func_to_uac(struct usb_function *f)
171*4882a593Smuzhiyun {
172*4882a593Smuzhiyun return container_of(f, struct f_uac, g_audio.func);
173*4882a593Smuzhiyun }
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun static inline
g_audio_to_uac_opts(struct g_audio * agdev)176*4882a593Smuzhiyun struct f_uac_opts *g_audio_to_uac_opts(struct g_audio *agdev)
177*4882a593Smuzhiyun {
178*4882a593Smuzhiyun return container_of(agdev->func.fi, struct f_uac_opts, func_inst);
179*4882a593Smuzhiyun }
180*4882a593Smuzhiyun
to_f_uac_opts(struct config_item * item)181*4882a593Smuzhiyun static inline struct f_uac_opts *to_f_uac_opts(struct config_item *item)
182*4882a593Smuzhiyun {
183*4882a593Smuzhiyun return container_of(to_config_group(item), struct f_uac_opts,
184*4882a593Smuzhiyun func_inst.group);
185*4882a593Smuzhiyun }
186*4882a593Smuzhiyun
f_uac_attr_release(struct config_item * item)187*4882a593Smuzhiyun static inline void f_uac_attr_release(struct config_item *item)
188*4882a593Smuzhiyun {
189*4882a593Smuzhiyun struct f_uac_opts *opts = to_f_uac_opts(item);
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun usb_put_function_instance(&opts->func_inst);
192*4882a593Smuzhiyun }
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun #endif /* __U_UAC_H */
195