|
94 | 94 | #include "f_uac1.c"
|
95 | 95 | #endif
|
96 | 96 | #include "f_ncm.c"
|
| 97 | +#include "f_fs.c" |
97 | 98 |
|
98 | 99 | MODULE_AUTHOR("Mike Lockwood");
|
99 | 100 | MODULE_DESCRIPTION("Android Composite USB Driver");
|
@@ -207,6 +208,8 @@ struct android_dev {
|
207 | 208 | struct pm_qos_request pm_qos_req_dma;
|
208 | 209 | struct work_struct work;
|
209 | 210 |
|
| 211 | + char ffs_aliases[256]; |
| 212 | + |
210 | 213 | /* A list of struct android_configuration */
|
211 | 214 | struct list_head configs;
|
212 | 215 | int configs_num;
|
@@ -235,6 +238,7 @@ struct android_configuration {
|
235 | 238 |
|
236 | 239 | struct dload_struct __iomem *diag_dload;
|
237 | 240 | static struct class *android_class;
|
| 241 | +static struct android_dev *_android_dev; |
238 | 242 | static struct list_head android_dev_list;
|
239 | 243 | static int android_dev_count;
|
240 | 244 | static int android_bind_config(struct usb_configuration *c);
|
@@ -2159,6 +2163,162 @@ static struct android_usb_function usbnet_function = {
|
2159 | 2163 | .ctrlrequest = usbnet_function_ctrlrequest,
|
2160 | 2164 | };
|
2161 | 2165 |
|
| 2166 | +/* functionfs */ |
| 2167 | +struct functionfs_config { |
| 2168 | + bool opened; |
| 2169 | + bool enabled; |
| 2170 | + struct ffs_data *data; |
| 2171 | +}; |
| 2172 | + |
| 2173 | +static int functionfs_check_dev_callback(const char *dev_name) |
| 2174 | +{ |
| 2175 | + return 0; |
| 2176 | +} |
| 2177 | + |
| 2178 | +static int ffs_function_init(struct android_usb_function *f, |
| 2179 | + struct usb_composite_dev *cdev) |
| 2180 | +{ |
| 2181 | + if(!_android_dev) |
| 2182 | + _android_dev = cdev_to_android_dev(cdev); |
| 2183 | + |
| 2184 | + f->config = kzalloc(sizeof(struct functionfs_config), GFP_KERNEL); |
| 2185 | + if (!f->config) |
| 2186 | + return -ENOMEM; |
| 2187 | + |
| 2188 | + return functionfs_init(); |
| 2189 | +} |
| 2190 | + |
| 2191 | +static void ffs_function_cleanup(struct android_usb_function *f) |
| 2192 | +{ |
| 2193 | + functionfs_cleanup(); |
| 2194 | + kfree(f->config); |
| 2195 | + _android_dev = NULL; |
| 2196 | +} |
| 2197 | + |
| 2198 | +static void ffs_function_enable(struct android_usb_function *f) |
| 2199 | +{ |
| 2200 | + struct android_dev *dev = _android_dev; |
| 2201 | + struct functionfs_config *config = f->config; |
| 2202 | + |
| 2203 | + config->enabled = true; |
| 2204 | + |
| 2205 | + /* Disable the gadget until the function is ready */ |
| 2206 | + if (!config->opened) |
| 2207 | + android_disable(dev); |
| 2208 | +} |
| 2209 | + |
| 2210 | +static void ffs_function_disable(struct android_usb_function *f) |
| 2211 | +{ |
| 2212 | + struct android_dev *dev = _android_dev; |
| 2213 | + struct functionfs_config *config = f->config; |
| 2214 | + |
| 2215 | + config->enabled = false; |
| 2216 | + |
| 2217 | + /* Balance the disable that was called in closed_callback */ |
| 2218 | + if (!config->opened) |
| 2219 | + android_enable(dev); |
| 2220 | +} |
| 2221 | + |
| 2222 | +static int ffs_function_bind_config(struct android_usb_function *f, |
| 2223 | + struct usb_configuration *c) |
| 2224 | +{ |
| 2225 | + struct functionfs_config *config = f->config; |
| 2226 | + return functionfs_bind_config(c->cdev, c, config->data); |
| 2227 | +} |
| 2228 | + |
| 2229 | +static ssize_t |
| 2230 | +ffs_aliases_show(struct device *pdev, struct device_attribute *attr, char *buf) |
| 2231 | +{ |
| 2232 | + struct android_dev *dev = _android_dev; |
| 2233 | + int ret; |
| 2234 | + |
| 2235 | + mutex_lock(&dev->mutex); |
| 2236 | + ret = sprintf(buf, "%s\n", dev->ffs_aliases); |
| 2237 | + mutex_unlock(&dev->mutex); |
| 2238 | + |
| 2239 | + return ret; |
| 2240 | +} |
| 2241 | + |
| 2242 | +static ssize_t |
| 2243 | +ffs_aliases_store(struct device *pdev, struct device_attribute *attr, |
| 2244 | + const char *buf, size_t size) |
| 2245 | +{ |
| 2246 | + struct android_dev *dev = _android_dev; |
| 2247 | + char buff[256]; |
| 2248 | + |
| 2249 | + mutex_lock(&dev->mutex); |
| 2250 | + |
| 2251 | + if (dev->enabled) { |
| 2252 | + mutex_unlock(&dev->mutex); |
| 2253 | + return -EBUSY; |
| 2254 | + } |
| 2255 | + |
| 2256 | + strlcpy(buff, buf, sizeof(buff)); |
| 2257 | + strlcpy(dev->ffs_aliases, strim(buff), sizeof(dev->ffs_aliases)); |
| 2258 | + |
| 2259 | + mutex_unlock(&dev->mutex); |
| 2260 | + |
| 2261 | + return size; |
| 2262 | +} |
| 2263 | + |
| 2264 | +static DEVICE_ATTR(aliases, S_IRUGO | S_IWUSR, ffs_aliases_show, |
| 2265 | + ffs_aliases_store); |
| 2266 | +static struct device_attribute *ffs_function_attributes[] = { |
| 2267 | + &dev_attr_aliases, |
| 2268 | + NULL |
| 2269 | +}; |
| 2270 | + |
| 2271 | +static struct android_usb_function ffs_function = { |
| 2272 | + .name = "ffs", |
| 2273 | + .init = ffs_function_init, |
| 2274 | + .enable = ffs_function_enable, |
| 2275 | + .disable = ffs_function_disable, |
| 2276 | + .cleanup = ffs_function_cleanup, |
| 2277 | + .bind_config = ffs_function_bind_config, |
| 2278 | + .attributes = ffs_function_attributes, |
| 2279 | +}; |
| 2280 | + |
| 2281 | +static int functionfs_ready_callback(struct ffs_data *ffs) |
| 2282 | +{ |
| 2283 | + struct android_dev *dev = _android_dev; |
| 2284 | + struct functionfs_config *config = ffs_function.config; |
| 2285 | + int ret = 0; |
| 2286 | + |
| 2287 | + mutex_lock(&dev->mutex); |
| 2288 | + |
| 2289 | + ret = functionfs_bind(ffs, dev->cdev); |
| 2290 | + if (ret) |
| 2291 | + goto err; |
| 2292 | + |
| 2293 | + config->data = ffs; |
| 2294 | + config->opened = true; |
| 2295 | + |
| 2296 | + if (config->enabled) |
| 2297 | + android_enable(dev); |
| 2298 | + |
| 2299 | +err: |
| 2300 | + mutex_unlock(&dev->mutex); |
| 2301 | + return ret; |
| 2302 | +} |
| 2303 | + |
| 2304 | +static void functionfs_closed_callback(struct ffs_data *ffs) |
| 2305 | +{ |
| 2306 | + struct android_dev *dev =_android_dev; |
| 2307 | + struct functionfs_config *config = ffs_function.config; |
| 2308 | + |
| 2309 | + mutex_lock(&dev->mutex); |
| 2310 | + |
| 2311 | + if (config->enabled) |
| 2312 | + android_disable(dev); |
| 2313 | + |
| 2314 | + config->opened = false; |
| 2315 | + config->data = NULL; |
| 2316 | + |
| 2317 | + functionfs_unbind(ffs); |
| 2318 | + |
| 2319 | + mutex_unlock(&dev->mutex); |
| 2320 | +} |
| 2321 | + |
2162 | 2322 | static struct android_usb_function *supported_functions[] = {
|
2163 | 2323 | &mbim_function,
|
2164 | 2324 | &ecm_qc_function,
|
@@ -2189,6 +2349,7 @@ static struct android_usb_function *supported_functions[] = {
|
2189 | 2349 | #endif
|
2190 | 2350 | &uasp_function,
|
2191 | 2351 | &usbnet_function,
|
| 2352 | + &ffs_function, |
2192 | 2353 | NULL
|
2193 | 2354 | };
|
2194 | 2355 |
|
@@ -2465,9 +2626,12 @@ functions_store(struct device *pdev, struct device_attribute *attr,
|
2465 | 2626 | struct android_configuration *conf;
|
2466 | 2627 | char *conf_str;
|
2467 | 2628 | struct android_usb_function_holder *f_holder;
|
2468 |
| - char *name; |
| 2629 | + char *name = NULL; |
| 2630 | + char aliases[256], *a; |
2469 | 2631 | char buf[256], *b;
|
2470 | 2632 | int err;
|
| 2633 | + int is_ffs; |
| 2634 | + int ffs_enabled = 0; |
2471 | 2635 |
|
2472 | 2636 | mutex_lock(&dev->mutex);
|
2473 | 2637 |
|
@@ -2510,12 +2674,35 @@ functions_store(struct device *pdev, struct device_attribute *attr,
|
2510 | 2674 |
|
2511 | 2675 | while (conf_str) {
|
2512 | 2676 | name = strsep(&conf_str, ",");
|
2513 |
| - if (name) { |
2514 |
| - err = android_enable_function(dev, conf, name); |
2515 |
| - if (err) |
2516 |
| - pr_err("android_usb: Cannot enable %s", |
2517 |
| - name); |
2518 |
| - } |
| 2677 | + if (!name) |
| 2678 | + continue; |
| 2679 | + |
| 2680 | + is_ffs = 0; |
| 2681 | + strlcpy(aliases, dev->ffs_aliases, sizeof(aliases)); |
| 2682 | + a = aliases; |
| 2683 | + |
| 2684 | + while (a) { |
| 2685 | + char *alias = strsep(&a, ","); |
| 2686 | + if (alias && !strcmp(name, alias)) { |
| 2687 | + is_ffs = 1; |
| 2688 | + break; |
| 2689 | + } |
| 2690 | + } |
| 2691 | + |
| 2692 | + if (is_ffs) { |
| 2693 | + if (ffs_enabled) |
| 2694 | + continue; |
| 2695 | + err = android_enable_function(dev, conf, "ffs"); |
| 2696 | + if (err) |
| 2697 | + pr_err("android_usb: Cannot enable ffs (%d)", err); |
| 2698 | + else |
| 2699 | + ffs_enabled = 1; |
| 2700 | + continue; |
| 2701 | + } |
| 2702 | + |
| 2703 | + err = android_enable_function(dev, conf, name); |
| 2704 | + if (err) |
| 2705 | + pr_err("android_usb: Cannot enable %s (%d)", name, err); |
2519 | 2706 | }
|
2520 | 2707 | }
|
2521 | 2708 |
|
|
0 commit comments