xref: /OK3568_Linux_fs/kernel/drivers/pnp/driver.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * driver.c - device id matching, driver model, etc.
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright 2002 Adam Belay <ambx1@neo.rr.com>
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #include <linux/string.h>
9*4882a593Smuzhiyun #include <linux/list.h>
10*4882a593Smuzhiyun #include <linux/module.h>
11*4882a593Smuzhiyun #include <linux/ctype.h>
12*4882a593Smuzhiyun #include <linux/slab.h>
13*4882a593Smuzhiyun #include <linux/pnp.h>
14*4882a593Smuzhiyun #include "base.h"
15*4882a593Smuzhiyun 
compare_func(const char * ida,const char * idb)16*4882a593Smuzhiyun static int compare_func(const char *ida, const char *idb)
17*4882a593Smuzhiyun {
18*4882a593Smuzhiyun 	int i;
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun 	/* we only need to compare the last 4 chars */
21*4882a593Smuzhiyun 	for (i = 3; i < 7; i++) {
22*4882a593Smuzhiyun 		if (ida[i] != 'X' &&
23*4882a593Smuzhiyun 		    idb[i] != 'X' && toupper(ida[i]) != toupper(idb[i]))
24*4882a593Smuzhiyun 			return 0;
25*4882a593Smuzhiyun 	}
26*4882a593Smuzhiyun 	return 1;
27*4882a593Smuzhiyun }
28*4882a593Smuzhiyun 
compare_pnp_id(struct pnp_id * pos,const char * id)29*4882a593Smuzhiyun int compare_pnp_id(struct pnp_id *pos, const char *id)
30*4882a593Smuzhiyun {
31*4882a593Smuzhiyun 	if (!pos || !id || (strlen(id) != 7))
32*4882a593Smuzhiyun 		return 0;
33*4882a593Smuzhiyun 	if (memcmp(id, "ANYDEVS", 7) == 0)
34*4882a593Smuzhiyun 		return 1;
35*4882a593Smuzhiyun 	while (pos) {
36*4882a593Smuzhiyun 		if (memcmp(pos->id, id, 3) == 0)
37*4882a593Smuzhiyun 			if (compare_func(pos->id, id) == 1)
38*4882a593Smuzhiyun 				return 1;
39*4882a593Smuzhiyun 		pos = pos->next;
40*4882a593Smuzhiyun 	}
41*4882a593Smuzhiyun 	return 0;
42*4882a593Smuzhiyun }
43*4882a593Smuzhiyun 
match_device(struct pnp_driver * drv,struct pnp_dev * dev)44*4882a593Smuzhiyun static const struct pnp_device_id *match_device(struct pnp_driver *drv,
45*4882a593Smuzhiyun 						struct pnp_dev *dev)
46*4882a593Smuzhiyun {
47*4882a593Smuzhiyun 	const struct pnp_device_id *drv_id = drv->id_table;
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun 	if (!drv_id)
50*4882a593Smuzhiyun 		return NULL;
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun 	while (*drv_id->id) {
53*4882a593Smuzhiyun 		if (compare_pnp_id(dev->id, drv_id->id))
54*4882a593Smuzhiyun 			return drv_id;
55*4882a593Smuzhiyun 		drv_id++;
56*4882a593Smuzhiyun 	}
57*4882a593Smuzhiyun 	return NULL;
58*4882a593Smuzhiyun }
59*4882a593Smuzhiyun 
pnp_device_attach(struct pnp_dev * pnp_dev)60*4882a593Smuzhiyun int pnp_device_attach(struct pnp_dev *pnp_dev)
61*4882a593Smuzhiyun {
62*4882a593Smuzhiyun 	mutex_lock(&pnp_lock);
63*4882a593Smuzhiyun 	if (pnp_dev->status != PNP_READY) {
64*4882a593Smuzhiyun 		mutex_unlock(&pnp_lock);
65*4882a593Smuzhiyun 		return -EBUSY;
66*4882a593Smuzhiyun 	}
67*4882a593Smuzhiyun 	pnp_dev->status = PNP_ATTACHED;
68*4882a593Smuzhiyun 	mutex_unlock(&pnp_lock);
69*4882a593Smuzhiyun 	return 0;
70*4882a593Smuzhiyun }
71*4882a593Smuzhiyun 
pnp_device_detach(struct pnp_dev * pnp_dev)72*4882a593Smuzhiyun void pnp_device_detach(struct pnp_dev *pnp_dev)
73*4882a593Smuzhiyun {
74*4882a593Smuzhiyun 	mutex_lock(&pnp_lock);
75*4882a593Smuzhiyun 	if (pnp_dev->status == PNP_ATTACHED)
76*4882a593Smuzhiyun 		pnp_dev->status = PNP_READY;
77*4882a593Smuzhiyun 	mutex_unlock(&pnp_lock);
78*4882a593Smuzhiyun }
79*4882a593Smuzhiyun 
pnp_device_probe(struct device * dev)80*4882a593Smuzhiyun static int pnp_device_probe(struct device *dev)
81*4882a593Smuzhiyun {
82*4882a593Smuzhiyun 	int error;
83*4882a593Smuzhiyun 	struct pnp_driver *pnp_drv;
84*4882a593Smuzhiyun 	struct pnp_dev *pnp_dev;
85*4882a593Smuzhiyun 	const struct pnp_device_id *dev_id = NULL;
86*4882a593Smuzhiyun 	pnp_dev = to_pnp_dev(dev);
87*4882a593Smuzhiyun 	pnp_drv = to_pnp_driver(dev->driver);
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun 	error = pnp_device_attach(pnp_dev);
90*4882a593Smuzhiyun 	if (error < 0)
91*4882a593Smuzhiyun 		return error;
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun 	if (pnp_dev->active == 0) {
94*4882a593Smuzhiyun 		if (!(pnp_drv->flags & PNP_DRIVER_RES_DO_NOT_CHANGE)) {
95*4882a593Smuzhiyun 			error = pnp_activate_dev(pnp_dev);
96*4882a593Smuzhiyun 			if (error < 0)
97*4882a593Smuzhiyun 				return error;
98*4882a593Smuzhiyun 		}
99*4882a593Smuzhiyun 	} else if ((pnp_drv->flags & PNP_DRIVER_RES_DISABLE)
100*4882a593Smuzhiyun 		   == PNP_DRIVER_RES_DISABLE) {
101*4882a593Smuzhiyun 		error = pnp_disable_dev(pnp_dev);
102*4882a593Smuzhiyun 		if (error < 0)
103*4882a593Smuzhiyun 			return error;
104*4882a593Smuzhiyun 	}
105*4882a593Smuzhiyun 	error = 0;
106*4882a593Smuzhiyun 	if (pnp_drv->probe) {
107*4882a593Smuzhiyun 		dev_id = match_device(pnp_drv, pnp_dev);
108*4882a593Smuzhiyun 		if (dev_id != NULL)
109*4882a593Smuzhiyun 			error = pnp_drv->probe(pnp_dev, dev_id);
110*4882a593Smuzhiyun 	}
111*4882a593Smuzhiyun 	if (error >= 0) {
112*4882a593Smuzhiyun 		pnp_dev->driver = pnp_drv;
113*4882a593Smuzhiyun 		error = 0;
114*4882a593Smuzhiyun 	} else
115*4882a593Smuzhiyun 		goto fail;
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun 	return error;
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun fail:
120*4882a593Smuzhiyun 	pnp_device_detach(pnp_dev);
121*4882a593Smuzhiyun 	return error;
122*4882a593Smuzhiyun }
123*4882a593Smuzhiyun 
pnp_device_remove(struct device * dev)124*4882a593Smuzhiyun static int pnp_device_remove(struct device *dev)
125*4882a593Smuzhiyun {
126*4882a593Smuzhiyun 	struct pnp_dev *pnp_dev = to_pnp_dev(dev);
127*4882a593Smuzhiyun 	struct pnp_driver *drv = pnp_dev->driver;
128*4882a593Smuzhiyun 
129*4882a593Smuzhiyun 	if (drv) {
130*4882a593Smuzhiyun 		if (drv->remove)
131*4882a593Smuzhiyun 			drv->remove(pnp_dev);
132*4882a593Smuzhiyun 		pnp_dev->driver = NULL;
133*4882a593Smuzhiyun 	}
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 	if (pnp_dev->active &&
136*4882a593Smuzhiyun 	    (!drv || !(drv->flags & PNP_DRIVER_RES_DO_NOT_CHANGE)))
137*4882a593Smuzhiyun 		pnp_disable_dev(pnp_dev);
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun 	pnp_device_detach(pnp_dev);
140*4882a593Smuzhiyun 	return 0;
141*4882a593Smuzhiyun }
142*4882a593Smuzhiyun 
pnp_device_shutdown(struct device * dev)143*4882a593Smuzhiyun static void pnp_device_shutdown(struct device *dev)
144*4882a593Smuzhiyun {
145*4882a593Smuzhiyun 	struct pnp_dev *pnp_dev = to_pnp_dev(dev);
146*4882a593Smuzhiyun 	struct pnp_driver *drv = pnp_dev->driver;
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun 	if (drv && drv->shutdown)
149*4882a593Smuzhiyun 		drv->shutdown(pnp_dev);
150*4882a593Smuzhiyun }
151*4882a593Smuzhiyun 
pnp_bus_match(struct device * dev,struct device_driver * drv)152*4882a593Smuzhiyun static int pnp_bus_match(struct device *dev, struct device_driver *drv)
153*4882a593Smuzhiyun {
154*4882a593Smuzhiyun 	struct pnp_dev *pnp_dev = to_pnp_dev(dev);
155*4882a593Smuzhiyun 	struct pnp_driver *pnp_drv = to_pnp_driver(drv);
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun 	if (match_device(pnp_drv, pnp_dev) == NULL)
158*4882a593Smuzhiyun 		return 0;
159*4882a593Smuzhiyun 	return 1;
160*4882a593Smuzhiyun }
161*4882a593Smuzhiyun 
__pnp_bus_suspend(struct device * dev,pm_message_t state)162*4882a593Smuzhiyun static int __pnp_bus_suspend(struct device *dev, pm_message_t state)
163*4882a593Smuzhiyun {
164*4882a593Smuzhiyun 	struct pnp_dev *pnp_dev = to_pnp_dev(dev);
165*4882a593Smuzhiyun 	struct pnp_driver *pnp_drv = pnp_dev->driver;
166*4882a593Smuzhiyun 	int error;
167*4882a593Smuzhiyun 
168*4882a593Smuzhiyun 	if (!pnp_drv)
169*4882a593Smuzhiyun 		return 0;
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun 	if (pnp_drv->driver.pm && pnp_drv->driver.pm->suspend) {
172*4882a593Smuzhiyun 		error = pnp_drv->driver.pm->suspend(dev);
173*4882a593Smuzhiyun 		suspend_report_result(pnp_drv->driver.pm->suspend, error);
174*4882a593Smuzhiyun 		if (error)
175*4882a593Smuzhiyun 			return error;
176*4882a593Smuzhiyun 	}
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun 	if (pnp_drv->suspend) {
179*4882a593Smuzhiyun 		error = pnp_drv->suspend(pnp_dev, state);
180*4882a593Smuzhiyun 		if (error)
181*4882a593Smuzhiyun 			return error;
182*4882a593Smuzhiyun 	}
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun 	if (pnp_can_disable(pnp_dev)) {
185*4882a593Smuzhiyun 		error = pnp_stop_dev(pnp_dev);
186*4882a593Smuzhiyun 		if (error)
187*4882a593Smuzhiyun 			return error;
188*4882a593Smuzhiyun 	}
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun 	if (pnp_can_suspend(pnp_dev))
191*4882a593Smuzhiyun 		pnp_dev->protocol->suspend(pnp_dev, state);
192*4882a593Smuzhiyun 	return 0;
193*4882a593Smuzhiyun }
194*4882a593Smuzhiyun 
pnp_bus_suspend(struct device * dev)195*4882a593Smuzhiyun static int pnp_bus_suspend(struct device *dev)
196*4882a593Smuzhiyun {
197*4882a593Smuzhiyun 	return __pnp_bus_suspend(dev, PMSG_SUSPEND);
198*4882a593Smuzhiyun }
199*4882a593Smuzhiyun 
pnp_bus_freeze(struct device * dev)200*4882a593Smuzhiyun static int pnp_bus_freeze(struct device *dev)
201*4882a593Smuzhiyun {
202*4882a593Smuzhiyun 	return __pnp_bus_suspend(dev, PMSG_FREEZE);
203*4882a593Smuzhiyun }
204*4882a593Smuzhiyun 
pnp_bus_poweroff(struct device * dev)205*4882a593Smuzhiyun static int pnp_bus_poweroff(struct device *dev)
206*4882a593Smuzhiyun {
207*4882a593Smuzhiyun 	return __pnp_bus_suspend(dev, PMSG_HIBERNATE);
208*4882a593Smuzhiyun }
209*4882a593Smuzhiyun 
pnp_bus_resume(struct device * dev)210*4882a593Smuzhiyun static int pnp_bus_resume(struct device *dev)
211*4882a593Smuzhiyun {
212*4882a593Smuzhiyun 	struct pnp_dev *pnp_dev = to_pnp_dev(dev);
213*4882a593Smuzhiyun 	struct pnp_driver *pnp_drv = pnp_dev->driver;
214*4882a593Smuzhiyun 	int error;
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun 	if (!pnp_drv)
217*4882a593Smuzhiyun 		return 0;
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun 	if (pnp_dev->protocol->resume) {
220*4882a593Smuzhiyun 		error = pnp_dev->protocol->resume(pnp_dev);
221*4882a593Smuzhiyun 		if (error)
222*4882a593Smuzhiyun 			return error;
223*4882a593Smuzhiyun 	}
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun 	if (pnp_can_write(pnp_dev)) {
226*4882a593Smuzhiyun 		error = pnp_start_dev(pnp_dev);
227*4882a593Smuzhiyun 		if (error)
228*4882a593Smuzhiyun 			return error;
229*4882a593Smuzhiyun 	}
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun 	if (pnp_drv->driver.pm && pnp_drv->driver.pm->resume) {
232*4882a593Smuzhiyun 		error = pnp_drv->driver.pm->resume(dev);
233*4882a593Smuzhiyun 		if (error)
234*4882a593Smuzhiyun 			return error;
235*4882a593Smuzhiyun 	}
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun 	if (pnp_drv->resume) {
238*4882a593Smuzhiyun 		error = pnp_drv->resume(pnp_dev);
239*4882a593Smuzhiyun 		if (error)
240*4882a593Smuzhiyun 			return error;
241*4882a593Smuzhiyun 	}
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun 	return 0;
244*4882a593Smuzhiyun }
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun static const struct dev_pm_ops pnp_bus_dev_pm_ops = {
247*4882a593Smuzhiyun 	/* Suspend callbacks */
248*4882a593Smuzhiyun 	.suspend = pnp_bus_suspend,
249*4882a593Smuzhiyun 	.resume = pnp_bus_resume,
250*4882a593Smuzhiyun 	/* Hibernate callbacks */
251*4882a593Smuzhiyun 	.freeze = pnp_bus_freeze,
252*4882a593Smuzhiyun 	.thaw = pnp_bus_resume,
253*4882a593Smuzhiyun 	.poweroff = pnp_bus_poweroff,
254*4882a593Smuzhiyun 	.restore = pnp_bus_resume,
255*4882a593Smuzhiyun };
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun struct bus_type pnp_bus_type = {
258*4882a593Smuzhiyun 	.name    = "pnp",
259*4882a593Smuzhiyun 	.match   = pnp_bus_match,
260*4882a593Smuzhiyun 	.probe   = pnp_device_probe,
261*4882a593Smuzhiyun 	.remove  = pnp_device_remove,
262*4882a593Smuzhiyun 	.shutdown = pnp_device_shutdown,
263*4882a593Smuzhiyun 	.pm	 = &pnp_bus_dev_pm_ops,
264*4882a593Smuzhiyun 	.dev_groups = pnp_dev_groups,
265*4882a593Smuzhiyun };
266*4882a593Smuzhiyun 
pnp_register_driver(struct pnp_driver * drv)267*4882a593Smuzhiyun int pnp_register_driver(struct pnp_driver *drv)
268*4882a593Smuzhiyun {
269*4882a593Smuzhiyun 	drv->driver.name = drv->name;
270*4882a593Smuzhiyun 	drv->driver.bus = &pnp_bus_type;
271*4882a593Smuzhiyun 
272*4882a593Smuzhiyun 	return driver_register(&drv->driver);
273*4882a593Smuzhiyun }
274*4882a593Smuzhiyun 
pnp_unregister_driver(struct pnp_driver * drv)275*4882a593Smuzhiyun void pnp_unregister_driver(struct pnp_driver *drv)
276*4882a593Smuzhiyun {
277*4882a593Smuzhiyun 	driver_unregister(&drv->driver);
278*4882a593Smuzhiyun }
279*4882a593Smuzhiyun 
280*4882a593Smuzhiyun /**
281*4882a593Smuzhiyun  * pnp_add_id - adds an EISA id to the specified device
282*4882a593Smuzhiyun  * @dev: pointer to the desired device
283*4882a593Smuzhiyun  * @id: pointer to an EISA id string
284*4882a593Smuzhiyun  */
pnp_add_id(struct pnp_dev * dev,const char * id)285*4882a593Smuzhiyun struct pnp_id *pnp_add_id(struct pnp_dev *dev, const char *id)
286*4882a593Smuzhiyun {
287*4882a593Smuzhiyun 	struct pnp_id *dev_id, *ptr;
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun 	dev_id = kzalloc(sizeof(struct pnp_id), GFP_KERNEL);
290*4882a593Smuzhiyun 	if (!dev_id)
291*4882a593Smuzhiyun 		return NULL;
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun 	dev_id->id[0] = id[0];
294*4882a593Smuzhiyun 	dev_id->id[1] = id[1];
295*4882a593Smuzhiyun 	dev_id->id[2] = id[2];
296*4882a593Smuzhiyun 	dev_id->id[3] = tolower(id[3]);
297*4882a593Smuzhiyun 	dev_id->id[4] = tolower(id[4]);
298*4882a593Smuzhiyun 	dev_id->id[5] = tolower(id[5]);
299*4882a593Smuzhiyun 	dev_id->id[6] = tolower(id[6]);
300*4882a593Smuzhiyun 	dev_id->id[7] = '\0';
301*4882a593Smuzhiyun 
302*4882a593Smuzhiyun 	dev_id->next = NULL;
303*4882a593Smuzhiyun 	ptr = dev->id;
304*4882a593Smuzhiyun 	while (ptr && ptr->next)
305*4882a593Smuzhiyun 		ptr = ptr->next;
306*4882a593Smuzhiyun 	if (ptr)
307*4882a593Smuzhiyun 		ptr->next = dev_id;
308*4882a593Smuzhiyun 	else
309*4882a593Smuzhiyun 		dev->id = dev_id;
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun 	return dev_id;
312*4882a593Smuzhiyun }
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun EXPORT_SYMBOL(pnp_register_driver);
315*4882a593Smuzhiyun EXPORT_SYMBOL(pnp_unregister_driver);
316*4882a593Smuzhiyun EXPORT_SYMBOL(pnp_device_attach);
317*4882a593Smuzhiyun EXPORT_SYMBOL(pnp_device_detach);
318