19a44c1ccSLoic Poulain // SPDX-License-Identifier: GPL-2.0-only 29a44c1ccSLoic Poulain /* Copyright (c) 2021, Linaro Ltd <loic.poulain@linaro.org> */ 39a44c1ccSLoic Poulain 49a44c1ccSLoic Poulain #include <linux/err.h> 59a44c1ccSLoic Poulain #include <linux/errno.h> 69a44c1ccSLoic Poulain #include <linux/fs.h> 79a44c1ccSLoic Poulain #include <linux/init.h> 89a44c1ccSLoic Poulain #include <linux/idr.h> 99a44c1ccSLoic Poulain #include <linux/kernel.h> 109a44c1ccSLoic Poulain #include <linux/module.h> 119a44c1ccSLoic Poulain #include <linux/poll.h> 129a44c1ccSLoic Poulain #include <linux/skbuff.h> 139a44c1ccSLoic Poulain #include <linux/slab.h> 149a44c1ccSLoic Poulain #include <linux/types.h> 159a44c1ccSLoic Poulain #include <linux/wwan.h> 169a44c1ccSLoic Poulain 179a44c1ccSLoic Poulain #define WWAN_MAX_MINORS 256 /* 256 minors allowed with register_chrdev() */ 189a44c1ccSLoic Poulain 199a44c1ccSLoic Poulain static DEFINE_MUTEX(wwan_register_lock); /* WWAN device create|remove lock */ 209a44c1ccSLoic Poulain static DEFINE_IDA(minors); /* minors for WWAN port chardevs */ 219a44c1ccSLoic Poulain static DEFINE_IDA(wwan_dev_ids); /* for unique WWAN device IDs */ 229a44c1ccSLoic Poulain static struct class *wwan_class; 239a44c1ccSLoic Poulain static int wwan_major; 249a44c1ccSLoic Poulain 259a44c1ccSLoic Poulain #define to_wwan_dev(d) container_of(d, struct wwan_device, dev) 269a44c1ccSLoic Poulain #define to_wwan_port(d) container_of(d, struct wwan_port, dev) 279a44c1ccSLoic Poulain 289a44c1ccSLoic Poulain /* WWAN port flags */ 29b8c55ce2SLoic Poulain #define WWAN_PORT_TX_OFF 0 309a44c1ccSLoic Poulain 319a44c1ccSLoic Poulain /** 329a44c1ccSLoic Poulain * struct wwan_device - The structure that defines a WWAN device 339a44c1ccSLoic Poulain * 349a44c1ccSLoic Poulain * @id: WWAN device unique ID. 359a44c1ccSLoic Poulain * @dev: Underlying device. 369a44c1ccSLoic Poulain */ 379a44c1ccSLoic Poulain struct wwan_device { 389a44c1ccSLoic Poulain unsigned int id; 399a44c1ccSLoic Poulain struct device dev; 409a44c1ccSLoic Poulain }; 419a44c1ccSLoic Poulain 429a44c1ccSLoic Poulain /** 439a44c1ccSLoic Poulain * struct wwan_port - The structure that defines a WWAN port 449a44c1ccSLoic Poulain * @type: Port type 459a44c1ccSLoic Poulain * @start_count: Port start counter 469a44c1ccSLoic Poulain * @flags: Store port state and capabilities 479a44c1ccSLoic Poulain * @ops: Pointer to WWAN port operations 489a44c1ccSLoic Poulain * @ops_lock: Protect port ops 499a44c1ccSLoic Poulain * @dev: Underlying device 509a44c1ccSLoic Poulain * @rxq: Buffer inbound queue 519a44c1ccSLoic Poulain * @waitqueue: The waitqueue for port fops (read/write/poll) 529a44c1ccSLoic Poulain */ 539a44c1ccSLoic Poulain struct wwan_port { 549a44c1ccSLoic Poulain enum wwan_port_type type; 559a44c1ccSLoic Poulain unsigned int start_count; 569a44c1ccSLoic Poulain unsigned long flags; 579a44c1ccSLoic Poulain const struct wwan_port_ops *ops; 589a44c1ccSLoic Poulain struct mutex ops_lock; /* Serialize ops + protect against removal */ 599a44c1ccSLoic Poulain struct device dev; 609a44c1ccSLoic Poulain struct sk_buff_head rxq; 619a44c1ccSLoic Poulain wait_queue_head_t waitqueue; 629a44c1ccSLoic Poulain }; 639a44c1ccSLoic Poulain 64e4e92ee7SLoic Poulain static ssize_t index_show(struct device *dev, struct device_attribute *attr, char *buf) 65e4e92ee7SLoic Poulain { 66e4e92ee7SLoic Poulain struct wwan_device *wwan = to_wwan_dev(dev); 67e4e92ee7SLoic Poulain 68e4e92ee7SLoic Poulain return sprintf(buf, "%d\n", wwan->id); 69e4e92ee7SLoic Poulain } 70e4e92ee7SLoic Poulain static DEVICE_ATTR_RO(index); 71e4e92ee7SLoic Poulain 72e4e92ee7SLoic Poulain static struct attribute *wwan_dev_attrs[] = { 73e4e92ee7SLoic Poulain &dev_attr_index.attr, 74e4e92ee7SLoic Poulain NULL, 75e4e92ee7SLoic Poulain }; 76e4e92ee7SLoic Poulain ATTRIBUTE_GROUPS(wwan_dev); 77e4e92ee7SLoic Poulain 789a44c1ccSLoic Poulain static void wwan_dev_destroy(struct device *dev) 799a44c1ccSLoic Poulain { 809a44c1ccSLoic Poulain struct wwan_device *wwandev = to_wwan_dev(dev); 819a44c1ccSLoic Poulain 829a44c1ccSLoic Poulain ida_free(&wwan_dev_ids, wwandev->id); 839a44c1ccSLoic Poulain kfree(wwandev); 849a44c1ccSLoic Poulain } 859a44c1ccSLoic Poulain 869a44c1ccSLoic Poulain static const struct device_type wwan_dev_type = { 879a44c1ccSLoic Poulain .name = "wwan_dev", 889a44c1ccSLoic Poulain .release = wwan_dev_destroy, 89e4e92ee7SLoic Poulain .groups = wwan_dev_groups, 909a44c1ccSLoic Poulain }; 919a44c1ccSLoic Poulain 929a44c1ccSLoic Poulain static int wwan_dev_parent_match(struct device *dev, const void *parent) 939a44c1ccSLoic Poulain { 949a44c1ccSLoic Poulain return (dev->type == &wwan_dev_type && dev->parent == parent); 959a44c1ccSLoic Poulain } 969a44c1ccSLoic Poulain 979a44c1ccSLoic Poulain static struct wwan_device *wwan_dev_get_by_parent(struct device *parent) 989a44c1ccSLoic Poulain { 999a44c1ccSLoic Poulain struct device *dev; 1009a44c1ccSLoic Poulain 1019a44c1ccSLoic Poulain dev = class_find_device(wwan_class, NULL, parent, wwan_dev_parent_match); 1029a44c1ccSLoic Poulain if (!dev) 1039a44c1ccSLoic Poulain return ERR_PTR(-ENODEV); 1049a44c1ccSLoic Poulain 1059a44c1ccSLoic Poulain return to_wwan_dev(dev); 1069a44c1ccSLoic Poulain } 1079a44c1ccSLoic Poulain 1089a44c1ccSLoic Poulain /* This function allocates and registers a new WWAN device OR if a WWAN device 1099a44c1ccSLoic Poulain * already exist for the given parent, it gets a reference and return it. 1109a44c1ccSLoic Poulain * This function is not exported (for now), it is called indirectly via 1119a44c1ccSLoic Poulain * wwan_create_port(). 1129a44c1ccSLoic Poulain */ 1139a44c1ccSLoic Poulain static struct wwan_device *wwan_create_dev(struct device *parent) 1149a44c1ccSLoic Poulain { 1159a44c1ccSLoic Poulain struct wwan_device *wwandev; 1169a44c1ccSLoic Poulain int err, id; 1179a44c1ccSLoic Poulain 1189a44c1ccSLoic Poulain /* The 'find-alloc-register' operation must be protected against 1199a44c1ccSLoic Poulain * concurrent execution, a WWAN device is possibly shared between 1209a44c1ccSLoic Poulain * multiple callers or concurrently unregistered from wwan_remove_dev(). 1219a44c1ccSLoic Poulain */ 1229a44c1ccSLoic Poulain mutex_lock(&wwan_register_lock); 1239a44c1ccSLoic Poulain 1249a44c1ccSLoic Poulain /* If wwandev already exists, return it */ 1259a44c1ccSLoic Poulain wwandev = wwan_dev_get_by_parent(parent); 1269a44c1ccSLoic Poulain if (!IS_ERR(wwandev)) 1279a44c1ccSLoic Poulain goto done_unlock; 1289a44c1ccSLoic Poulain 1299a44c1ccSLoic Poulain id = ida_alloc(&wwan_dev_ids, GFP_KERNEL); 1309a44c1ccSLoic Poulain if (id < 0) 1319a44c1ccSLoic Poulain goto done_unlock; 1329a44c1ccSLoic Poulain 1339a44c1ccSLoic Poulain wwandev = kzalloc(sizeof(*wwandev), GFP_KERNEL); 1349a44c1ccSLoic Poulain if (!wwandev) { 1359a44c1ccSLoic Poulain ida_free(&wwan_dev_ids, id); 1369a44c1ccSLoic Poulain goto done_unlock; 1379a44c1ccSLoic Poulain } 1389a44c1ccSLoic Poulain 1399a44c1ccSLoic Poulain wwandev->dev.parent = parent; 1409a44c1ccSLoic Poulain wwandev->dev.class = wwan_class; 1419a44c1ccSLoic Poulain wwandev->dev.type = &wwan_dev_type; 1429a44c1ccSLoic Poulain wwandev->id = id; 1439a44c1ccSLoic Poulain dev_set_name(&wwandev->dev, "wwan%d", wwandev->id); 1449a44c1ccSLoic Poulain 1459a44c1ccSLoic Poulain err = device_register(&wwandev->dev); 1469a44c1ccSLoic Poulain if (err) { 1479a44c1ccSLoic Poulain put_device(&wwandev->dev); 1489a44c1ccSLoic Poulain wwandev = NULL; 1499a44c1ccSLoic Poulain } 1509a44c1ccSLoic Poulain 1519a44c1ccSLoic Poulain done_unlock: 1529a44c1ccSLoic Poulain mutex_unlock(&wwan_register_lock); 1539a44c1ccSLoic Poulain 1549a44c1ccSLoic Poulain return wwandev; 1559a44c1ccSLoic Poulain } 1569a44c1ccSLoic Poulain 1579a44c1ccSLoic Poulain static int is_wwan_child(struct device *dev, void *data) 1589a44c1ccSLoic Poulain { 1599a44c1ccSLoic Poulain return dev->class == wwan_class; 1609a44c1ccSLoic Poulain } 1619a44c1ccSLoic Poulain 1629a44c1ccSLoic Poulain static void wwan_remove_dev(struct wwan_device *wwandev) 1639a44c1ccSLoic Poulain { 1649a44c1ccSLoic Poulain int ret; 1659a44c1ccSLoic Poulain 1669a44c1ccSLoic Poulain /* Prevent concurrent picking from wwan_create_dev */ 1679a44c1ccSLoic Poulain mutex_lock(&wwan_register_lock); 1689a44c1ccSLoic Poulain 1699a44c1ccSLoic Poulain /* WWAN device is created and registered (get+add) along with its first 1709a44c1ccSLoic Poulain * child port, and subsequent port registrations only grab a reference 1719a44c1ccSLoic Poulain * (get). The WWAN device must then be unregistered (del+put) along with 1729a44c1ccSLoic Poulain * its latest port, and reference simply dropped (put) otherwise. 1739a44c1ccSLoic Poulain */ 1749a44c1ccSLoic Poulain ret = device_for_each_child(&wwandev->dev, NULL, is_wwan_child); 1759a44c1ccSLoic Poulain if (!ret) 1769a44c1ccSLoic Poulain device_unregister(&wwandev->dev); 1779a44c1ccSLoic Poulain else 1789a44c1ccSLoic Poulain put_device(&wwandev->dev); 1799a44c1ccSLoic Poulain 1809a44c1ccSLoic Poulain mutex_unlock(&wwan_register_lock); 1819a44c1ccSLoic Poulain } 1829a44c1ccSLoic Poulain 1839a44c1ccSLoic Poulain /* ------- WWAN port management ------- */ 1849a44c1ccSLoic Poulain 185392c26f7SSergey Ryazanov static const struct { 186392c26f7SSergey Ryazanov const char * const name; /* Port type name */ 187392c26f7SSergey Ryazanov const char * const devsuf; /* Port devce name suffix */ 188392c26f7SSergey Ryazanov } wwan_port_types[WWAN_PORT_MAX + 1] = { 189392c26f7SSergey Ryazanov [WWAN_PORT_AT] = { 190392c26f7SSergey Ryazanov .name = "AT", 191392c26f7SSergey Ryazanov .devsuf = "at", 192392c26f7SSergey Ryazanov }, 193392c26f7SSergey Ryazanov [WWAN_PORT_MBIM] = { 194392c26f7SSergey Ryazanov .name = "MBIM", 195392c26f7SSergey Ryazanov .devsuf = "mbim", 196392c26f7SSergey Ryazanov }, 197392c26f7SSergey Ryazanov [WWAN_PORT_QMI] = { 198392c26f7SSergey Ryazanov .name = "QMI", 199392c26f7SSergey Ryazanov .devsuf = "qmi", 200392c26f7SSergey Ryazanov }, 201392c26f7SSergey Ryazanov [WWAN_PORT_QCDM] = { 202392c26f7SSergey Ryazanov .name = "QCDM", 203392c26f7SSergey Ryazanov .devsuf = "qcdm", 204392c26f7SSergey Ryazanov }, 205392c26f7SSergey Ryazanov [WWAN_PORT_FIREHOSE] = { 206392c26f7SSergey Ryazanov .name = "FIREHOSE", 207392c26f7SSergey Ryazanov .devsuf = "firehose", 208392c26f7SSergey Ryazanov }, 209b3e22e10SLoic Poulain }; 210b3e22e10SLoic Poulain 211b3e22e10SLoic Poulain static ssize_t type_show(struct device *dev, struct device_attribute *attr, 212b3e22e10SLoic Poulain char *buf) 213b3e22e10SLoic Poulain { 214b3e22e10SLoic Poulain struct wwan_port *port = to_wwan_port(dev); 215b3e22e10SLoic Poulain 216392c26f7SSergey Ryazanov return sprintf(buf, "%s\n", wwan_port_types[port->type].name); 217b3e22e10SLoic Poulain } 218b3e22e10SLoic Poulain static DEVICE_ATTR_RO(type); 219b3e22e10SLoic Poulain 220b3e22e10SLoic Poulain static struct attribute *wwan_port_attrs[] = { 221b3e22e10SLoic Poulain &dev_attr_type.attr, 222b3e22e10SLoic Poulain NULL, 223b3e22e10SLoic Poulain }; 224b3e22e10SLoic Poulain ATTRIBUTE_GROUPS(wwan_port); 225b3e22e10SLoic Poulain 2269a44c1ccSLoic Poulain static void wwan_port_destroy(struct device *dev) 2279a44c1ccSLoic Poulain { 2289a44c1ccSLoic Poulain struct wwan_port *port = to_wwan_port(dev); 2299a44c1ccSLoic Poulain 2309a44c1ccSLoic Poulain ida_free(&minors, MINOR(port->dev.devt)); 2319a44c1ccSLoic Poulain skb_queue_purge(&port->rxq); 2329a44c1ccSLoic Poulain mutex_destroy(&port->ops_lock); 2339a44c1ccSLoic Poulain kfree(port); 2349a44c1ccSLoic Poulain } 2359a44c1ccSLoic Poulain 2369a44c1ccSLoic Poulain static const struct device_type wwan_port_dev_type = { 2379a44c1ccSLoic Poulain .name = "wwan_port", 2389a44c1ccSLoic Poulain .release = wwan_port_destroy, 239b3e22e10SLoic Poulain .groups = wwan_port_groups, 2409a44c1ccSLoic Poulain }; 2419a44c1ccSLoic Poulain 2429a44c1ccSLoic Poulain static int wwan_port_minor_match(struct device *dev, const void *minor) 2439a44c1ccSLoic Poulain { 2449a44c1ccSLoic Poulain return (dev->type == &wwan_port_dev_type && 2459a44c1ccSLoic Poulain MINOR(dev->devt) == *(unsigned int *)minor); 2469a44c1ccSLoic Poulain } 2479a44c1ccSLoic Poulain 2489a44c1ccSLoic Poulain static struct wwan_port *wwan_port_get_by_minor(unsigned int minor) 2499a44c1ccSLoic Poulain { 2509a44c1ccSLoic Poulain struct device *dev; 2519a44c1ccSLoic Poulain 2529a44c1ccSLoic Poulain dev = class_find_device(wwan_class, NULL, &minor, wwan_port_minor_match); 2539a44c1ccSLoic Poulain if (!dev) 2549a44c1ccSLoic Poulain return ERR_PTR(-ENODEV); 2559a44c1ccSLoic Poulain 2569a44c1ccSLoic Poulain return to_wwan_port(dev); 2579a44c1ccSLoic Poulain } 2589a44c1ccSLoic Poulain 259*f458709fSSergey Ryazanov /* Allocate and set unique name based on passed format 260*f458709fSSergey Ryazanov * 261*f458709fSSergey Ryazanov * Name allocation approach is highly inspired by the __dev_alloc_name() 262*f458709fSSergey Ryazanov * function. 263*f458709fSSergey Ryazanov * 264*f458709fSSergey Ryazanov * To avoid names collision, the caller must prevent the new port device 265*f458709fSSergey Ryazanov * registration as well as concurrent invocation of this function. 266*f458709fSSergey Ryazanov */ 267*f458709fSSergey Ryazanov static int __wwan_port_dev_assign_name(struct wwan_port *port, const char *fmt) 268*f458709fSSergey Ryazanov { 269*f458709fSSergey Ryazanov struct wwan_device *wwandev = to_wwan_dev(port->dev.parent); 270*f458709fSSergey Ryazanov const unsigned int max_ports = PAGE_SIZE * 8; 271*f458709fSSergey Ryazanov struct class_dev_iter iter; 272*f458709fSSergey Ryazanov unsigned long *idmap; 273*f458709fSSergey Ryazanov struct device *dev; 274*f458709fSSergey Ryazanov char buf[0x20]; 275*f458709fSSergey Ryazanov int id; 276*f458709fSSergey Ryazanov 277*f458709fSSergey Ryazanov idmap = (unsigned long *)get_zeroed_page(GFP_KERNEL); 278*f458709fSSergey Ryazanov if (!idmap) 279*f458709fSSergey Ryazanov return -ENOMEM; 280*f458709fSSergey Ryazanov 281*f458709fSSergey Ryazanov /* Collect ids of same name format ports */ 282*f458709fSSergey Ryazanov class_dev_iter_init(&iter, wwan_class, NULL, &wwan_port_dev_type); 283*f458709fSSergey Ryazanov while ((dev = class_dev_iter_next(&iter))) { 284*f458709fSSergey Ryazanov if (dev->parent != &wwandev->dev) 285*f458709fSSergey Ryazanov continue; 286*f458709fSSergey Ryazanov if (sscanf(dev_name(dev), fmt, &id) != 1) 287*f458709fSSergey Ryazanov continue; 288*f458709fSSergey Ryazanov if (id < 0 || id >= max_ports) 289*f458709fSSergey Ryazanov continue; 290*f458709fSSergey Ryazanov set_bit(id, idmap); 291*f458709fSSergey Ryazanov } 292*f458709fSSergey Ryazanov class_dev_iter_exit(&iter); 293*f458709fSSergey Ryazanov 294*f458709fSSergey Ryazanov /* Allocate unique id */ 295*f458709fSSergey Ryazanov id = find_first_zero_bit(idmap, max_ports); 296*f458709fSSergey Ryazanov free_page((unsigned long)idmap); 297*f458709fSSergey Ryazanov 298*f458709fSSergey Ryazanov snprintf(buf, sizeof(buf), fmt, id); /* Name generation */ 299*f458709fSSergey Ryazanov 300*f458709fSSergey Ryazanov dev = device_find_child_by_name(&wwandev->dev, buf); 301*f458709fSSergey Ryazanov if (dev) { 302*f458709fSSergey Ryazanov put_device(dev); 303*f458709fSSergey Ryazanov return -ENFILE; 304*f458709fSSergey Ryazanov } 305*f458709fSSergey Ryazanov 306*f458709fSSergey Ryazanov return dev_set_name(&port->dev, buf); 307*f458709fSSergey Ryazanov } 308*f458709fSSergey Ryazanov 3099a44c1ccSLoic Poulain struct wwan_port *wwan_create_port(struct device *parent, 3109a44c1ccSLoic Poulain enum wwan_port_type type, 3119a44c1ccSLoic Poulain const struct wwan_port_ops *ops, 3129a44c1ccSLoic Poulain void *drvdata) 3139a44c1ccSLoic Poulain { 3149a44c1ccSLoic Poulain struct wwan_device *wwandev; 3159a44c1ccSLoic Poulain struct wwan_port *port; 3169a44c1ccSLoic Poulain int minor, err = -ENOMEM; 317*f458709fSSergey Ryazanov char namefmt[0x20]; 3189a44c1ccSLoic Poulain 319b64d76b7SSergey Ryazanov if (type > WWAN_PORT_MAX || !ops) 3209a44c1ccSLoic Poulain return ERR_PTR(-EINVAL); 3219a44c1ccSLoic Poulain 3229a44c1ccSLoic Poulain /* A port is always a child of a WWAN device, retrieve (allocate or 3239a44c1ccSLoic Poulain * pick) the WWAN device based on the provided parent device. 3249a44c1ccSLoic Poulain */ 3259a44c1ccSLoic Poulain wwandev = wwan_create_dev(parent); 3269a44c1ccSLoic Poulain if (IS_ERR(wwandev)) 3279a44c1ccSLoic Poulain return ERR_CAST(wwandev); 3289a44c1ccSLoic Poulain 3299a44c1ccSLoic Poulain /* A port is exposed as character device, get a minor */ 3309a44c1ccSLoic Poulain minor = ida_alloc_range(&minors, 0, WWAN_MAX_MINORS - 1, GFP_KERNEL); 3319a44c1ccSLoic Poulain if (minor < 0) 3329a44c1ccSLoic Poulain goto error_wwandev_remove; 3339a44c1ccSLoic Poulain 3349a44c1ccSLoic Poulain port = kzalloc(sizeof(*port), GFP_KERNEL); 3359a44c1ccSLoic Poulain if (!port) { 3369a44c1ccSLoic Poulain ida_free(&minors, minor); 3379a44c1ccSLoic Poulain goto error_wwandev_remove; 3389a44c1ccSLoic Poulain } 3399a44c1ccSLoic Poulain 3409a44c1ccSLoic Poulain port->type = type; 3419a44c1ccSLoic Poulain port->ops = ops; 3429a44c1ccSLoic Poulain mutex_init(&port->ops_lock); 3439a44c1ccSLoic Poulain skb_queue_head_init(&port->rxq); 3449a44c1ccSLoic Poulain init_waitqueue_head(&port->waitqueue); 3459a44c1ccSLoic Poulain 3469a44c1ccSLoic Poulain port->dev.parent = &wwandev->dev; 3479a44c1ccSLoic Poulain port->dev.class = wwan_class; 3489a44c1ccSLoic Poulain port->dev.type = &wwan_port_dev_type; 3499a44c1ccSLoic Poulain port->dev.devt = MKDEV(wwan_major, minor); 3509a44c1ccSLoic Poulain dev_set_drvdata(&port->dev, drvdata); 3519a44c1ccSLoic Poulain 352*f458709fSSergey Ryazanov /* allocate unique name based on wwan device id, port type and number */ 353*f458709fSSergey Ryazanov snprintf(namefmt, sizeof(namefmt), "wwan%u%s%%d", wwandev->id, 354392c26f7SSergey Ryazanov wwan_port_types[port->type].devsuf); 3559a44c1ccSLoic Poulain 356*f458709fSSergey Ryazanov /* Serialize ports registration */ 357*f458709fSSergey Ryazanov mutex_lock(&wwan_register_lock); 358*f458709fSSergey Ryazanov 359*f458709fSSergey Ryazanov __wwan_port_dev_assign_name(port, namefmt); 3609a44c1ccSLoic Poulain err = device_register(&port->dev); 361*f458709fSSergey Ryazanov 362*f458709fSSergey Ryazanov mutex_unlock(&wwan_register_lock); 363*f458709fSSergey Ryazanov 3649a44c1ccSLoic Poulain if (err) 3659a44c1ccSLoic Poulain goto error_put_device; 3669a44c1ccSLoic Poulain 3679a44c1ccSLoic Poulain return port; 3689a44c1ccSLoic Poulain 3699a44c1ccSLoic Poulain error_put_device: 3709a44c1ccSLoic Poulain put_device(&port->dev); 3719a44c1ccSLoic Poulain error_wwandev_remove: 3729a44c1ccSLoic Poulain wwan_remove_dev(wwandev); 3739a44c1ccSLoic Poulain 3749a44c1ccSLoic Poulain return ERR_PTR(err); 3759a44c1ccSLoic Poulain } 3769a44c1ccSLoic Poulain EXPORT_SYMBOL_GPL(wwan_create_port); 3779a44c1ccSLoic Poulain 3789a44c1ccSLoic Poulain void wwan_remove_port(struct wwan_port *port) 3799a44c1ccSLoic Poulain { 3809a44c1ccSLoic Poulain struct wwan_device *wwandev = to_wwan_dev(port->dev.parent); 3819a44c1ccSLoic Poulain 3829a44c1ccSLoic Poulain mutex_lock(&port->ops_lock); 3839a44c1ccSLoic Poulain if (port->start_count) 3849a44c1ccSLoic Poulain port->ops->stop(port); 3859a44c1ccSLoic Poulain port->ops = NULL; /* Prevent any new port operations (e.g. from fops) */ 3869a44c1ccSLoic Poulain mutex_unlock(&port->ops_lock); 3879a44c1ccSLoic Poulain 3889a44c1ccSLoic Poulain wake_up_interruptible(&port->waitqueue); 3899a44c1ccSLoic Poulain 3909a44c1ccSLoic Poulain skb_queue_purge(&port->rxq); 3919a44c1ccSLoic Poulain dev_set_drvdata(&port->dev, NULL); 3929a44c1ccSLoic Poulain device_unregister(&port->dev); 3939a44c1ccSLoic Poulain 3949a44c1ccSLoic Poulain /* Release related wwan device */ 3959a44c1ccSLoic Poulain wwan_remove_dev(wwandev); 3969a44c1ccSLoic Poulain } 3979a44c1ccSLoic Poulain EXPORT_SYMBOL_GPL(wwan_remove_port); 3989a44c1ccSLoic Poulain 3999a44c1ccSLoic Poulain void wwan_port_rx(struct wwan_port *port, struct sk_buff *skb) 4009a44c1ccSLoic Poulain { 4019a44c1ccSLoic Poulain skb_queue_tail(&port->rxq, skb); 4029a44c1ccSLoic Poulain wake_up_interruptible(&port->waitqueue); 4039a44c1ccSLoic Poulain } 4049a44c1ccSLoic Poulain EXPORT_SYMBOL_GPL(wwan_port_rx); 4059a44c1ccSLoic Poulain 4069a44c1ccSLoic Poulain void wwan_port_txon(struct wwan_port *port) 4079a44c1ccSLoic Poulain { 4089a44c1ccSLoic Poulain clear_bit(WWAN_PORT_TX_OFF, &port->flags); 4099a44c1ccSLoic Poulain wake_up_interruptible(&port->waitqueue); 4109a44c1ccSLoic Poulain } 4119a44c1ccSLoic Poulain EXPORT_SYMBOL_GPL(wwan_port_txon); 4129a44c1ccSLoic Poulain 4139a44c1ccSLoic Poulain void wwan_port_txoff(struct wwan_port *port) 4149a44c1ccSLoic Poulain { 4159a44c1ccSLoic Poulain set_bit(WWAN_PORT_TX_OFF, &port->flags); 4169a44c1ccSLoic Poulain } 4179a44c1ccSLoic Poulain EXPORT_SYMBOL_GPL(wwan_port_txoff); 4189a44c1ccSLoic Poulain 4199a44c1ccSLoic Poulain void *wwan_port_get_drvdata(struct wwan_port *port) 4209a44c1ccSLoic Poulain { 4219a44c1ccSLoic Poulain return dev_get_drvdata(&port->dev); 4229a44c1ccSLoic Poulain } 4239a44c1ccSLoic Poulain EXPORT_SYMBOL_GPL(wwan_port_get_drvdata); 4249a44c1ccSLoic Poulain 4259a44c1ccSLoic Poulain static int wwan_port_op_start(struct wwan_port *port) 4269a44c1ccSLoic Poulain { 4279a44c1ccSLoic Poulain int ret = 0; 4289a44c1ccSLoic Poulain 4299a44c1ccSLoic Poulain mutex_lock(&port->ops_lock); 4309a44c1ccSLoic Poulain if (!port->ops) { /* Port got unplugged */ 4319a44c1ccSLoic Poulain ret = -ENODEV; 4329a44c1ccSLoic Poulain goto out_unlock; 4339a44c1ccSLoic Poulain } 4349a44c1ccSLoic Poulain 4359a44c1ccSLoic Poulain /* If port is already started, don't start again */ 4369a44c1ccSLoic Poulain if (!port->start_count) 4379a44c1ccSLoic Poulain ret = port->ops->start(port); 4389a44c1ccSLoic Poulain 4399a44c1ccSLoic Poulain if (!ret) 4409a44c1ccSLoic Poulain port->start_count++; 4419a44c1ccSLoic Poulain 4429a44c1ccSLoic Poulain out_unlock: 4439a44c1ccSLoic Poulain mutex_unlock(&port->ops_lock); 4449a44c1ccSLoic Poulain 4459a44c1ccSLoic Poulain return ret; 4469a44c1ccSLoic Poulain } 4479a44c1ccSLoic Poulain 4489a44c1ccSLoic Poulain static void wwan_port_op_stop(struct wwan_port *port) 4499a44c1ccSLoic Poulain { 4509a44c1ccSLoic Poulain mutex_lock(&port->ops_lock); 4519a44c1ccSLoic Poulain port->start_count--; 4529a44c1ccSLoic Poulain if (port->ops && !port->start_count) 4539a44c1ccSLoic Poulain port->ops->stop(port); 4549a44c1ccSLoic Poulain mutex_unlock(&port->ops_lock); 4559a44c1ccSLoic Poulain } 4569a44c1ccSLoic Poulain 4579a44c1ccSLoic Poulain static int wwan_port_op_tx(struct wwan_port *port, struct sk_buff *skb) 4589a44c1ccSLoic Poulain { 4599a44c1ccSLoic Poulain int ret; 4609a44c1ccSLoic Poulain 4619a44c1ccSLoic Poulain mutex_lock(&port->ops_lock); 4629a44c1ccSLoic Poulain if (!port->ops) { /* Port got unplugged */ 4639a44c1ccSLoic Poulain ret = -ENODEV; 4649a44c1ccSLoic Poulain goto out_unlock; 4659a44c1ccSLoic Poulain } 4669a44c1ccSLoic Poulain 4679a44c1ccSLoic Poulain ret = port->ops->tx(port, skb); 4689a44c1ccSLoic Poulain 4699a44c1ccSLoic Poulain out_unlock: 4709a44c1ccSLoic Poulain mutex_unlock(&port->ops_lock); 4719a44c1ccSLoic Poulain 4729a44c1ccSLoic Poulain return ret; 4739a44c1ccSLoic Poulain } 4749a44c1ccSLoic Poulain 4759a44c1ccSLoic Poulain static bool is_read_blocked(struct wwan_port *port) 4769a44c1ccSLoic Poulain { 4779a44c1ccSLoic Poulain return skb_queue_empty(&port->rxq) && port->ops; 4789a44c1ccSLoic Poulain } 4799a44c1ccSLoic Poulain 4809a44c1ccSLoic Poulain static bool is_write_blocked(struct wwan_port *port) 4819a44c1ccSLoic Poulain { 4829a44c1ccSLoic Poulain return test_bit(WWAN_PORT_TX_OFF, &port->flags) && port->ops; 4839a44c1ccSLoic Poulain } 4849a44c1ccSLoic Poulain 4859a44c1ccSLoic Poulain static int wwan_wait_rx(struct wwan_port *port, bool nonblock) 4869a44c1ccSLoic Poulain { 4879a44c1ccSLoic Poulain if (!is_read_blocked(port)) 4889a44c1ccSLoic Poulain return 0; 4899a44c1ccSLoic Poulain 4909a44c1ccSLoic Poulain if (nonblock) 4919a44c1ccSLoic Poulain return -EAGAIN; 4929a44c1ccSLoic Poulain 4939a44c1ccSLoic Poulain if (wait_event_interruptible(port->waitqueue, !is_read_blocked(port))) 4949a44c1ccSLoic Poulain return -ERESTARTSYS; 4959a44c1ccSLoic Poulain 4969a44c1ccSLoic Poulain return 0; 4979a44c1ccSLoic Poulain } 4989a44c1ccSLoic Poulain 4999a44c1ccSLoic Poulain static int wwan_wait_tx(struct wwan_port *port, bool nonblock) 5009a44c1ccSLoic Poulain { 5019a44c1ccSLoic Poulain if (!is_write_blocked(port)) 5029a44c1ccSLoic Poulain return 0; 5039a44c1ccSLoic Poulain 5049a44c1ccSLoic Poulain if (nonblock) 5059a44c1ccSLoic Poulain return -EAGAIN; 5069a44c1ccSLoic Poulain 5079a44c1ccSLoic Poulain if (wait_event_interruptible(port->waitqueue, !is_write_blocked(port))) 5089a44c1ccSLoic Poulain return -ERESTARTSYS; 5099a44c1ccSLoic Poulain 5109a44c1ccSLoic Poulain return 0; 5119a44c1ccSLoic Poulain } 5129a44c1ccSLoic Poulain 5139a44c1ccSLoic Poulain static int wwan_port_fops_open(struct inode *inode, struct file *file) 5149a44c1ccSLoic Poulain { 5159a44c1ccSLoic Poulain struct wwan_port *port; 5169a44c1ccSLoic Poulain int err = 0; 5179a44c1ccSLoic Poulain 5189a44c1ccSLoic Poulain port = wwan_port_get_by_minor(iminor(inode)); 5199a44c1ccSLoic Poulain if (IS_ERR(port)) 5209a44c1ccSLoic Poulain return PTR_ERR(port); 5219a44c1ccSLoic Poulain 5229a44c1ccSLoic Poulain file->private_data = port; 5239a44c1ccSLoic Poulain stream_open(inode, file); 5249a44c1ccSLoic Poulain 5259a44c1ccSLoic Poulain err = wwan_port_op_start(port); 5269a44c1ccSLoic Poulain if (err) 5279a44c1ccSLoic Poulain put_device(&port->dev); 5289a44c1ccSLoic Poulain 5299a44c1ccSLoic Poulain return err; 5309a44c1ccSLoic Poulain } 5319a44c1ccSLoic Poulain 5329a44c1ccSLoic Poulain static int wwan_port_fops_release(struct inode *inode, struct file *filp) 5339a44c1ccSLoic Poulain { 5349a44c1ccSLoic Poulain struct wwan_port *port = filp->private_data; 5359a44c1ccSLoic Poulain 5369a44c1ccSLoic Poulain wwan_port_op_stop(port); 5379a44c1ccSLoic Poulain put_device(&port->dev); 5389a44c1ccSLoic Poulain 5399a44c1ccSLoic Poulain return 0; 5409a44c1ccSLoic Poulain } 5419a44c1ccSLoic Poulain 5429a44c1ccSLoic Poulain static ssize_t wwan_port_fops_read(struct file *filp, char __user *buf, 5439a44c1ccSLoic Poulain size_t count, loff_t *ppos) 5449a44c1ccSLoic Poulain { 5459a44c1ccSLoic Poulain struct wwan_port *port = filp->private_data; 5469a44c1ccSLoic Poulain struct sk_buff *skb; 5479a44c1ccSLoic Poulain size_t copied; 5489a44c1ccSLoic Poulain int ret; 5499a44c1ccSLoic Poulain 5509a44c1ccSLoic Poulain ret = wwan_wait_rx(port, !!(filp->f_flags & O_NONBLOCK)); 5519a44c1ccSLoic Poulain if (ret) 5529a44c1ccSLoic Poulain return ret; 5539a44c1ccSLoic Poulain 5549a44c1ccSLoic Poulain skb = skb_dequeue(&port->rxq); 5559a44c1ccSLoic Poulain if (!skb) 5569a44c1ccSLoic Poulain return -EIO; 5579a44c1ccSLoic Poulain 5589a44c1ccSLoic Poulain copied = min_t(size_t, count, skb->len); 5599a44c1ccSLoic Poulain if (copy_to_user(buf, skb->data, copied)) { 5609a44c1ccSLoic Poulain kfree_skb(skb); 5619a44c1ccSLoic Poulain return -EFAULT; 5629a44c1ccSLoic Poulain } 5639a44c1ccSLoic Poulain skb_pull(skb, copied); 5649a44c1ccSLoic Poulain 5659a44c1ccSLoic Poulain /* skb is not fully consumed, keep it in the queue */ 5669a44c1ccSLoic Poulain if (skb->len) 5679a44c1ccSLoic Poulain skb_queue_head(&port->rxq, skb); 5689a44c1ccSLoic Poulain else 5699a44c1ccSLoic Poulain consume_skb(skb); 5709a44c1ccSLoic Poulain 5719a44c1ccSLoic Poulain return copied; 5729a44c1ccSLoic Poulain } 5739a44c1ccSLoic Poulain 5749a44c1ccSLoic Poulain static ssize_t wwan_port_fops_write(struct file *filp, const char __user *buf, 5759a44c1ccSLoic Poulain size_t count, loff_t *offp) 5769a44c1ccSLoic Poulain { 5779a44c1ccSLoic Poulain struct wwan_port *port = filp->private_data; 5789a44c1ccSLoic Poulain struct sk_buff *skb; 5799a44c1ccSLoic Poulain int ret; 5809a44c1ccSLoic Poulain 5819a44c1ccSLoic Poulain ret = wwan_wait_tx(port, !!(filp->f_flags & O_NONBLOCK)); 5829a44c1ccSLoic Poulain if (ret) 5839a44c1ccSLoic Poulain return ret; 5849a44c1ccSLoic Poulain 5859a44c1ccSLoic Poulain skb = alloc_skb(count, GFP_KERNEL); 5869a44c1ccSLoic Poulain if (!skb) 5879a44c1ccSLoic Poulain return -ENOMEM; 5889a44c1ccSLoic Poulain 5899a44c1ccSLoic Poulain if (copy_from_user(skb_put(skb, count), buf, count)) { 5909a44c1ccSLoic Poulain kfree_skb(skb); 5919a44c1ccSLoic Poulain return -EFAULT; 5929a44c1ccSLoic Poulain } 5939a44c1ccSLoic Poulain 5949a44c1ccSLoic Poulain ret = wwan_port_op_tx(port, skb); 5959a44c1ccSLoic Poulain if (ret) { 5969a44c1ccSLoic Poulain kfree_skb(skb); 5979a44c1ccSLoic Poulain return ret; 5989a44c1ccSLoic Poulain } 5999a44c1ccSLoic Poulain 6009a44c1ccSLoic Poulain return count; 6019a44c1ccSLoic Poulain } 6029a44c1ccSLoic Poulain 6039a44c1ccSLoic Poulain static __poll_t wwan_port_fops_poll(struct file *filp, poll_table *wait) 6049a44c1ccSLoic Poulain { 6059a44c1ccSLoic Poulain struct wwan_port *port = filp->private_data; 6069a44c1ccSLoic Poulain __poll_t mask = 0; 6079a44c1ccSLoic Poulain 6089a44c1ccSLoic Poulain poll_wait(filp, &port->waitqueue, wait); 6099a44c1ccSLoic Poulain 6109a44c1ccSLoic Poulain if (!is_write_blocked(port)) 6119a44c1ccSLoic Poulain mask |= EPOLLOUT | EPOLLWRNORM; 6129a44c1ccSLoic Poulain if (!is_read_blocked(port)) 6139a44c1ccSLoic Poulain mask |= EPOLLIN | EPOLLRDNORM; 61457e22247SLoic Poulain if (!port->ops) 61557e22247SLoic Poulain mask |= EPOLLHUP | EPOLLERR; 6169a44c1ccSLoic Poulain 6179a44c1ccSLoic Poulain return mask; 6189a44c1ccSLoic Poulain } 6199a44c1ccSLoic Poulain 6209a44c1ccSLoic Poulain static const struct file_operations wwan_port_fops = { 6219a44c1ccSLoic Poulain .owner = THIS_MODULE, 6229a44c1ccSLoic Poulain .open = wwan_port_fops_open, 6239a44c1ccSLoic Poulain .release = wwan_port_fops_release, 6249a44c1ccSLoic Poulain .read = wwan_port_fops_read, 6259a44c1ccSLoic Poulain .write = wwan_port_fops_write, 6269a44c1ccSLoic Poulain .poll = wwan_port_fops_poll, 6279a44c1ccSLoic Poulain .llseek = noop_llseek, 6289a44c1ccSLoic Poulain }; 6299a44c1ccSLoic Poulain 6309a44c1ccSLoic Poulain static int __init wwan_init(void) 6319a44c1ccSLoic Poulain { 6329a44c1ccSLoic Poulain wwan_class = class_create(THIS_MODULE, "wwan"); 6339a44c1ccSLoic Poulain if (IS_ERR(wwan_class)) 6349a44c1ccSLoic Poulain return PTR_ERR(wwan_class); 6359a44c1ccSLoic Poulain 6369a44c1ccSLoic Poulain /* chrdev used for wwan ports */ 6379a44c1ccSLoic Poulain wwan_major = register_chrdev(0, "wwan_port", &wwan_port_fops); 6389a44c1ccSLoic Poulain if (wwan_major < 0) { 6399a44c1ccSLoic Poulain class_destroy(wwan_class); 6409a44c1ccSLoic Poulain return wwan_major; 6419a44c1ccSLoic Poulain } 6429a44c1ccSLoic Poulain 6439a44c1ccSLoic Poulain return 0; 6449a44c1ccSLoic Poulain } 6459a44c1ccSLoic Poulain 6469a44c1ccSLoic Poulain static void __exit wwan_exit(void) 6479a44c1ccSLoic Poulain { 6489a44c1ccSLoic Poulain unregister_chrdev(wwan_major, "wwan_port"); 6499a44c1ccSLoic Poulain class_destroy(wwan_class); 6509a44c1ccSLoic Poulain } 6519a44c1ccSLoic Poulain 6529a44c1ccSLoic Poulain module_init(wwan_init); 6539a44c1ccSLoic Poulain module_exit(wwan_exit); 6549a44c1ccSLoic Poulain 6559a44c1ccSLoic Poulain MODULE_AUTHOR("Loic Poulain <loic.poulain@linaro.org>"); 6569a44c1ccSLoic Poulain MODULE_DESCRIPTION("WWAN core"); 6579a44c1ccSLoic Poulain MODULE_LICENSE("GPL v2"); 658