Blame view

drivers/pnp/driver.c 6.4 KB
b24413180   Greg Kroah-Hartman   License cleanup: ...
1
  // SPDX-License-Identifier: GPL-2.0
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
  /*
   * driver.c - device id matching, driver model, etc.
   *
   * Copyright 2002 Adam Belay <ambx1@neo.rr.com>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7
8
9
10
11
  #include <linux/string.h>
  #include <linux/list.h>
  #include <linux/module.h>
  #include <linux/ctype.h>
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
12
13
14
15
16
17
  #include <linux/pnp.h>
  #include "base.h"
  
  static int compare_func(const char *ida, const char *idb)
  {
  	int i;
07d4e9af1   Bjorn Helgaas   PNP: fix up after...
18

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19
  	/* we only need to compare the last 4 chars */
9dd78466c   Bjorn Helgaas   PNP: Lindent all ...
20
  	for (i = 3; i < 7; i++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21
  		if (ida[i] != 'X' &&
9dd78466c   Bjorn Helgaas   PNP: Lindent all ...
22
  		    idb[i] != 'X' && toupper(ida[i]) != toupper(idb[i]))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
24
25
26
27
28
29
30
31
  			return 0;
  	}
  	return 1;
  }
  
  int compare_pnp_id(struct pnp_id *pos, const char *id)
  {
  	if (!pos || !id || (strlen(id) != 7))
  		return 0;
9dd78466c   Bjorn Helgaas   PNP: Lindent all ...
32
  	if (memcmp(id, "ANYDEVS", 7) == 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
33
  		return 1;
9dd78466c   Bjorn Helgaas   PNP: Lindent all ...
34
35
36
  	while (pos) {
  		if (memcmp(pos->id, id, 3) == 0)
  			if (compare_func(pos->id, id) == 1)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37
38
39
40
41
  				return 1;
  		pos = pos->next;
  	}
  	return 0;
  }
9dd78466c   Bjorn Helgaas   PNP: Lindent all ...
42
43
  static const struct pnp_device_id *match_device(struct pnp_driver *drv,
  						struct pnp_dev *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44
45
  {
  	const struct pnp_device_id *drv_id = drv->id_table;
07d4e9af1   Bjorn Helgaas   PNP: fix up after...
46

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47
48
49
50
51
52
53
54
55
56
57
58
59
  	if (!drv_id)
  		return NULL;
  
  	while (*drv_id->id) {
  		if (compare_pnp_id(dev->id, drv_id->id))
  			return drv_id;
  		drv_id++;
  	}
  	return NULL;
  }
  
  int pnp_device_attach(struct pnp_dev *pnp_dev)
  {
38f6b38db   Rafael J. Wysocki   PNP: Convert pnp_...
60
  	mutex_lock(&pnp_lock);
9dd78466c   Bjorn Helgaas   PNP: Lindent all ...
61
  	if (pnp_dev->status != PNP_READY) {
38f6b38db   Rafael J. Wysocki   PNP: Convert pnp_...
62
  		mutex_unlock(&pnp_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
63
64
65
  		return -EBUSY;
  	}
  	pnp_dev->status = PNP_ATTACHED;
38f6b38db   Rafael J. Wysocki   PNP: Convert pnp_...
66
  	mutex_unlock(&pnp_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
67
68
69
70
71
  	return 0;
  }
  
  void pnp_device_detach(struct pnp_dev *pnp_dev)
  {
38f6b38db   Rafael J. Wysocki   PNP: Convert pnp_...
72
  	mutex_lock(&pnp_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
73
74
  	if (pnp_dev->status == PNP_ATTACHED)
  		pnp_dev->status = PNP_READY;
38f6b38db   Rafael J. Wysocki   PNP: Convert pnp_...
75
  	mutex_unlock(&pnp_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
76
77
78
79
80
81
82
83
84
85
  }
  
  static int pnp_device_probe(struct device *dev)
  {
  	int error;
  	struct pnp_driver *pnp_drv;
  	struct pnp_dev *pnp_dev;
  	const struct pnp_device_id *dev_id = NULL;
  	pnp_dev = to_pnp_dev(dev);
  	pnp_drv = to_pnp_driver(dev->driver);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
86
87
88
89
90
91
92
93
94
95
96
  	error = pnp_device_attach(pnp_dev);
  	if (error < 0)
  		return error;
  
  	if (pnp_dev->active == 0) {
  		if (!(pnp_drv->flags & PNP_DRIVER_RES_DO_NOT_CHANGE)) {
  			error = pnp_activate_dev(pnp_dev);
  			if (error < 0)
  				return error;
  		}
  	} else if ((pnp_drv->flags & PNP_DRIVER_RES_DISABLE)
9dd78466c   Bjorn Helgaas   PNP: Lindent all ...
97
  		   == PNP_DRIVER_RES_DISABLE) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
98
99
100
101
102
103
104
105
106
107
  		error = pnp_disable_dev(pnp_dev);
  		if (error < 0)
  			return error;
  	}
  	error = 0;
  	if (pnp_drv->probe) {
  		dev_id = match_device(pnp_drv, pnp_dev);
  		if (dev_id != NULL)
  			error = pnp_drv->probe(pnp_dev, dev_id);
  	}
9dd78466c   Bjorn Helgaas   PNP: Lindent all ...
108
  	if (error >= 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
109
110
111
112
  		pnp_dev->driver = pnp_drv;
  		error = 0;
  	} else
  		goto fail;
a05d07816   Bjorn Helgaas   PNP: use dev_info...
113

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
114
  	return error;
1e0aa9ad7   Bjorn Helgaas   PNP: fix up after...
115
  fail:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
116
117
118
119
120
121
  	pnp_device_detach(pnp_dev);
  	return error;
  }
  
  static int pnp_device_remove(struct device *dev)
  {
9dd78466c   Bjorn Helgaas   PNP: Lindent all ...
122
123
  	struct pnp_dev *pnp_dev = to_pnp_dev(dev);
  	struct pnp_driver *drv = pnp_dev->driver;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
124
125
126
127
128
129
  
  	if (drv) {
  		if (drv->remove)
  			drv->remove(pnp_dev);
  		pnp_dev->driver = NULL;
  	}
e0f03e87f   Heiner Kallweit   PNP: respect PNP_...
130
131
132
133
  
  	if (pnp_dev->active &&
  	    (!drv || !(drv->flags & PNP_DRIVER_RES_DO_NOT_CHANGE)))
  		pnp_disable_dev(pnp_dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
134
135
136
  	pnp_device_detach(pnp_dev);
  	return 0;
  }
abd6633c6   David Härdeman   pnp: add a shutdo...
137
138
139
140
141
142
143
144
  static void pnp_device_shutdown(struct device *dev)
  {
  	struct pnp_dev *pnp_dev = to_pnp_dev(dev);
  	struct pnp_driver *drv = pnp_dev->driver;
  
  	if (drv && drv->shutdown)
  		drv->shutdown(pnp_dev);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
145
146
  static int pnp_bus_match(struct device *dev, struct device_driver *drv)
  {
9dd78466c   Bjorn Helgaas   PNP: Lindent all ...
147
148
  	struct pnp_dev *pnp_dev = to_pnp_dev(dev);
  	struct pnp_driver *pnp_drv = to_pnp_driver(drv);
07d4e9af1   Bjorn Helgaas   PNP: fix up after...
149

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
150
151
152
153
  	if (match_device(pnp_drv, pnp_dev) == NULL)
  		return 0;
  	return 1;
  }
eaf140b60   Shuah Khan   PNP: convert PNP ...
154
  static int __pnp_bus_suspend(struct device *dev, pm_message_t state)
4c98cfef2   Takashi Iwai   [ALSA] PATCH] Add...
155
  {
9dd78466c   Bjorn Helgaas   PNP: Lindent all ...
156
157
  	struct pnp_dev *pnp_dev = to_pnp_dev(dev);
  	struct pnp_driver *pnp_drv = pnp_dev->driver;
68094e325   Pierre Ossman   [ALSA] [PATCH] al...
158
159
160
161
  	int error;
  
  	if (!pnp_drv)
  		return 0;
729377d55   Shuah Khan   pnp: change pnp b...
162
163
164
165
166
167
  	if (pnp_drv->driver.pm && pnp_drv->driver.pm->suspend) {
  		error = pnp_drv->driver.pm->suspend(dev);
  		suspend_report_result(pnp_drv->driver.pm->suspend, error);
  		if (error)
  			return error;
  	}
68094e325   Pierre Ossman   [ALSA] [PATCH] al...
168
169
170
171
172
  	if (pnp_drv->suspend) {
  		error = pnp_drv->suspend(pnp_dev, state);
  		if (error)
  			return error;
  	}
5d38998ed   Rene Herman   PNP: do not test ...
173
  	if (pnp_can_disable(pnp_dev)) {
9dd78466c   Bjorn Helgaas   PNP: Lindent all ...
174
175
176
  		error = pnp_stop_dev(pnp_dev);
  		if (error)
  			return error;
68094e325   Pierre Ossman   [ALSA] [PATCH] al...
177
  	}
4c98cfef2   Takashi Iwai   [ALSA] PATCH] Add...
178

01395d798   Peter Hurley   PNP: Allow consol...
179
  	if (pnp_can_suspend(pnp_dev))
fc30e68e8   Shaohua Li   ACPI, PNP: hook A...
180
  		pnp_dev->protocol->suspend(pnp_dev, state);
4c98cfef2   Takashi Iwai   [ALSA] PATCH] Add...
181
182
  	return 0;
  }
eaf140b60   Shuah Khan   PNP: convert PNP ...
183
184
185
186
187
188
189
190
191
  static int pnp_bus_suspend(struct device *dev)
  {
  	return __pnp_bus_suspend(dev, PMSG_SUSPEND);
  }
  
  static int pnp_bus_freeze(struct device *dev)
  {
  	return __pnp_bus_suspend(dev, PMSG_FREEZE);
  }
8a37ea50e   Dmitry Torokhov   PNP: fix restorin...
192
193
194
195
  static int pnp_bus_poweroff(struct device *dev)
  {
  	return __pnp_bus_suspend(dev, PMSG_HIBERNATE);
  }
68094e325   Pierre Ossman   [ALSA] [PATCH] al...
196
  static int pnp_bus_resume(struct device *dev)
4c98cfef2   Takashi Iwai   [ALSA] PATCH] Add...
197
  {
9dd78466c   Bjorn Helgaas   PNP: Lindent all ...
198
199
  	struct pnp_dev *pnp_dev = to_pnp_dev(dev);
  	struct pnp_driver *pnp_drv = pnp_dev->driver;
68094e325   Pierre Ossman   [ALSA] [PATCH] al...
200
201
202
203
  	int error;
  
  	if (!pnp_drv)
  		return 0;
cc8e7a355   Rafael J. Wysocki   PNP / ACPI: Use D...
204
205
206
207
208
  	if (pnp_dev->protocol->resume) {
  		error = pnp_dev->protocol->resume(pnp_dev);
  		if (error)
  			return error;
  	}
fc30e68e8   Shaohua Li   ACPI, PNP: hook A...
209

5d38998ed   Rene Herman   PNP: do not test ...
210
  	if (pnp_can_write(pnp_dev)) {
68094e325   Pierre Ossman   [ALSA] [PATCH] al...
211
212
213
214
  		error = pnp_start_dev(pnp_dev);
  		if (error)
  			return error;
  	}
4c98cfef2   Takashi Iwai   [ALSA] PATCH] Add...
215

729377d55   Shuah Khan   pnp: change pnp b...
216
217
218
219
220
  	if (pnp_drv->driver.pm && pnp_drv->driver.pm->resume) {
  		error = pnp_drv->driver.pm->resume(dev);
  		if (error)
  			return error;
  	}
5d38998ed   Rene Herman   PNP: do not test ...
221
222
223
224
225
  	if (pnp_drv->resume) {
  		error = pnp_drv->resume(pnp_dev);
  		if (error)
  			return error;
  	}
68094e325   Pierre Ossman   [ALSA] [PATCH] al...
226
227
  
  	return 0;
4c98cfef2   Takashi Iwai   [ALSA] PATCH] Add...
228
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
229

eaf140b60   Shuah Khan   PNP: convert PNP ...
230
  static const struct dev_pm_ops pnp_bus_dev_pm_ops = {
8a37ea50e   Dmitry Torokhov   PNP: fix restorin...
231
  	/* Suspend callbacks */
eaf140b60   Shuah Khan   PNP: convert PNP ...
232
  	.suspend = pnp_bus_suspend,
eaf140b60   Shuah Khan   PNP: convert PNP ...
233
  	.resume = pnp_bus_resume,
8a37ea50e   Dmitry Torokhov   PNP: fix restorin...
234
235
236
237
238
  	/* Hibernate callbacks */
  	.freeze = pnp_bus_freeze,
  	.thaw = pnp_bus_resume,
  	.poweroff = pnp_bus_poweroff,
  	.restore = pnp_bus_resume,
eaf140b60   Shuah Khan   PNP: convert PNP ...
239
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
240
  struct bus_type pnp_bus_type = {
07d4e9af1   Bjorn Helgaas   PNP: fix up after...
241
242
243
244
  	.name    = "pnp",
  	.match   = pnp_bus_match,
  	.probe   = pnp_device_probe,
  	.remove  = pnp_device_remove,
abd6633c6   David Härdeman   pnp: add a shutdo...
245
  	.shutdown = pnp_device_shutdown,
eaf140b60   Shuah Khan   PNP: convert PNP ...
246
  	.pm	 = &pnp_bus_dev_pm_ops,
2df439013   Greg Kroah-Hartman   PNP: convert bus ...
247
  	.dev_groups = pnp_dev_groups,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
248
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
249
250
  int pnp_register_driver(struct pnp_driver *drv)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
251
252
  	drv->driver.name = drv->name;
  	drv->driver.bus = &pnp_bus_type;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
253

982c60944   Bjorn Helgaas   [PATCH] pnp: PNP:...
254
  	return driver_register(&drv->driver);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
255
256
257
258
259
  }
  
  void pnp_unregister_driver(struct pnp_driver *drv)
  {
  	driver_unregister(&drv->driver);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
260
261
262
263
  }
  
  /**
   * pnp_add_id - adds an EISA id to the specified device
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
264
   * @dev: pointer to the desired device
772defc62   Bjorn Helgaas   PNP: change pnp_a...
265
   * @id: pointer to an EISA id string
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
266
   */
620e112cf   Thomas Renninger   ACPI/PNP: A HID v...
267
  struct pnp_id *pnp_add_id(struct pnp_dev *dev, const char *id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
268
  {
772defc62   Bjorn Helgaas   PNP: change pnp_a...
269
  	struct pnp_id *dev_id, *ptr;
07d4e9af1   Bjorn Helgaas   PNP: fix up after...
270

772defc62   Bjorn Helgaas   PNP: change pnp_a...
271
272
273
274
275
276
277
278
279
280
281
282
283
284
  	dev_id = kzalloc(sizeof(struct pnp_id), GFP_KERNEL);
  	if (!dev_id)
  		return NULL;
  
  	dev_id->id[0] = id[0];
  	dev_id->id[1] = id[1];
  	dev_id->id[2] = id[2];
  	dev_id->id[3] = tolower(id[3]);
  	dev_id->id[4] = tolower(id[4]);
  	dev_id->id[5] = tolower(id[5]);
  	dev_id->id[6] = tolower(id[6]);
  	dev_id->id[7] = '\0';
  
  	dev_id->next = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
285
286
287
288
  	ptr = dev->id;
  	while (ptr && ptr->next)
  		ptr = ptr->next;
  	if (ptr)
772defc62   Bjorn Helgaas   PNP: change pnp_a...
289
  		ptr->next = dev_id;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
290
  	else
772defc62   Bjorn Helgaas   PNP: change pnp_a...
291
292
293
  		dev->id = dev_id;
  
  	return dev_id;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
294
295
296
297
  }
  
  EXPORT_SYMBOL(pnp_register_driver);
  EXPORT_SYMBOL(pnp_unregister_driver);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
298
299
  EXPORT_SYMBOL(pnp_device_attach);
  EXPORT_SYMBOL(pnp_device_detach);