FILE
serial_base_bus.c
File preview with syntax highlighting.
linux-6.19.14/drivers/tty/serial/serial_base_bus.c
1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Serial base bus layer for controllers 4 * 5 * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ 6 * Author: Tony Lindgren <tony@atomide.com> 7 * 8 * The serial core bus manages the serial core controller instances. 9 */ 10 11#include <linux/cleanup.h> 12#include <linux/container_of.h> 13#include <linux/device.h> 14#include <linux/idr.h> 15#include <linux/module.h> 16#include <linux/property.h> 17#include <linux/serial_core.h> 18#include <linux/slab.h> 19#include <linux/spinlock.h> 20 21#include "serial_base.h" 22 23static bool serial_base_initialized; 24 25static const struct device_type serial_ctrl_type = { 26 .name = "ctrl", 27}; 28 29static const struct device_type serial_port_type = { 30 .name = "port", 31}; 32 33static int serial_base_match(struct device *dev, const struct device_driver *drv) 34{ 35 if (dev->type == &serial_ctrl_type && 36 str_has_prefix(drv->name, serial_ctrl_type.name)) 37 return 1; 38 39 if (dev->type == &serial_port_type && 40 str_has_prefix(drv->name, serial_port_type.name)) 41 return 1; 42 43 return 0; 44} 45 46static const struct bus_type serial_base_bus_type = { 47 .name = "serial-base", 48 .match = serial_base_match, 49}; 50 51int serial_base_driver_register(struct device_driver *driver) 52{ 53 driver->bus = &serial_base_bus_type; 54 55 return driver_register(driver); 56} 57 58void serial_base_driver_unregister(struct device_driver *driver) 59{ 60 driver_unregister(driver); 61} 62 63/* On failure the caller must put device @dev with put_device() */ 64static int serial_base_device_init(struct uart_port *port, 65 struct device *dev, 66 struct device *parent_dev, 67 const struct device_type *type, 68 void (*release)(struct device *dev), 69 unsigned int ctrl_id, 70 unsigned int port_id) 71{ 72 device_initialize(dev); 73 dev->type = type; 74 dev->parent = parent_dev; 75 dev->bus = &serial_base_bus_type; 76 dev->release = release; 77 dev->of_node_reused = true; 78 79 device_set_node(dev, fwnode_handle_get(dev_fwnode(parent_dev))); 80 81 if (!serial_base_initialized) { 82 dev_dbg(port->dev, "uart_add_one_port() called before arch_initcall()?\n"); 83 return -EPROBE_DEFER; 84 } 85 86 if (type == &serial_ctrl_type) 87 return dev_set_name(dev, "%s:%d", dev_name(port->dev), ctrl_id); 88 89 if (type == &serial_port_type) 90 return dev_set_name(dev, "%s:%d.%d", dev_name(port->dev), 91 ctrl_id, port_id); 92 93 return -EINVAL; 94} 95 96static void serial_base_ctrl_release(struct device *dev) 97{ 98 struct serial_ctrl_device *ctrl_dev = to_serial_base_ctrl_device(dev); 99 100 fwnode_handle_put(dev_fwnode(dev)); 101 kfree(ctrl_dev); 102} 103 104void serial_base_ctrl_device_remove(struct serial_ctrl_device *ctrl_dev) 105{ 106 if (!ctrl_dev) 107 return; 108 109 device_del(&ctrl_dev->dev); 110 put_device(&ctrl_dev->dev); 111} 112 113struct serial_ctrl_device *serial_base_ctrl_add(struct uart_port *port, 114 struct device *parent) 115{ 116 struct serial_ctrl_device *ctrl_dev; 117 int err; 118 119 ctrl_dev = kzalloc(sizeof(*ctrl_dev), GFP_KERNEL); 120 if (!ctrl_dev) 121 return ERR_PTR(-ENOMEM); 122 123 ida_init(&ctrl_dev->port_ida); 124 125 err = serial_base_device_init(port, &ctrl_dev->dev, 126 parent, &serial_ctrl_type, 127 serial_base_ctrl_release, 128 port->ctrl_id, 0); 129 if (err) 130 goto err_put_device; 131 132 err = device_add(&ctrl_dev->dev); 133 if (err) 134 goto err_put_device; 135 136 return ctrl_dev; 137 138err_put_device: 139 put_device(&ctrl_dev->dev); 140 141 return ERR_PTR(err); 142} 143 144static void serial_base_port_release(struct device *dev) 145{ 146 struct serial_port_device *port_dev = to_serial_base_port_device(dev); 147 148 fwnode_handle_put(dev_fwnode(dev)); 149 kfree(port_dev); 150} 151 152struct serial_port_device *serial_base_port_add(struct uart_port *port, 153 struct serial_ctrl_device *ctrl_dev) 154{ 155 struct serial_port_device *port_dev; 156 int min = 0, max = -1; /* Use -1 for max to apply IDA defaults */ 157 int err; 158 159 port_dev = kzalloc(sizeof(*port_dev), GFP_KERNEL); 160 if (!port_dev) 161 return ERR_PTR(-ENOMEM); 162 163 /* Device driver specified port_id vs automatic assignment? */ 164 if (port->port_id) { 165 min = port->port_id; 166 max = port->port_id; 167 } 168 169 err = ida_alloc_range(&ctrl_dev->port_ida, min, max, GFP_KERNEL); 170 if (err < 0) { 171 kfree(port_dev); 172 return ERR_PTR(err); 173 } 174 175 port->port_id = err; 176 177 err = serial_base_device_init(port, &port_dev->dev, 178 &ctrl_dev->dev, &serial_port_type, 179 serial_base_port_release, 180 port->ctrl_id, port->port_id); 181 if (err) 182 goto err_put_device; 183 184 port_dev->port = port; 185 186 err = device_add(&port_dev->dev); 187 if (err) 188 goto err_put_device; 189 190 return port_dev; 191 192err_put_device: 193 put_device(&port_dev->dev); 194 ida_free(&ctrl_dev->port_ida, port->port_id); 195 196 return ERR_PTR(err); 197} 198 199void serial_base_port_device_remove(struct serial_port_device *port_dev) 200{ 201 struct serial_ctrl_device *ctrl_dev; 202 struct device *parent; 203 204 if (!port_dev) 205 return; 206 207 parent = port_dev->dev.parent; 208 ctrl_dev = to_serial_base_ctrl_device(parent); 209 210 device_del(&port_dev->dev); 211 ida_free(&ctrl_dev->port_ida, port_dev->port->port_id); 212 put_device(&port_dev->dev); 213} 214 215#ifdef CONFIG_SERIAL_CORE_CONSOLE 216 217/** 218 * serial_base_match_and_update_preferred_console - Match and update a preferred console 219 * @drv: Serial port device driver 220 * @port: Serial port instance 221 * 222 * Tries to match and update the preferred console for a serial port for 223 * the kernel command line option console=DEVNAME:0.0. 224 * 225 * Cannot be called early for ISA ports, depends on struct device. 226 * 227 * Return: 0 on success, negative error code on failure. 228 */ 229int serial_base_match_and_update_preferred_console(struct uart_driver *drv, 230 struct uart_port *port) 231{ 232 const char *port_match __free(kfree) = NULL; 233 int ret; 234 235 port_match = kasprintf(GFP_KERNEL, "%s:%d.%d", dev_name(port->dev), 236 port->ctrl_id, port->port_id); 237 if (!port_match) 238 return -ENOMEM; 239 240 ret = match_devname_and_update_preferred_console(port_match, 241 drv->dev_name, 242 port->line); 243 if (ret == -ENOENT) 244 return 0; 245 246 return ret; 247} 248 249#endif 250 251static int serial_base_init(void) 252{ 253 int ret; 254 255 ret = bus_register(&serial_base_bus_type); 256 if (ret) 257 return ret; 258 259 ret = serial_base_ctrl_init(); 260 if (ret) 261 goto err_bus_unregister; 262 263 ret = serial_base_port_init(); 264 if (ret) 265 goto err_ctrl_exit; 266 267 serial_base_initialized = true; 268 269 return 0; 270 271err_ctrl_exit: 272 serial_base_ctrl_exit(); 273 274err_bus_unregister: 275 bus_unregister(&serial_base_bus_type); 276 277 return ret; 278} 279arch_initcall(serial_base_init); 280 281static void serial_base_exit(void) 282{ 283 serial_base_port_exit(); 284 serial_base_ctrl_exit(); 285 bus_unregister(&serial_base_bus_type); 286} 287module_exit(serial_base_exit); 288 289MODULE_AUTHOR("Tony Lindgren <tony@atomide.com>"); 290MODULE_DESCRIPTION("Serial core bus"); 291MODULE_LICENSE("GPL");
~/
Read-only file preview.