diff options
author | Andrzej Pietrasiewicz <andrzej.p@samsung.com> | 2015-03-03 04:52:32 -0500 |
---|---|---|
committer | Felipe Balbi <balbi@ti.com> | 2015-03-10 16:33:41 -0400 |
commit | ee1cd515e889d222f5a7397fead0a9db1214edea (patch) | |
tree | 8946a1608e69546a85d4311ca6ab5bdcd3852a3f /drivers/usb/gadget/function | |
parent | a2a8e48a94c78c72b5dd1e4c8d190c5c54aca7a4 (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.c | 130 | ||||
-rw-r--r-- | drivers/usb/gadget/function/u_printer.h | 7 |
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 | ||
1143 | static 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 | |||
1150 | CONFIGFS_ATTR_STRUCT(f_printer_opts); | ||
1151 | CONFIGFS_ATTR_OPS(f_printer_opts); | ||
1152 | |||
1153 | static 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 | |||
1160 | static 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 | |||
1166 | static 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 | |||
1178 | static 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 | |||
1193 | static 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 | |||
1198 | static 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 | |||
1210 | static 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; | ||
1233 | end: | ||
1234 | mutex_unlock(&opts->lock); | ||
1235 | return ret; | ||
1236 | } | ||
1237 | |||
1238 | static 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 | |||
1242 | static struct configfs_attribute *printer_attrs[] = { | ||
1243 | &f_printer_opts_pnp_string.attr, | ||
1244 | &f_printer_opts_q_len.attr, | ||
1245 | NULL, | ||
1246 | }; | ||
1247 | |||
1248 | static 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 | |||
1143 | static inline int gprinter_get_minor(void) | 1254 | static 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 | ||
1205 | unlock: | 1319 | unlock: |
1206 | mutex_unlock(&printer_ida_lock); | 1320 | mutex_unlock(&printer_ida_lock); |
@@ -1210,8 +1324,13 @@ unlock: | |||
1210 | static void gprinter_free(struct usb_function *f) | 1324 | static 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 | ||
1217 | static void printer_func_unbind(struct usb_configuration *c, | 1336 | static 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 */ |