aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/gadget/function
diff options
context:
space:
mode:
authorAndrzej Pietrasiewicz <andrzej.p@samsung.com>2015-03-03 04:52:32 -0500
committerFelipe Balbi <balbi@ti.com>2015-03-10 16:33:41 -0400
commitee1cd515e889d222f5a7397fead0a9db1214edea (patch)
tree8946a1608e69546a85d4311ca6ab5bdcd3852a3f /drivers/usb/gadget/function
parenta2a8e48a94c78c72b5dd1e4c8d190c5c54aca7a4 (diff)
usb: gadget: printer: add configfs support
Add support for configfs interface so that f_printer can be used as a component of usb gadgets composed with it. Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@samsung.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers/usb/gadget/function')
-rw-r--r--drivers/usb/gadget/function/f_printer.c130
-rw-r--r--drivers/usb/gadget/function/u_printer.h7
2 files changed, 135 insertions, 2 deletions
diff --git a/drivers/usb/gadget/function/f_printer.c b/drivers/usb/gadget/function/f_printer.c
index 7afe17d76f17..757fcf070013 100644
--- a/drivers/usb/gadget/function/f_printer.c
+++ b/drivers/usb/gadget/function/f_printer.c
@@ -1140,6 +1140,117 @@ static void printer_func_disable(struct usb_function *f)
1140 spin_unlock_irqrestore(&dev->lock, flags); 1140 spin_unlock_irqrestore(&dev->lock, flags);
1141} 1141}
1142 1142
1143static inline struct f_printer_opts
1144*to_f_printer_opts(struct config_item *item)
1145{
1146 return container_of(to_config_group(item), struct f_printer_opts,
1147 func_inst.group);
1148}
1149
1150CONFIGFS_ATTR_STRUCT(f_printer_opts);
1151CONFIGFS_ATTR_OPS(f_printer_opts);
1152
1153static void printer_attr_release(struct config_item *item)
1154{
1155 struct f_printer_opts *opts = to_f_printer_opts(item);
1156
1157 usb_put_function_instance(&opts->func_inst);
1158}
1159
1160static struct configfs_item_operations printer_item_ops = {
1161 .release = printer_attr_release,
1162 .show_attribute = f_printer_opts_attr_show,
1163 .store_attribute = f_printer_opts_attr_store,
1164};
1165
1166static ssize_t f_printer_opts_pnp_string_show(struct f_printer_opts *opts,
1167 char *page)
1168{
1169 int result;
1170
1171 mutex_lock(&opts->lock);
1172 result = strlcpy(page, opts->pnp_string + 2, PNP_STRING_LEN - 2);
1173 mutex_unlock(&opts->lock);
1174
1175 return result;
1176}
1177
1178static ssize_t f_printer_opts_pnp_string_store(struct f_printer_opts *opts,
1179 const char *page, size_t len)
1180{
1181 int result, l;
1182
1183 mutex_lock(&opts->lock);
1184 result = strlcpy(opts->pnp_string + 2, page, PNP_STRING_LEN - 2);
1185 l = strlen(opts->pnp_string + 2) + 2;
1186 opts->pnp_string[0] = (l >> 8) & 0xFF;
1187 opts->pnp_string[1] = l & 0xFF;
1188 mutex_unlock(&opts->lock);
1189
1190 return result;
1191}
1192
1193static struct f_printer_opts_attribute f_printer_opts_pnp_string =
1194 __CONFIGFS_ATTR(pnp_string, S_IRUGO | S_IWUSR,
1195 f_printer_opts_pnp_string_show,
1196 f_printer_opts_pnp_string_store);
1197
1198static ssize_t f_printer_opts_q_len_show(struct f_printer_opts *opts,
1199 char *page)
1200{
1201 int result;
1202
1203 mutex_lock(&opts->lock);
1204 result = sprintf(page, "%d\n", opts->q_len);
1205 mutex_unlock(&opts->lock);
1206
1207 return result;
1208}
1209
1210static ssize_t f_printer_opts_q_len_store(struct f_printer_opts *opts,
1211 const char *page, size_t len)
1212{
1213 int ret;
1214 u16 num;
1215
1216 mutex_lock(&opts->lock);
1217 if (opts->refcnt) {
1218 ret = -EBUSY;
1219 goto end;
1220 }
1221
1222 ret = kstrtou16(page, 0, &num);
1223 if (ret)
1224 goto end;
1225
1226 if (num > 65535) {
1227 ret = -EINVAL;
1228 goto end;
1229 }
1230
1231 opts->q_len = (unsigned)num;
1232 ret = len;
1233end:
1234 mutex_unlock(&opts->lock);
1235 return ret;
1236}
1237
1238static struct f_printer_opts_attribute f_printer_opts_q_len =
1239 __CONFIGFS_ATTR(q_len, S_IRUGO | S_IWUSR, f_printer_opts_q_len_show,
1240 f_printer_opts_q_len_store);
1241
1242static struct configfs_attribute *printer_attrs[] = {
1243 &f_printer_opts_pnp_string.attr,
1244 &f_printer_opts_q_len.attr,
1245 NULL,
1246};
1247
1248static struct config_item_type printer_func_type = {
1249 .ct_item_ops = &printer_item_ops,
1250 .ct_attrs = printer_attrs,
1251 .ct_owner = THIS_MODULE,
1252};
1253
1143static inline int gprinter_get_minor(void) 1254static inline int gprinter_get_minor(void)
1144{ 1255{
1145 return ida_simple_get(&printer_ida, 0, 0, GFP_KERNEL); 1256 return ida_simple_get(&printer_ida, 0, 0, GFP_KERNEL);
@@ -1180,6 +1291,7 @@ static struct usb_function_instance *gprinter_alloc_inst(void)
1180 if (!opts) 1291 if (!opts)
1181 return ERR_PTR(-ENOMEM); 1292 return ERR_PTR(-ENOMEM);
1182 1293
1294 mutex_init(&opts->lock);
1183 opts->func_inst.free_func_inst = gprinter_free_inst; 1295 opts->func_inst.free_func_inst = gprinter_free_inst;
1184 ret = &opts->func_inst; 1296 ret = &opts->func_inst;
1185 1297
@@ -1201,6 +1313,8 @@ static struct usb_function_instance *gprinter_alloc_inst(void)
1201 if (idr_is_empty(&printer_ida.idr)) 1313 if (idr_is_empty(&printer_ida.idr))
1202 gprinter_cleanup(); 1314 gprinter_cleanup();
1203 } 1315 }
1316 config_group_init_type_name(&opts->func_inst.group, "",
1317 &printer_func_type);
1204 1318
1205unlock: 1319unlock:
1206 mutex_unlock(&printer_ida_lock); 1320 mutex_unlock(&printer_ida_lock);
@@ -1210,8 +1324,13 @@ unlock:
1210static void gprinter_free(struct usb_function *f) 1324static void gprinter_free(struct usb_function *f)
1211{ 1325{
1212 struct printer_dev *dev = func_to_printer(f); 1326 struct printer_dev *dev = func_to_printer(f);
1327 struct f_printer_opts *opts;
1213 1328
1329 opts = container_of(f->fi, struct f_printer_opts, func_inst);
1214 kfree(dev); 1330 kfree(dev);
1331 mutex_lock(&opts->lock);
1332 --opts->refcnt;
1333 mutex_unlock(&opts->lock);
1215} 1334}
1216 1335
1217static void printer_func_unbind(struct usb_configuration *c, 1336static void printer_func_unbind(struct usb_configuration *c,
@@ -1265,16 +1384,23 @@ static struct usb_function *gprinter_alloc(struct usb_function_instance *fi)
1265 1384
1266 opts = container_of(fi, struct f_printer_opts, func_inst); 1385 opts = container_of(fi, struct f_printer_opts, func_inst);
1267 1386
1268 if (opts->minor >= minors) 1387 mutex_lock(&opts->lock);
1388 if (opts->minor >= minors) {
1389 mutex_unlock(&opts->lock);
1269 return ERR_PTR(-ENOENT); 1390 return ERR_PTR(-ENOENT);
1391 }
1270 1392
1271 dev = kzalloc(sizeof(*dev), GFP_KERNEL); 1393 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
1272 if (!dev) 1394 if (!dev) {
1395 mutex_unlock(&opts->lock);
1273 return ERR_PTR(-ENOMEM); 1396 return ERR_PTR(-ENOMEM);
1397 }
1274 1398
1399 ++opts->refcnt;
1275 dev->minor = opts->minor; 1400 dev->minor = opts->minor;
1276 dev->pnp_string = opts->pnp_string; 1401 dev->pnp_string = opts->pnp_string;
1277 dev->q_len = opts->q_len; 1402 dev->q_len = opts->q_len;
1403 mutex_unlock(&opts->lock);
1278 1404
1279 dev->function.name = "printer"; 1405 dev->function.name = "printer";
1280 dev->function.bind = printer_func_bind; 1406 dev->function.bind = printer_func_bind;
diff --git a/drivers/usb/gadget/function/u_printer.h b/drivers/usb/gadget/function/u_printer.h
index b2338cacdfe4..0e2c49d4274e 100644
--- a/drivers/usb/gadget/function/u_printer.h
+++ b/drivers/usb/gadget/function/u_printer.h
@@ -25,6 +25,13 @@ struct f_printer_opts {
25 int minor; 25 int minor;
26 char pnp_string[PNP_STRING_LEN]; 26 char pnp_string[PNP_STRING_LEN];
27 unsigned q_len; 27 unsigned q_len;
28
29 /*
30 * Protect the data from concurrent access by read/write
31 * and create symlink/remove symlink
32 */
33 struct mutex lock;
34 int refcnt;
28}; 35};
29 36
30#endif /* U_PRINTER_H */ 37#endif /* U_PRINTER_H */