brintos

brintos / linux-shallow public Read only

0
0
Text · 4.9 KiB · 6a60c5d Raw
241 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * core.c - contains all core device and protocol registration functions4 *5 * Copyright 2002 Adam Belay <ambx1@neo.rr.com>6 */7 8#include <linux/pnp.h>9#include <linux/types.h>10#include <linux/list.h>11#include <linux/device.h>12#include <linux/module.h>13#include <linux/mutex.h>14#include <linux/init.h>15#include <linux/string.h>16#include <linux/slab.h>17#include <linux/errno.h>18#include <linux/dma-mapping.h>19 20#include "base.h"21 22static LIST_HEAD(pnp_protocols);23LIST_HEAD(pnp_global);24DEFINE_MUTEX(pnp_lock);25 26/*27 * ACPI or PNPBIOS should tell us about all platform devices, so we can28 * skip some blind probes.  ISAPNP typically enumerates only plug-in ISA29 * devices, not built-in things like COM ports.30 */31int pnp_platform_devices;32EXPORT_SYMBOL(pnp_platform_devices);33 34static void pnp_remove_protocol(struct pnp_protocol *protocol)35{36	mutex_lock(&pnp_lock);37	list_del(&protocol->protocol_list);38	mutex_unlock(&pnp_lock);39}40 41/**42 * pnp_register_protocol - adds a pnp protocol to the pnp layer43 * @protocol: pointer to the corresponding pnp_protocol structure44 *45 *  Ex protocols: ISAPNP, PNPBIOS, etc46 */47int pnp_register_protocol(struct pnp_protocol *protocol)48{49	struct list_head *pos;50	int nodenum, ret;51 52	INIT_LIST_HEAD(&protocol->devices);53	INIT_LIST_HEAD(&protocol->cards);54	nodenum = 0;55 56	mutex_lock(&pnp_lock);57 58	/* assign the lowest unused number */59	list_for_each(pos, &pnp_protocols) {60		struct pnp_protocol *cur = to_pnp_protocol(pos);61		if (cur->number == nodenum) {62			pos = &pnp_protocols;63			nodenum++;64		}65	}66 67	protocol->number = nodenum;68	dev_set_name(&protocol->dev, "pnp%d", nodenum);69 70	list_add_tail(&protocol->protocol_list, &pnp_protocols);71 72	mutex_unlock(&pnp_lock);73 74	ret = device_register(&protocol->dev);75	if (ret)76		pnp_remove_protocol(protocol);77 78	return ret;79}80 81/**82 * pnp_unregister_protocol - removes a pnp protocol from the pnp layer83 * @protocol: pointer to the corresponding pnp_protocol structure84 */85void pnp_unregister_protocol(struct pnp_protocol *protocol)86{87	pnp_remove_protocol(protocol);88	device_unregister(&protocol->dev);89}90 91static void pnp_free_ids(struct pnp_dev *dev)92{93	struct pnp_id *id;94	struct pnp_id *next;95 96	id = dev->id;97	while (id) {98		next = id->next;99		kfree(id);100		id = next;101	}102}103 104void pnp_free_resource(struct pnp_resource *pnp_res)105{106	list_del(&pnp_res->list);107	kfree(pnp_res);108}109 110void pnp_free_resources(struct pnp_dev *dev)111{112	struct pnp_resource *pnp_res, *tmp;113 114	list_for_each_entry_safe(pnp_res, tmp, &dev->resources, list) {115		pnp_free_resource(pnp_res);116	}117}118 119static void pnp_release_device(struct device *dmdev)120{121	struct pnp_dev *dev = to_pnp_dev(dmdev);122 123	pnp_free_ids(dev);124	pnp_free_resources(dev);125	pnp_free_options(dev);126	kfree(dev);127}128 129struct pnp_dev *pnp_alloc_dev(struct pnp_protocol *protocol, int id,130			      const char *pnpid)131{132	struct pnp_dev *dev;133	struct pnp_id *dev_id;134 135	dev = kzalloc(sizeof(struct pnp_dev), GFP_KERNEL);136	if (!dev)137		return NULL;138 139	INIT_LIST_HEAD(&dev->resources);140	INIT_LIST_HEAD(&dev->options);141	dev->protocol = protocol;142	dev->number = id;143	dev->dma_mask = DMA_BIT_MASK(24);144 145	dev->dev.parent = &dev->protocol->dev;146	dev->dev.bus = &pnp_bus_type;147	dev->dev.dma_mask = &dev->dma_mask;148	dev->dev.coherent_dma_mask = dev->dma_mask;149	dev->dev.release = &pnp_release_device;150 151	dev_id = pnp_add_id(dev, pnpid);152	if (!dev_id) {153		kfree(dev);154		return NULL;155	}156 157	dev_set_name(&dev->dev, "%02x:%02x", dev->protocol->number, dev->number);158 159	return dev;160}161 162static void pnp_delist_device(struct pnp_dev *dev)163{164	mutex_lock(&pnp_lock);165	list_del(&dev->global_list);166	list_del(&dev->protocol_list);167	mutex_unlock(&pnp_lock);168}169 170int __pnp_add_device(struct pnp_dev *dev)171{172	int ret;173 174	pnp_fixup_device(dev);175	dev->status = PNP_READY;176 177	mutex_lock(&pnp_lock);178 179	list_add_tail(&dev->global_list, &pnp_global);180	list_add_tail(&dev->protocol_list, &dev->protocol->devices);181 182	mutex_unlock(&pnp_lock);183 184	ret = device_register(&dev->dev);185	if (ret)186		pnp_delist_device(dev);187	else if (dev->protocol->can_wakeup)188		device_set_wakeup_capable(&dev->dev,189				dev->protocol->can_wakeup(dev));190 191	return ret;192}193 194/*195 * pnp_add_device - adds a pnp device to the pnp layer196 * @dev: pointer to dev to add197 *198 *  adds to driver model, name database, fixups, interface, etc.199 */200int pnp_add_device(struct pnp_dev *dev)201{202	int ret;203	char buf[128];204	int len = 0;205	struct pnp_id *id;206 207	if (dev->card)208		return -EINVAL;209 210	ret = __pnp_add_device(dev);211	if (ret)212		return ret;213 214	buf[0] = '\0';215	for (id = dev->id; id; id = id->next)216		len += scnprintf(buf + len, sizeof(buf) - len, " %s", id->id);217 218	dev_dbg(&dev->dev, "%s device, IDs%s (%s)\n", dev->protocol->name, buf,219		dev->active ? "active" : "disabled");220	return 0;221}222 223void __pnp_remove_device(struct pnp_dev *dev)224{225	pnp_delist_device(dev);226	device_unregister(&dev->dev);227}228 229static int __init pnp_init(void)230{231	return bus_register(&pnp_bus_type);232}233 234subsys_initcall(pnp_init);235 236int pnp_debug;237 238#if defined(CONFIG_PNP_DEBUG_MESSAGES)239module_param_named(debug, pnp_debug, int, 0644);240#endif241