brintos

brintos / linux-shallow public Read only

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