File: /usr/src/linux/drivers/acpi/ospm/busmgr/bmnotify.c
1 /*****************************************************************************
2 *
3 * Module Name: bmnotify.c
4 * $Revision: 21 $
5 *
6 *****************************************************************************/
7
8 /*
9 * Copyright (C) 2000, 2001 Andrew Grover
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25
26
27 #include <acpi.h>
28 #include "bm.h"
29
30
31 #define _COMPONENT ACPI_BUS
32 MODULE_NAME ("bmnotify")
33
34
35 /****************************************************************************
36 * Internal Functions
37 ****************************************************************************/
38
39 /****************************************************************************
40 *
41 * FUNCTION: bm_generate_notify
42 *
43 * PARAMETERS:
44 *
45 * RETURN:
46 *
47 * DESCRIPTION:
48 *
49 ****************************************************************************/
50
51 acpi_status
52 bm_generate_notify (
53 BM_NODE *node,
54 u32 notify_type)
55 {
56 acpi_status status = AE_OK;
57 BM_DEVICE *device = NULL;
58
59 FUNCTION_TRACE("bm_generate_notify");
60
61 if (!node) {
62 return_ACPI_STATUS(AE_BAD_PARAMETER);
63 }
64
65 device = &(node->device);
66
67 ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Sending notify [%02x] to device [%02x].\n", notify_type, node->device.handle));
68
69 if (!BM_IS_DRIVER_CONTROL(device)) {
70 ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "No driver installed for device [%02x].\n", device->handle));
71 return_ACPI_STATUS(AE_NOT_EXIST);
72 }
73
74 status = node->driver.notify(notify_type, node->device.handle,
75 &(node->driver.context));
76
77 return_ACPI_STATUS(status);
78 }
79
80
81 /****************************************************************************
82 *
83 * FUNCTION: bm_device_check
84 *
85 * PARAMETERS:
86 *
87 * RETURN:
88 *
89 * DESCRIPTION:
90 *
91 ****************************************************************************/
92
93 acpi_status
94 bm_device_check (
95 BM_NODE *node,
96 u32 *status_change)
97 {
98 acpi_status status = AE_OK;
99 BM_DEVICE *device = NULL;
100 BM_DEVICE_STATUS old_status = BM_STATUS_UNKNOWN;
101
102 FUNCTION_TRACE("bm_device_check");
103
104 if (!node) {
105 return_ACPI_STATUS(AE_BAD_PARAMETER);
106 }
107
108 device = &(node->device);
109
110 if (status_change) {
111 *status_change = FALSE;
112 }
113
114 old_status = device->status;
115
116 /*
117 * Parent Present?
118 * ---------------
119 * Only check this device if its parent is present (which implies
120 * this device MAY be present).
121 */
122 if (!BM_NODE_PRESENT(node->parent)) {
123 return_ACPI_STATUS(AE_OK);
124 }
125
126 /*
127 * Get Status:
128 * -----------
129 * And see if the status has changed.
130 */
131 status = bm_get_status(device);
132 if (ACPI_FAILURE(status)) {
133 return_ACPI_STATUS(status);
134 }
135
136 if (old_status == node->device.status) {
137 return_ACPI_STATUS(AE_OK);
138 }
139
140 if (status_change) {
141 *status_change = TRUE;
142 }
143
144 /*
145 * Device Insertion?
146 * -----------------
147 */
148 if ((device->status & BM_STATUS_PRESENT) &&
149 !(old_status & BM_STATUS_PRESENT)) {
150 /* TBD: Make sure driver is loaded, and if not, load. */
151 status = bm_generate_notify(node, BM_NOTIFY_DEVICE_ADDED);
152 }
153
154 /*
155 * Device Removal?
156 * ---------------
157 */
158 else if (!(device->status & BM_STATUS_PRESENT) &&
159 (old_status & BM_STATUS_PRESENT)) {
160 /* TBD: Unload driver if last device instance. */
161 status = bm_generate_notify(node, BM_NOTIFY_DEVICE_REMOVED);
162 }
163
164 return_ACPI_STATUS(AE_OK);
165 }
166
167
168 /****************************************************************************
169 *
170 * FUNCTION: bm_bus_check
171 *
172 * PARAMETERS:
173 *
174 * RETURN:
175 *
176 * DESCRIPTION:
177 *
178 ****************************************************************************/
179
180 acpi_status
181 bm_bus_check (
182 BM_NODE *parent_node)
183 {
184 acpi_status status = AE_OK;
185 u32 status_change = FALSE;
186
187 FUNCTION_TRACE("bm_bus_check");
188
189 if (!parent_node) {
190 return_ACPI_STATUS(AE_BAD_PARAMETER);
191 }
192
193 /*
194 * Status Change?
195 * --------------
196 */
197 status = bm_device_check(parent_node, &status_change);
198 if (ACPI_FAILURE(status) || !status_change) {
199 return_ACPI_STATUS(status);
200 }
201
202 /*
203 * Enumerate Scope:
204 * ----------------
205 * TBD: Enumerate child devices within this device's scope and
206 * run bm_device_check()'s on them...
207 */
208
209 return_ACPI_STATUS(AE_OK);
210 }
211
212
213 /****************************************************************************
214 * External Functions
215 ****************************************************************************/
216
217 /****************************************************************************
218 *
219 * FUNCTION: bm_notify
220 *
221 * PARAMETERS:
222 *
223 * RETURN:
224 *
225 * DESCRIPTION:
226 *
227 ****************************************************************************/
228
229 void
230 bm_notify (
231 acpi_handle acpi_handle,
232 u32 notify_value,
233 void *context)
234 {
235 acpi_status status = AE_OK;
236 BM_NODE *node = NULL;
237
238 FUNCTION_TRACE("bm_notify");
239
240 /*
241 * Resolve the ACPI handle.
242 */
243 status = bm_get_node(0, acpi_handle, &node);
244 if (ACPI_FAILURE(status)) {
245 ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Recieved notify [%02x] for unknown device [%p].\n", notify_value, acpi_handle));
246 return_VOID;
247 }
248
249 /*
250 * Device-Specific or Standard?
251 * ----------------------------
252 * Device-specific notifies are forwarded to the control module's
253 * notify() function for processing. Standard notifies are handled
254 * internally.
255 */
256 if (notify_value > 0x7F) {
257 status = bm_generate_notify(node, notify_value);
258 }
259 else {
260 switch (notify_value) {
261
262 case BM_NOTIFY_BUS_CHECK:
263 ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Received BUS CHECK notification for device [%02x].\n", node->device.handle));
264 status = bm_bus_check(node);
265 break;
266
267 case BM_NOTIFY_DEVICE_CHECK:
268 ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Received DEVICE CHECK notification for device [%02x].\n", node->device.handle));
269 status = bm_device_check(node, NULL);
270 break;
271
272 case BM_NOTIFY_DEVICE_WAKE:
273 ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Received DEVICE WAKE notification for device [%02x].\n", node->device.handle));
274 /* TBD */
275 break;
276
277 case BM_NOTIFY_EJECT_REQUEST:
278 ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Received EJECT REQUEST notification for device [%02x].\n", node->device.handle));
279 /* TBD */
280 break;
281
282 case BM_NOTIFY_DEVICE_CHECK_LIGHT:
283 ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Received DEVICE CHECK LIGHT notification for device [%02x].\n", node->device.handle));
284 /* TBD: Exactly what does the 'light' mean? */
285 status = bm_device_check(node, NULL);
286 break;
287
288 case BM_NOTIFY_FREQUENCY_MISMATCH:
289 ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Received FREQUENCY MISMATCH notification for device [%02x].\n", node->device.handle));
290 /* TBD */
291 break;
292
293 case BM_NOTIFY_BUS_MODE_MISMATCH:
294 ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Received BUS MODE MISMATCH notification for device [%02x].\n", node->device.handle));
295 /* TBD */
296 break;
297
298 case BM_NOTIFY_POWER_FAULT:
299 ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Received POWER FAULT notification.\n"));
300 /* TBD */
301 break;
302
303 default:
304 ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Received unknown/unsupported notification.\n"));
305 break;
306 }
307 }
308
309 return_VOID;
310 }
311
312
313