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 */ 29*b8c55ce2SLoic 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 * @port_id: Current available port ID to pick. 379a44c1ccSLoic Poulain */ 389a44c1ccSLoic Poulain struct wwan_device { 399a44c1ccSLoic Poulain unsigned int id; 409a44c1ccSLoic Poulain struct device dev; 419a44c1ccSLoic Poulain atomic_t port_id; 429a44c1ccSLoic Poulain }; 439a44c1ccSLoic Poulain 449a44c1ccSLoic Poulain /** 459a44c1ccSLoic Poulain * struct wwan_port - The structure that defines a WWAN port 469a44c1ccSLoic Poulain * @type: Port type 479a44c1ccSLoic Poulain * @start_count: Port start counter 489a44c1ccSLoic Poulain * @flags: Store port state and capabilities 499a44c1ccSLoic Poulain * @ops: Pointer to WWAN port operations 509a44c1ccSLoic Poulain * @ops_lock: Protect port ops 519a44c1ccSLoic Poulain * @dev: Underlying device 529a44c1ccSLoic Poulain * @rxq: Buffer inbound queue 539a44c1ccSLoic Poulain * @waitqueue: The waitqueue for port fops (read/write/poll) 549a44c1ccSLoic Poulain */ 559a44c1ccSLoic Poulain struct wwan_port { 569a44c1ccSLoic Poulain enum wwan_port_type type; 579a44c1ccSLoic Poulain unsigned int start_count; 589a44c1ccSLoic Poulain unsigned long flags; 599a44c1ccSLoic Poulain const struct wwan_port_ops *ops; 609a44c1ccSLoic Poulain struct mutex ops_lock; /* Serialize ops + protect against removal */ 619a44c1ccSLoic Poulain struct device dev; 629a44c1ccSLoic Poulain struct sk_buff_head rxq; 639a44c1ccSLoic Poulain wait_queue_head_t waitqueue; 649a44c1ccSLoic Poulain }; 659a44c1ccSLoic Poulain 669a44c1ccSLoic Poulain static void wwan_dev_destroy(struct device *dev) 679a44c1ccSLoic Poulain { 689a44c1ccSLoic Poulain struct wwan_device *wwandev = to_wwan_dev(dev); 699a44c1ccSLoic Poulain 709a44c1ccSLoic Poulain ida_free(&wwan_dev_ids, wwandev->id); 719a44c1ccSLoic Poulain kfree(wwandev); 729a44c1ccSLoic Poulain } 739a44c1ccSLoic Poulain 749a44c1ccSLoic Poulain static const struct device_type wwan_dev_type = { 759a44c1ccSLoic Poulain .name = "wwan_dev", 769a44c1ccSLoic Poulain .release = wwan_dev_destroy, 779a44c1ccSLoic Poulain }; 789a44c1ccSLoic Poulain 799a44c1ccSLoic Poulain static int wwan_dev_parent_match(struct device *dev, const void *parent) 809a44c1ccSLoic Poulain { 819a44c1ccSLoic Poulain return (dev->type == &wwan_dev_type && dev->parent == parent); 829a44c1ccSLoic Poulain } 839a44c1ccSLoic Poulain 849a44c1ccSLoic Poulain static struct wwan_device *wwan_dev_get_by_parent(struct device *parent) 859a44c1ccSLoic Poulain { 869a44c1ccSLoic Poulain struct device *dev; 879a44c1ccSLoic Poulain 889a44c1ccSLoic Poulain dev = class_find_device(wwan_class, NULL, parent, wwan_dev_parent_match); 899a44c1ccSLoic Poulain if (!dev) 909a44c1ccSLoic Poulain return ERR_PTR(-ENODEV); 919a44c1ccSLoic Poulain 929a44c1ccSLoic Poulain return to_wwan_dev(dev); 939a44c1ccSLoic Poulain } 949a44c1ccSLoic Poulain 959a44c1ccSLoic Poulain /* This function allocates and registers a new WWAN device OR if a WWAN device 969a44c1ccSLoic Poulain * already exist for the given parent, it gets a reference and return it. 979a44c1ccSLoic Poulain * This function is not exported (for now), it is called indirectly via 989a44c1ccSLoic Poulain * wwan_create_port(). 999a44c1ccSLoic Poulain */ 1009a44c1ccSLoic Poulain static struct wwan_device *wwan_create_dev(struct device *parent) 1019a44c1ccSLoic Poulain { 1029a44c1ccSLoic Poulain struct wwan_device *wwandev; 1039a44c1ccSLoic Poulain int err, id; 1049a44c1ccSLoic Poulain 1059a44c1ccSLoic Poulain /* The 'find-alloc-register' operation must be protected against 1069a44c1ccSLoic Poulain * concurrent execution, a WWAN device is possibly shared between 1079a44c1ccSLoic Poulain * multiple callers or concurrently unregistered from wwan_remove_dev(). 1089a44c1ccSLoic Poulain */ 1099a44c1ccSLoic Poulain mutex_lock(&wwan_register_lock); 1109a44c1ccSLoic Poulain 1119a44c1ccSLoic Poulain /* If wwandev already exists, return it */ 1129a44c1ccSLoic Poulain wwandev = wwan_dev_get_by_parent(parent); 1139a44c1ccSLoic Poulain if (!IS_ERR(wwandev)) 1149a44c1ccSLoic Poulain goto done_unlock; 1159a44c1ccSLoic Poulain 1169a44c1ccSLoic Poulain id = ida_alloc(&wwan_dev_ids, GFP_KERNEL); 1179a44c1ccSLoic Poulain if (id < 0) 1189a44c1ccSLoic Poulain goto done_unlock; 1199a44c1ccSLoic Poulain 1209a44c1ccSLoic Poulain wwandev = kzalloc(sizeof(*wwandev), GFP_KERNEL); 1219a44c1ccSLoic Poulain if (!wwandev) { 1229a44c1ccSLoic Poulain ida_free(&wwan_dev_ids, id); 1239a44c1ccSLoic Poulain goto done_unlock; 1249a44c1ccSLoic Poulain } 1259a44c1ccSLoic Poulain 1269a44c1ccSLoic Poulain wwandev->dev.parent = parent; 1279a44c1ccSLoic Poulain wwandev->dev.class = wwan_class; 1289a44c1ccSLoic Poulain wwandev->dev.type = &wwan_dev_type; 1299a44c1ccSLoic Poulain wwandev->id = id; 1309a44c1ccSLoic Poulain dev_set_name(&wwandev->dev, "wwan%d", wwandev->id); 1319a44c1ccSLoic Poulain 1329a44c1ccSLoic Poulain err = device_register(&wwandev->dev); 1339a44c1ccSLoic Poulain if (err) { 1349a44c1ccSLoic Poulain put_device(&wwandev->dev); 1359a44c1ccSLoic Poulain wwandev = NULL; 1369a44c1ccSLoic Poulain } 1379a44c1ccSLoic Poulain 1389a44c1ccSLoic Poulain done_unlock: 1399a44c1ccSLoic Poulain mutex_unlock(&wwan_register_lock); 1409a44c1ccSLoic Poulain 1419a44c1ccSLoic Poulain return wwandev; 1429a44c1ccSLoic Poulain } 1439a44c1ccSLoic Poulain 1449a44c1ccSLoic Poulain static int is_wwan_child(struct device *dev, void *data) 1459a44c1ccSLoic Poulain { 1469a44c1ccSLoic Poulain return dev->class == wwan_class; 1479a44c1ccSLoic Poulain } 1489a44c1ccSLoic Poulain 1499a44c1ccSLoic Poulain static void wwan_remove_dev(struct wwan_device *wwandev) 1509a44c1ccSLoic Poulain { 1519a44c1ccSLoic Poulain int ret; 1529a44c1ccSLoic Poulain 1539a44c1ccSLoic Poulain /* Prevent concurrent picking from wwan_create_dev */ 1549a44c1ccSLoic Poulain mutex_lock(&wwan_register_lock); 1559a44c1ccSLoic Poulain 1569a44c1ccSLoic Poulain /* WWAN device is created and registered (get+add) along with its first 1579a44c1ccSLoic Poulain * child port, and subsequent port registrations only grab a reference 1589a44c1ccSLoic Poulain * (get). The WWAN device must then be unregistered (del+put) along with 1599a44c1ccSLoic Poulain * its latest port, and reference simply dropped (put) otherwise. 1609a44c1ccSLoic Poulain */ 1619a44c1ccSLoic Poulain ret = device_for_each_child(&wwandev->dev, NULL, is_wwan_child); 1629a44c1ccSLoic Poulain if (!ret) 1639a44c1ccSLoic Poulain device_unregister(&wwandev->dev); 1649a44c1ccSLoic Poulain else 1659a44c1ccSLoic Poulain put_device(&wwandev->dev); 1669a44c1ccSLoic Poulain 1679a44c1ccSLoic Poulain mutex_unlock(&wwan_register_lock); 1689a44c1ccSLoic Poulain } 1699a44c1ccSLoic Poulain 1709a44c1ccSLoic Poulain /* ------- WWAN port management ------- */ 1719a44c1ccSLoic Poulain 1729a44c1ccSLoic Poulain static void wwan_port_destroy(struct device *dev) 1739a44c1ccSLoic Poulain { 1749a44c1ccSLoic Poulain struct wwan_port *port = to_wwan_port(dev); 1759a44c1ccSLoic Poulain 1769a44c1ccSLoic Poulain ida_free(&minors, MINOR(port->dev.devt)); 1779a44c1ccSLoic Poulain skb_queue_purge(&port->rxq); 1789a44c1ccSLoic Poulain mutex_destroy(&port->ops_lock); 1799a44c1ccSLoic Poulain kfree(port); 1809a44c1ccSLoic Poulain } 1819a44c1ccSLoic Poulain 1829a44c1ccSLoic Poulain static const struct device_type wwan_port_dev_type = { 1839a44c1ccSLoic Poulain .name = "wwan_port", 1849a44c1ccSLoic Poulain .release = wwan_port_destroy, 1859a44c1ccSLoic Poulain }; 1869a44c1ccSLoic Poulain 1879a44c1ccSLoic Poulain static int wwan_port_minor_match(struct device *dev, const void *minor) 1889a44c1ccSLoic Poulain { 1899a44c1ccSLoic Poulain return (dev->type == &wwan_port_dev_type && 1909a44c1ccSLoic Poulain MINOR(dev->devt) == *(unsigned int *)minor); 1919a44c1ccSLoic Poulain } 1929a44c1ccSLoic Poulain 1939a44c1ccSLoic Poulain static struct wwan_port *wwan_port_get_by_minor(unsigned int minor) 1949a44c1ccSLoic Poulain { 1959a44c1ccSLoic Poulain struct device *dev; 1969a44c1ccSLoic Poulain 1979a44c1ccSLoic Poulain dev = class_find_device(wwan_class, NULL, &minor, wwan_port_minor_match); 1989a44c1ccSLoic Poulain if (!dev) 1999a44c1ccSLoic Poulain return ERR_PTR(-ENODEV); 2009a44c1ccSLoic Poulain 2019a44c1ccSLoic Poulain return to_wwan_port(dev); 2029a44c1ccSLoic Poulain } 2039a44c1ccSLoic Poulain 2049a44c1ccSLoic Poulain /* Keep aligned with wwan_port_type enum */ 2059a44c1ccSLoic Poulain static const char * const wwan_port_type_str[] = { 2069a44c1ccSLoic Poulain "AT", 2079a44c1ccSLoic Poulain "MBIM", 2089a44c1ccSLoic Poulain "QMI", 2099a44c1ccSLoic Poulain "QCDM", 2109a44c1ccSLoic Poulain "FIREHOSE" 2119a44c1ccSLoic Poulain }; 2129a44c1ccSLoic Poulain 2139a44c1ccSLoic Poulain struct wwan_port *wwan_create_port(struct device *parent, 2149a44c1ccSLoic Poulain enum wwan_port_type type, 2159a44c1ccSLoic Poulain const struct wwan_port_ops *ops, 2169a44c1ccSLoic Poulain void *drvdata) 2179a44c1ccSLoic Poulain { 2189a44c1ccSLoic Poulain struct wwan_device *wwandev; 2199a44c1ccSLoic Poulain struct wwan_port *port; 2209a44c1ccSLoic Poulain int minor, err = -ENOMEM; 2219a44c1ccSLoic Poulain 2229a44c1ccSLoic Poulain if (type >= WWAN_PORT_MAX || !ops) 2239a44c1ccSLoic Poulain return ERR_PTR(-EINVAL); 2249a44c1ccSLoic Poulain 2259a44c1ccSLoic Poulain /* A port is always a child of a WWAN device, retrieve (allocate or 2269a44c1ccSLoic Poulain * pick) the WWAN device based on the provided parent device. 2279a44c1ccSLoic Poulain */ 2289a44c1ccSLoic Poulain wwandev = wwan_create_dev(parent); 2299a44c1ccSLoic Poulain if (IS_ERR(wwandev)) 2309a44c1ccSLoic Poulain return ERR_CAST(wwandev); 2319a44c1ccSLoic Poulain 2329a44c1ccSLoic Poulain /* A port is exposed as character device, get a minor */ 2339a44c1ccSLoic Poulain minor = ida_alloc_range(&minors, 0, WWAN_MAX_MINORS - 1, GFP_KERNEL); 2349a44c1ccSLoic Poulain if (minor < 0) 2359a44c1ccSLoic Poulain goto error_wwandev_remove; 2369a44c1ccSLoic Poulain 2379a44c1ccSLoic Poulain port = kzalloc(sizeof(*port), GFP_KERNEL); 2389a44c1ccSLoic Poulain if (!port) { 2399a44c1ccSLoic Poulain ida_free(&minors, minor); 2409a44c1ccSLoic Poulain goto error_wwandev_remove; 2419a44c1ccSLoic Poulain } 2429a44c1ccSLoic Poulain 2439a44c1ccSLoic Poulain port->type = type; 2449a44c1ccSLoic Poulain port->ops = ops; 2459a44c1ccSLoic Poulain mutex_init(&port->ops_lock); 2469a44c1ccSLoic Poulain skb_queue_head_init(&port->rxq); 2479a44c1ccSLoic Poulain init_waitqueue_head(&port->waitqueue); 2489a44c1ccSLoic Poulain 2499a44c1ccSLoic Poulain port->dev.parent = &wwandev->dev; 2509a44c1ccSLoic Poulain port->dev.class = wwan_class; 2519a44c1ccSLoic Poulain port->dev.type = &wwan_port_dev_type; 2529a44c1ccSLoic Poulain port->dev.devt = MKDEV(wwan_major, minor); 2539a44c1ccSLoic Poulain dev_set_drvdata(&port->dev, drvdata); 2549a44c1ccSLoic Poulain 2559a44c1ccSLoic Poulain /* create unique name based on wwan device id, port index and type */ 2569a44c1ccSLoic Poulain dev_set_name(&port->dev, "wwan%up%u%s", wwandev->id, 2579a44c1ccSLoic Poulain atomic_inc_return(&wwandev->port_id), 2589a44c1ccSLoic Poulain wwan_port_type_str[port->type]); 2599a44c1ccSLoic Poulain 2609a44c1ccSLoic Poulain err = device_register(&port->dev); 2619a44c1ccSLoic Poulain if (err) 2629a44c1ccSLoic Poulain goto error_put_device; 2639a44c1ccSLoic Poulain 2649a44c1ccSLoic Poulain return port; 2659a44c1ccSLoic Poulain 2669a44c1ccSLoic Poulain error_put_device: 2679a44c1ccSLoic Poulain put_device(&port->dev); 2689a44c1ccSLoic Poulain error_wwandev_remove: 2699a44c1ccSLoic Poulain wwan_remove_dev(wwandev); 2709a44c1ccSLoic Poulain 2719a44c1ccSLoic Poulain return ERR_PTR(err); 2729a44c1ccSLoic Poulain } 2739a44c1ccSLoic Poulain EXPORT_SYMBOL_GPL(wwan_create_port); 2749a44c1ccSLoic Poulain 2759a44c1ccSLoic Poulain void wwan_remove_port(struct wwan_port *port) 2769a44c1ccSLoic Poulain { 2779a44c1ccSLoic Poulain struct wwan_device *wwandev = to_wwan_dev(port->dev.parent); 2789a44c1ccSLoic Poulain 2799a44c1ccSLoic Poulain mutex_lock(&port->ops_lock); 2809a44c1ccSLoic Poulain if (port->start_count) 2819a44c1ccSLoic Poulain port->ops->stop(port); 2829a44c1ccSLoic Poulain port->ops = NULL; /* Prevent any new port operations (e.g. from fops) */ 2839a44c1ccSLoic Poulain mutex_unlock(&port->ops_lock); 2849a44c1ccSLoic Poulain 2859a44c1ccSLoic Poulain wake_up_interruptible(&port->waitqueue); 2869a44c1ccSLoic Poulain 2879a44c1ccSLoic Poulain skb_queue_purge(&port->rxq); 2889a44c1ccSLoic Poulain dev_set_drvdata(&port->dev, NULL); 2899a44c1ccSLoic Poulain device_unregister(&port->dev); 2909a44c1ccSLoic Poulain 2919a44c1ccSLoic Poulain /* Release related wwan device */ 2929a44c1ccSLoic Poulain wwan_remove_dev(wwandev); 2939a44c1ccSLoic Poulain } 2949a44c1ccSLoic Poulain EXPORT_SYMBOL_GPL(wwan_remove_port); 2959a44c1ccSLoic Poulain 2969a44c1ccSLoic Poulain void wwan_port_rx(struct wwan_port *port, struct sk_buff *skb) 2979a44c1ccSLoic Poulain { 2989a44c1ccSLoic Poulain skb_queue_tail(&port->rxq, skb); 2999a44c1ccSLoic Poulain wake_up_interruptible(&port->waitqueue); 3009a44c1ccSLoic Poulain } 3019a44c1ccSLoic Poulain EXPORT_SYMBOL_GPL(wwan_port_rx); 3029a44c1ccSLoic Poulain 3039a44c1ccSLoic Poulain void wwan_port_txon(struct wwan_port *port) 3049a44c1ccSLoic Poulain { 3059a44c1ccSLoic Poulain clear_bit(WWAN_PORT_TX_OFF, &port->flags); 3069a44c1ccSLoic Poulain wake_up_interruptible(&port->waitqueue); 3079a44c1ccSLoic Poulain } 3089a44c1ccSLoic Poulain EXPORT_SYMBOL_GPL(wwan_port_txon); 3099a44c1ccSLoic Poulain 3109a44c1ccSLoic Poulain void wwan_port_txoff(struct wwan_port *port) 3119a44c1ccSLoic Poulain { 3129a44c1ccSLoic Poulain set_bit(WWAN_PORT_TX_OFF, &port->flags); 3139a44c1ccSLoic Poulain } 3149a44c1ccSLoic Poulain EXPORT_SYMBOL_GPL(wwan_port_txoff); 3159a44c1ccSLoic Poulain 3169a44c1ccSLoic Poulain void *wwan_port_get_drvdata(struct wwan_port *port) 3179a44c1ccSLoic Poulain { 3189a44c1ccSLoic Poulain return dev_get_drvdata(&port->dev); 3199a44c1ccSLoic Poulain } 3209a44c1ccSLoic Poulain EXPORT_SYMBOL_GPL(wwan_port_get_drvdata); 3219a44c1ccSLoic Poulain 3229a44c1ccSLoic Poulain static int wwan_port_op_start(struct wwan_port *port) 3239a44c1ccSLoic Poulain { 3249a44c1ccSLoic Poulain int ret = 0; 3259a44c1ccSLoic Poulain 3269a44c1ccSLoic Poulain mutex_lock(&port->ops_lock); 3279a44c1ccSLoic Poulain if (!port->ops) { /* Port got unplugged */ 3289a44c1ccSLoic Poulain ret = -ENODEV; 3299a44c1ccSLoic Poulain goto out_unlock; 3309a44c1ccSLoic Poulain } 3319a44c1ccSLoic Poulain 3329a44c1ccSLoic Poulain /* If port is already started, don't start again */ 3339a44c1ccSLoic Poulain if (!port->start_count) 3349a44c1ccSLoic Poulain ret = port->ops->start(port); 3359a44c1ccSLoic Poulain 3369a44c1ccSLoic Poulain if (!ret) 3379a44c1ccSLoic Poulain port->start_count++; 3389a44c1ccSLoic Poulain 3399a44c1ccSLoic Poulain out_unlock: 3409a44c1ccSLoic Poulain mutex_unlock(&port->ops_lock); 3419a44c1ccSLoic Poulain 3429a44c1ccSLoic Poulain return ret; 3439a44c1ccSLoic Poulain } 3449a44c1ccSLoic Poulain 3459a44c1ccSLoic Poulain static void wwan_port_op_stop(struct wwan_port *port) 3469a44c1ccSLoic Poulain { 3479a44c1ccSLoic Poulain mutex_lock(&port->ops_lock); 3489a44c1ccSLoic Poulain port->start_count--; 3499a44c1ccSLoic Poulain if (port->ops && !port->start_count) 3509a44c1ccSLoic Poulain port->ops->stop(port); 3519a44c1ccSLoic Poulain mutex_unlock(&port->ops_lock); 3529a44c1ccSLoic Poulain } 3539a44c1ccSLoic Poulain 3549a44c1ccSLoic Poulain static int wwan_port_op_tx(struct wwan_port *port, struct sk_buff *skb) 3559a44c1ccSLoic Poulain { 3569a44c1ccSLoic Poulain int ret; 3579a44c1ccSLoic Poulain 3589a44c1ccSLoic Poulain mutex_lock(&port->ops_lock); 3599a44c1ccSLoic Poulain if (!port->ops) { /* Port got unplugged */ 3609a44c1ccSLoic Poulain ret = -ENODEV; 3619a44c1ccSLoic Poulain goto out_unlock; 3629a44c1ccSLoic Poulain } 3639a44c1ccSLoic Poulain 3649a44c1ccSLoic Poulain ret = port->ops->tx(port, skb); 3659a44c1ccSLoic Poulain 3669a44c1ccSLoic Poulain out_unlock: 3679a44c1ccSLoic Poulain mutex_unlock(&port->ops_lock); 3689a44c1ccSLoic Poulain 3699a44c1ccSLoic Poulain return ret; 3709a44c1ccSLoic Poulain } 3719a44c1ccSLoic Poulain 3729a44c1ccSLoic Poulain static bool is_read_blocked(struct wwan_port *port) 3739a44c1ccSLoic Poulain { 3749a44c1ccSLoic Poulain return skb_queue_empty(&port->rxq) && port->ops; 3759a44c1ccSLoic Poulain } 3769a44c1ccSLoic Poulain 3779a44c1ccSLoic Poulain static bool is_write_blocked(struct wwan_port *port) 3789a44c1ccSLoic Poulain { 3799a44c1ccSLoic Poulain return test_bit(WWAN_PORT_TX_OFF, &port->flags) && port->ops; 3809a44c1ccSLoic Poulain } 3819a44c1ccSLoic Poulain 3829a44c1ccSLoic Poulain static int wwan_wait_rx(struct wwan_port *port, bool nonblock) 3839a44c1ccSLoic Poulain { 3849a44c1ccSLoic Poulain if (!is_read_blocked(port)) 3859a44c1ccSLoic Poulain return 0; 3869a44c1ccSLoic Poulain 3879a44c1ccSLoic Poulain if (nonblock) 3889a44c1ccSLoic Poulain return -EAGAIN; 3899a44c1ccSLoic Poulain 3909a44c1ccSLoic Poulain if (wait_event_interruptible(port->waitqueue, !is_read_blocked(port))) 3919a44c1ccSLoic Poulain return -ERESTARTSYS; 3929a44c1ccSLoic Poulain 3939a44c1ccSLoic Poulain return 0; 3949a44c1ccSLoic Poulain } 3959a44c1ccSLoic Poulain 3969a44c1ccSLoic Poulain static int wwan_wait_tx(struct wwan_port *port, bool nonblock) 3979a44c1ccSLoic Poulain { 3989a44c1ccSLoic Poulain if (!is_write_blocked(port)) 3999a44c1ccSLoic Poulain return 0; 4009a44c1ccSLoic Poulain 4019a44c1ccSLoic Poulain if (nonblock) 4029a44c1ccSLoic Poulain return -EAGAIN; 4039a44c1ccSLoic Poulain 4049a44c1ccSLoic Poulain if (wait_event_interruptible(port->waitqueue, !is_write_blocked(port))) 4059a44c1ccSLoic Poulain return -ERESTARTSYS; 4069a44c1ccSLoic Poulain 4079a44c1ccSLoic Poulain return 0; 4089a44c1ccSLoic Poulain } 4099a44c1ccSLoic Poulain 4109a44c1ccSLoic Poulain static int wwan_port_fops_open(struct inode *inode, struct file *file) 4119a44c1ccSLoic Poulain { 4129a44c1ccSLoic Poulain struct wwan_port *port; 4139a44c1ccSLoic Poulain int err = 0; 4149a44c1ccSLoic Poulain 4159a44c1ccSLoic Poulain port = wwan_port_get_by_minor(iminor(inode)); 4169a44c1ccSLoic Poulain if (IS_ERR(port)) 4179a44c1ccSLoic Poulain return PTR_ERR(port); 4189a44c1ccSLoic Poulain 4199a44c1ccSLoic Poulain file->private_data = port; 4209a44c1ccSLoic Poulain stream_open(inode, file); 4219a44c1ccSLoic Poulain 4229a44c1ccSLoic Poulain err = wwan_port_op_start(port); 4239a44c1ccSLoic Poulain if (err) 4249a44c1ccSLoic Poulain put_device(&port->dev); 4259a44c1ccSLoic Poulain 4269a44c1ccSLoic Poulain return err; 4279a44c1ccSLoic Poulain } 4289a44c1ccSLoic Poulain 4299a44c1ccSLoic Poulain static int wwan_port_fops_release(struct inode *inode, struct file *filp) 4309a44c1ccSLoic Poulain { 4319a44c1ccSLoic Poulain struct wwan_port *port = filp->private_data; 4329a44c1ccSLoic Poulain 4339a44c1ccSLoic Poulain wwan_port_op_stop(port); 4349a44c1ccSLoic Poulain put_device(&port->dev); 4359a44c1ccSLoic Poulain 4369a44c1ccSLoic Poulain return 0; 4379a44c1ccSLoic Poulain } 4389a44c1ccSLoic Poulain 4399a44c1ccSLoic Poulain static ssize_t wwan_port_fops_read(struct file *filp, char __user *buf, 4409a44c1ccSLoic Poulain size_t count, loff_t *ppos) 4419a44c1ccSLoic Poulain { 4429a44c1ccSLoic Poulain struct wwan_port *port = filp->private_data; 4439a44c1ccSLoic Poulain struct sk_buff *skb; 4449a44c1ccSLoic Poulain size_t copied; 4459a44c1ccSLoic Poulain int ret; 4469a44c1ccSLoic Poulain 4479a44c1ccSLoic Poulain ret = wwan_wait_rx(port, !!(filp->f_flags & O_NONBLOCK)); 4489a44c1ccSLoic Poulain if (ret) 4499a44c1ccSLoic Poulain return ret; 4509a44c1ccSLoic Poulain 4519a44c1ccSLoic Poulain skb = skb_dequeue(&port->rxq); 4529a44c1ccSLoic Poulain if (!skb) 4539a44c1ccSLoic Poulain return -EIO; 4549a44c1ccSLoic Poulain 4559a44c1ccSLoic Poulain copied = min_t(size_t, count, skb->len); 4569a44c1ccSLoic Poulain if (copy_to_user(buf, skb->data, copied)) { 4579a44c1ccSLoic Poulain kfree_skb(skb); 4589a44c1ccSLoic Poulain return -EFAULT; 4599a44c1ccSLoic Poulain } 4609a44c1ccSLoic Poulain skb_pull(skb, copied); 4619a44c1ccSLoic Poulain 4629a44c1ccSLoic Poulain /* skb is not fully consumed, keep it in the queue */ 4639a44c1ccSLoic Poulain if (skb->len) 4649a44c1ccSLoic Poulain skb_queue_head(&port->rxq, skb); 4659a44c1ccSLoic Poulain else 4669a44c1ccSLoic Poulain consume_skb(skb); 4679a44c1ccSLoic Poulain 4689a44c1ccSLoic Poulain return copied; 4699a44c1ccSLoic Poulain } 4709a44c1ccSLoic Poulain 4719a44c1ccSLoic Poulain static ssize_t wwan_port_fops_write(struct file *filp, const char __user *buf, 4729a44c1ccSLoic Poulain size_t count, loff_t *offp) 4739a44c1ccSLoic Poulain { 4749a44c1ccSLoic Poulain struct wwan_port *port = filp->private_data; 4759a44c1ccSLoic Poulain struct sk_buff *skb; 4769a44c1ccSLoic Poulain int ret; 4779a44c1ccSLoic Poulain 4789a44c1ccSLoic Poulain ret = wwan_wait_tx(port, !!(filp->f_flags & O_NONBLOCK)); 4799a44c1ccSLoic Poulain if (ret) 4809a44c1ccSLoic Poulain return ret; 4819a44c1ccSLoic Poulain 4829a44c1ccSLoic Poulain skb = alloc_skb(count, GFP_KERNEL); 4839a44c1ccSLoic Poulain if (!skb) 4849a44c1ccSLoic Poulain return -ENOMEM; 4859a44c1ccSLoic Poulain 4869a44c1ccSLoic Poulain if (copy_from_user(skb_put(skb, count), buf, count)) { 4879a44c1ccSLoic Poulain kfree_skb(skb); 4889a44c1ccSLoic Poulain return -EFAULT; 4899a44c1ccSLoic Poulain } 4909a44c1ccSLoic Poulain 4919a44c1ccSLoic Poulain ret = wwan_port_op_tx(port, skb); 4929a44c1ccSLoic Poulain if (ret) { 4939a44c1ccSLoic Poulain kfree_skb(skb); 4949a44c1ccSLoic Poulain return ret; 4959a44c1ccSLoic Poulain } 4969a44c1ccSLoic Poulain 4979a44c1ccSLoic Poulain return count; 4989a44c1ccSLoic Poulain } 4999a44c1ccSLoic Poulain 5009a44c1ccSLoic Poulain static __poll_t wwan_port_fops_poll(struct file *filp, poll_table *wait) 5019a44c1ccSLoic Poulain { 5029a44c1ccSLoic Poulain struct wwan_port *port = filp->private_data; 5039a44c1ccSLoic Poulain __poll_t mask = 0; 5049a44c1ccSLoic Poulain 5059a44c1ccSLoic Poulain poll_wait(filp, &port->waitqueue, wait); 5069a44c1ccSLoic Poulain 5079a44c1ccSLoic Poulain if (!is_write_blocked(port)) 5089a44c1ccSLoic Poulain mask |= EPOLLOUT | EPOLLWRNORM; 5099a44c1ccSLoic Poulain if (!is_read_blocked(port)) 5109a44c1ccSLoic Poulain mask |= EPOLLIN | EPOLLRDNORM; 5119a44c1ccSLoic Poulain 5129a44c1ccSLoic Poulain return mask; 5139a44c1ccSLoic Poulain } 5149a44c1ccSLoic Poulain 5159a44c1ccSLoic Poulain static const struct file_operations wwan_port_fops = { 5169a44c1ccSLoic Poulain .owner = THIS_MODULE, 5179a44c1ccSLoic Poulain .open = wwan_port_fops_open, 5189a44c1ccSLoic Poulain .release = wwan_port_fops_release, 5199a44c1ccSLoic Poulain .read = wwan_port_fops_read, 5209a44c1ccSLoic Poulain .write = wwan_port_fops_write, 5219a44c1ccSLoic Poulain .poll = wwan_port_fops_poll, 5229a44c1ccSLoic Poulain .llseek = noop_llseek, 5239a44c1ccSLoic Poulain }; 5249a44c1ccSLoic Poulain 5259a44c1ccSLoic Poulain static int __init wwan_init(void) 5269a44c1ccSLoic Poulain { 5279a44c1ccSLoic Poulain wwan_class = class_create(THIS_MODULE, "wwan"); 5289a44c1ccSLoic Poulain if (IS_ERR(wwan_class)) 5299a44c1ccSLoic Poulain return PTR_ERR(wwan_class); 5309a44c1ccSLoic Poulain 5319a44c1ccSLoic Poulain /* chrdev used for wwan ports */ 5329a44c1ccSLoic Poulain wwan_major = register_chrdev(0, "wwan_port", &wwan_port_fops); 5339a44c1ccSLoic Poulain if (wwan_major < 0) { 5349a44c1ccSLoic Poulain class_destroy(wwan_class); 5359a44c1ccSLoic Poulain return wwan_major; 5369a44c1ccSLoic Poulain } 5379a44c1ccSLoic Poulain 5389a44c1ccSLoic Poulain return 0; 5399a44c1ccSLoic Poulain } 5409a44c1ccSLoic Poulain 5419a44c1ccSLoic Poulain static void __exit wwan_exit(void) 5429a44c1ccSLoic Poulain { 5439a44c1ccSLoic Poulain unregister_chrdev(wwan_major, "wwan_port"); 5449a44c1ccSLoic Poulain class_destroy(wwan_class); 5459a44c1ccSLoic Poulain } 5469a44c1ccSLoic Poulain 5479a44c1ccSLoic Poulain module_init(wwan_init); 5489a44c1ccSLoic Poulain module_exit(wwan_exit); 5499a44c1ccSLoic Poulain 5509a44c1ccSLoic Poulain MODULE_AUTHOR("Loic Poulain <loic.poulain@linaro.org>"); 5519a44c1ccSLoic Poulain MODULE_DESCRIPTION("WWAN core"); 5529a44c1ccSLoic Poulain MODULE_LICENSE("GPL v2"); 553