1157774Siwasaki/*-
2157774Siwasaki * Copyright (c) 2005-2006 Mitsuru IWASAKI <iwasaki@FreeBSD.org>
3157774Siwasaki * All rights reserved.
4157774Siwasaki *
5157774Siwasaki * Redistribution and use in source and binary forms, with or without
6157774Siwasaki * modification, are permitted provided that the following conditions
7157774Siwasaki * are met:
8157774Siwasaki * 1. Redistributions of source code must retain the above copyright
9157774Siwasaki *    notice, this list of conditions and the following disclaimer.
10157774Siwasaki * 2. Redistributions in binary form must reproduce the above copyright
11157774Siwasaki *    notice, this list of conditions and the following disclaimer in the
12157774Siwasaki *    documentation and/or other materials provided with the distribution.
13157774Siwasaki *
14157774Siwasaki * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15157774Siwasaki * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16157774Siwasaki * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17157774Siwasaki * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18157774Siwasaki * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19157774Siwasaki * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20157774Siwasaki * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21157774Siwasaki * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22157774Siwasaki * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23157774Siwasaki * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24157774Siwasaki * SUCH DAMAGE.
25157774Siwasaki *
26157774Siwasaki * $FreeBSD$
27157774Siwasaki */
28157774Siwasaki
29157774Siwasaki#include "opt_acpi.h"
30157774Siwasaki#include <sys/param.h>
31159855Snjl#include <sys/bus.h>
32157774Siwasaki#include <sys/kernel.h>
33157774Siwasaki#include <sys/module.h>
34157774Siwasaki
35193530Sjkim#include <contrib/dev/acpica/include/acpi.h>
36193530Sjkim#include <contrib/dev/acpica/include/accommon.h>
37193530Sjkim
38157774Siwasaki#include <dev/acpica/acpivar.h>
39157774Siwasaki#include <dev/acpica/acpiio.h>
40157774Siwasaki
41157774Siwasaki/* Hooks for the ACPI CA debugging infrastructure */
42157774Siwasaki#define _COMPONENT	ACPI_DOCK
43157774SiwasakiACPI_MODULE_NAME("DOCK")
44157774Siwasaki
45157774Siwasaki/* For Docking status */
46157774Siwasaki#define ACPI_DOCK_STATUS_UNKNOWN	-1
47157774Siwasaki#define ACPI_DOCK_STATUS_UNDOCKED	0
48157774Siwasaki#define ACPI_DOCK_STATUS_DOCKED		1
49157774Siwasaki
50161065Snjl#define ACPI_DOCK_UNLOCK		0 /* Allow device to be ejected */
51161065Snjl#define ACPI_DOCK_LOCK			1 /* Prevent dev from being removed */
52159855Snjl
53161065Snjl#define ACPI_DOCK_ISOLATE		0 /* Isolate from dock connector */
54161065Snjl#define ACPI_DOCK_CONNECT		1 /* Connect to dock */
55161065Snjl
56157774Siwasakistruct acpi_dock_softc {
57157774Siwasaki	int		_sta;
58157774Siwasaki	int		_bdn;
59157774Siwasaki	int		_uid;
60157774Siwasaki	int		status;
61157774Siwasaki	struct sysctl_ctx_list	*sysctl_ctx;
62157774Siwasaki	struct sysctl_oid	*sysctl_tree;
63157774Siwasaki};
64157774Siwasaki
65159855SnjlACPI_SERIAL_DECL(dock, "ACPI Docking Station");
66157774Siwasaki
67157774Siwasaki/*
68159855Snjl * Utility functions
69157774Siwasaki */
70157774Siwasaki
71157774Siwasakistatic void
72157774Siwasakiacpi_dock_get_info(device_t dev)
73157774Siwasaki{
74157774Siwasaki	struct acpi_dock_softc *sc;
75157774Siwasaki	ACPI_HANDLE	h;
76157774Siwasaki
77157774Siwasaki	sc = device_get_softc(dev);
78157774Siwasaki	h = acpi_get_handle(dev);
79157774Siwasaki
80159855Snjl	if (ACPI_FAILURE(acpi_GetInteger(h, "_STA", &sc->_sta)))
81157774Siwasaki		sc->_sta = ACPI_DOCK_STATUS_UNKNOWN;
82159855Snjl	if (ACPI_FAILURE(acpi_GetInteger(h, "_BDN", &sc->_bdn)))
83157774Siwasaki		sc->_bdn = ACPI_DOCK_STATUS_UNKNOWN;
84159855Snjl	if (ACPI_FAILURE(acpi_GetInteger(h, "_UID", &sc->_uid)))
85157774Siwasaki		sc->_uid = ACPI_DOCK_STATUS_UNKNOWN;
86157774Siwasaki	ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
87159855Snjl		    "_STA: %04x, _BDN: %04x, _UID: %04x\n", sc->_sta,
88159855Snjl		    sc->_bdn, sc->_uid);
89157774Siwasaki}
90157774Siwasaki
91157774Siwasakistatic int
92157774Siwasakiacpi_dock_execute_dck(device_t dev, int dock)
93157774Siwasaki{
94157774Siwasaki	ACPI_HANDLE	h;
95157774Siwasaki	ACPI_OBJECT	argobj;
96157774Siwasaki	ACPI_OBJECT_LIST args;
97157774Siwasaki	ACPI_BUFFER	buf;
98157774Siwasaki	ACPI_OBJECT	retobj;
99157774Siwasaki	ACPI_STATUS	status;
100157774Siwasaki
101157774Siwasaki	h = acpi_get_handle(dev);
102157774Siwasaki
103157774Siwasaki	argobj.Type = ACPI_TYPE_INTEGER;
104157774Siwasaki	argobj.Integer.Value = dock;
105157774Siwasaki	args.Count = 1;
106157774Siwasaki	args.Pointer = &argobj;
107157774Siwasaki	buf.Pointer = &retobj;
108157774Siwasaki	buf.Length = sizeof(retobj);
109157774Siwasaki	status = AcpiEvaluateObject(h, "_DCK", &args, &buf);
110157774Siwasaki
111159855Snjl	/*
112159855Snjl	 * When _DCK is called with 0, OSPM will ignore the return value.
113159855Snjl	 */
114161065Snjl	if (dock == ACPI_DOCK_ISOLATE)
115157774Siwasaki		return (0);
116157774Siwasaki
117159855Snjl	/* If _DCK returned 1, the request succeeded. */
118159855Snjl	if (ACPI_SUCCESS(status) && retobj.Type == ACPI_TYPE_INTEGER &&
119159855Snjl	    retobj.Integer.Value == 1)
120159855Snjl		return (0);
121157774Siwasaki
122157774Siwasaki	return (-1);
123157774Siwasaki}
124157774Siwasaki
125161065Snjl/* Lock devices while docked to prevent surprise removal. */
126157774Siwasakistatic void
127157774Siwasakiacpi_dock_execute_lck(device_t dev, int lock)
128157774Siwasaki{
129157774Siwasaki	ACPI_HANDLE	h;
130157774Siwasaki
131157774Siwasaki	h = acpi_get_handle(dev);
132157774Siwasaki	acpi_SetInteger(h, "_LCK", lock);
133157774Siwasaki}
134157774Siwasaki
135161065Snjl/* Eject a device (i.e., motorized). */
136157774Siwasakistatic int
137157774Siwasakiacpi_dock_execute_ejx(device_t dev, int eject, int state)
138157774Siwasaki{
139157774Siwasaki	ACPI_HANDLE	h;
140157774Siwasaki	ACPI_STATUS	status;
141157774Siwasaki	char		ejx[5];
142157774Siwasaki
143157774Siwasaki	h = acpi_get_handle(dev);
144157774Siwasaki	snprintf(ejx, sizeof(ejx), "_EJ%d", state);
145157774Siwasaki	status = acpi_SetInteger(h, ejx, eject);
146159855Snjl	if (ACPI_SUCCESS(status))
147157774Siwasaki		return (0);
148157774Siwasaki
149157774Siwasaki	return (-1);
150157774Siwasaki}
151157774Siwasaki
152161065Snjl/* Find dependent devices.  When their parent is removed, so are they. */
153157774Siwasakistatic int
154157774Siwasakiacpi_dock_is_ejd_device(ACPI_HANDLE dock_handle, ACPI_HANDLE handle)
155157774Siwasaki{
156157774Siwasaki	int		ret;
157157774Siwasaki	ACPI_STATUS	ret_status;
158157774Siwasaki	ACPI_BUFFER	ejd_buffer;
159157774Siwasaki	ACPI_OBJECT	*obj;
160157774Siwasaki
161157774Siwasaki	ret = 0;
162157774Siwasaki
163157774Siwasaki	ejd_buffer.Pointer = NULL;
164157774Siwasaki	ejd_buffer.Length = ACPI_ALLOCATE_BUFFER;
165157774Siwasaki	ret_status = AcpiEvaluateObject(handle, "_EJD", NULL, &ejd_buffer);
166159855Snjl	if (ACPI_FAILURE(ret_status))
167157774Siwasaki		goto out;
168157774Siwasaki
169157774Siwasaki	obj = (ACPI_OBJECT *)ejd_buffer.Pointer;
170159855Snjl	if (dock_handle == acpi_GetReference(NULL, obj))
171159855Snjl		ret = 1;
172157774Siwasaki
173157774Siwasakiout:
174157774Siwasaki	if (ejd_buffer.Pointer != NULL)
175157774Siwasaki		AcpiOsFree(ejd_buffer.Pointer);
176157774Siwasaki
177157774Siwasaki	return (ret);
178157774Siwasaki}
179157774Siwasaki
180157774Siwasaki/*
181159855Snjl * Docking functions
182157774Siwasaki */
183157774Siwasaki
184157774Siwasakistatic void
185157774Siwasakiacpi_dock_attach_later(void *context)
186157774Siwasaki{
187157774Siwasaki	device_t	dev;
188157774Siwasaki
189157774Siwasaki	dev = (device_t)context;
190157774Siwasaki
191159855Snjl	if (!device_is_enabled(dev))
192157774Siwasaki		device_enable(dev);
193157774Siwasaki
194196403Sjhb	mtx_lock(&Giant);
195157774Siwasaki	device_probe_and_attach(dev);
196196403Sjhb	mtx_unlock(&Giant);
197157774Siwasaki}
198157774Siwasaki
199157774Siwasakistatic ACPI_STATUS
200159855Snjlacpi_dock_insert_child(ACPI_HANDLE handle, UINT32 level, void *context,
201159855Snjl    void **status)
202157774Siwasaki{
203157774Siwasaki	device_t	dock_dev, dev;
204157774Siwasaki	ACPI_HANDLE	dock_handle;
205157774Siwasaki
206157774Siwasaki	dock_dev = (device_t)context;
207157774Siwasaki	dock_handle = acpi_get_handle(dock_dev);
208157774Siwasaki
209159855Snjl	if (!acpi_dock_is_ejd_device(dock_handle, handle))
210157774Siwasaki		goto out;
211157774Siwasaki
212157774Siwasaki	ACPI_VPRINT(dock_dev, acpi_device_get_parent_softc(dock_dev),
213157774Siwasaki		    "inserting device for %s\n", acpi_name(handle));
214157774Siwasaki
215157774Siwasaki#if 0
216157774Siwasaki	/*
217157774Siwasaki	 * If the system boot up w/o Docking, the devices under the dock
218157774Siwasaki	 * still un-initialized, also control methods such as _INI, _STA
219157774Siwasaki	 * are not executed.
220157774Siwasaki	 * Normal devices are initialized at booting by calling
221157774Siwasaki	 * AcpiInitializeObjects(), however the devices under the dock
222157774Siwasaki	 * need to be initialized here on the scheme of ACPICA.
223157774Siwasaki	 */
224157774Siwasaki	ACPI_INIT_WALK_INFO	Info;
225157774Siwasaki
226157774Siwasaki	AcpiNsWalkNamespace(ACPI_TYPE_ANY, handle,
227199337Sjkim	    100, TRUE, AcpiNsInitOneDevice, NULL, &Info, NULL);
228157774Siwasaki#endif
229157774Siwasaki
230157774Siwasaki	dev = acpi_get_device(handle);
231157774Siwasaki	if (dev == NULL) {
232159855Snjl		device_printf(dock_dev, "error: %s has no associated device\n",
233157774Siwasaki		    acpi_name(handle));
234157774Siwasaki		goto out;
235157774Siwasaki	}
236157774Siwasaki
237167814Sjkim	AcpiOsExecute(OSL_NOTIFY_HANDLER, acpi_dock_attach_later, dev);
238157774Siwasaki
239157774Siwasakiout:
240157774Siwasaki	return (AE_OK);
241157774Siwasaki}
242157774Siwasaki
243157774Siwasakistatic void
244157774Siwasakiacpi_dock_insert_children(device_t dev)
245157774Siwasaki{
246159855Snjl	ACPI_STATUS	status;
247157774Siwasaki	ACPI_HANDLE	sb_handle;
248157774Siwasaki
249159855Snjl	status = AcpiGetHandle(ACPI_ROOT_OBJECT, "\\_SB_", &sb_handle);
250159855Snjl	if (ACPI_SUCCESS(status)) {
251157774Siwasaki		AcpiWalkNamespace(ACPI_TYPE_DEVICE, sb_handle,
252199337Sjkim		    100, acpi_dock_insert_child, NULL, dev, NULL);
253157774Siwasaki	}
254157774Siwasaki}
255157774Siwasaki
256157774Siwasakistatic void
257157774Siwasakiacpi_dock_insert(device_t dev)
258157774Siwasaki{
259157774Siwasaki	struct acpi_dock_softc *sc;
260157774Siwasaki
261157774Siwasaki	ACPI_SERIAL_ASSERT(dock);
262157774Siwasaki
263157774Siwasaki	sc = device_get_softc(dev);
264157774Siwasaki
265161065Snjl	if (sc->status == ACPI_DOCK_STATUS_UNDOCKED ||
266161065Snjl	    sc->status == ACPI_DOCK_STATUS_UNKNOWN) {
267159855Snjl		acpi_dock_execute_lck(dev, ACPI_DOCK_LOCK);
268161065Snjl		if (acpi_dock_execute_dck(dev, ACPI_DOCK_CONNECT) != 0) {
269157774Siwasaki			device_printf(dev, "_DCK failed\n");
270157774Siwasaki			return;
271157774Siwasaki		}
272157774Siwasaki
273159855Snjl		if (!cold)
274157774Siwasaki			acpi_dock_insert_children(dev);
275161065Snjl		sc->status = ACPI_DOCK_STATUS_DOCKED;
276157774Siwasaki	}
277157774Siwasaki}
278157774Siwasaki
279157774Siwasaki/*
280157774Siwasaki * Undock
281157774Siwasaki */
282157774Siwasaki
283157774Siwasakistatic ACPI_STATUS
284159855Snjlacpi_dock_eject_child(ACPI_HANDLE handle, UINT32 level, void *context,
285159855Snjl    void **status)
286157774Siwasaki{
287157774Siwasaki	device_t	dock_dev, dev;
288157774Siwasaki	ACPI_HANDLE	dock_handle;
289157774Siwasaki
290157774Siwasaki	dock_dev = *(device_t *)context;
291157774Siwasaki	dock_handle = acpi_get_handle(dock_dev);
292157774Siwasaki
293159855Snjl	if (!acpi_dock_is_ejd_device(dock_handle, handle))
294157774Siwasaki		goto out;
295157774Siwasaki
296157774Siwasaki	ACPI_VPRINT(dock_dev, acpi_device_get_parent_softc(dock_dev),
297159855Snjl	    "ejecting device for %s\n", acpi_name(handle));
298157774Siwasaki
299157774Siwasaki	dev = acpi_get_device(handle);
300157774Siwasaki	if (dev != NULL && device_is_attached(dev)) {
301196403Sjhb		mtx_lock(&Giant);
302157774Siwasaki		device_detach(dev);
303196403Sjhb		mtx_unlock(&Giant);
304157774Siwasaki	}
305157774Siwasaki
306157774Siwasaki	acpi_SetInteger(handle, "_EJ0", 0);
307157774Siwasakiout:
308157774Siwasaki	return (AE_OK);
309157774Siwasaki}
310157774Siwasaki
311157774Siwasakistatic void
312157774Siwasakiacpi_dock_eject_children(device_t dev)
313157774Siwasaki{
314157774Siwasaki	ACPI_HANDLE	sb_handle;
315159855Snjl	ACPI_STATUS	status;
316157774Siwasaki
317159855Snjl	status = AcpiGetHandle(ACPI_ROOT_OBJECT, "\\_SB_", &sb_handle);
318159855Snjl	if (ACPI_SUCCESS(status)) {
319157774Siwasaki		AcpiWalkNamespace(ACPI_TYPE_DEVICE, sb_handle,
320199337Sjkim		    100, acpi_dock_eject_child, NULL, &dev, NULL);
321157774Siwasaki	}
322157774Siwasaki}
323157774Siwasaki
324157774Siwasakistatic void
325157774Siwasakiacpi_dock_removal(device_t dev)
326157774Siwasaki{
327157774Siwasaki	struct acpi_dock_softc *sc;
328157774Siwasaki
329157774Siwasaki	ACPI_SERIAL_ASSERT(dock);
330157774Siwasaki
331157774Siwasaki	sc = device_get_softc(dev);
332161065Snjl	if (sc->status == ACPI_DOCK_STATUS_DOCKED ||
333161065Snjl	    sc->status == ACPI_DOCK_STATUS_UNKNOWN) {
334157774Siwasaki		acpi_dock_eject_children(dev);
335161065Snjl		if (acpi_dock_execute_dck(dev, ACPI_DOCK_ISOLATE) != 0)
336157774Siwasaki			return;
337157774Siwasaki
338159855Snjl		acpi_dock_execute_lck(dev, ACPI_DOCK_UNLOCK);
339157774Siwasaki
340157774Siwasaki		if (acpi_dock_execute_ejx(dev, 1, 0) != 0) {
341157774Siwasaki			device_printf(dev, "_EJ0 failed\n");
342157774Siwasaki			return;
343157774Siwasaki		}
344157774Siwasaki
345161065Snjl		sc->status = ACPI_DOCK_STATUS_UNDOCKED;
346157774Siwasaki	}
347157774Siwasaki
348157774Siwasaki	acpi_dock_get_info(dev);
349159855Snjl	if (sc->_sta != 0)
350159855Snjl		device_printf(dev, "mechanical failure (%#x).\n", sc->_sta);
351157774Siwasaki}
352157774Siwasaki
353157774Siwasaki/*
354157774Siwasaki * Device/Bus check
355157774Siwasaki */
356157774Siwasaki
357157774Siwasakistatic void
358157774Siwasakiacpi_dock_device_check(device_t dev)
359157774Siwasaki{
360157774Siwasaki	struct acpi_dock_softc *sc;
361157774Siwasaki
362157774Siwasaki	ACPI_SERIAL_ASSERT(dock);
363157774Siwasaki
364157774Siwasaki	sc = device_get_softc(dev);
365157774Siwasaki	acpi_dock_get_info(dev);
366157774Siwasaki
367157774Siwasaki	/*
368161065Snjl	 * If the _STA method indicates 'present' and 'functioning', the
369161065Snjl	 * system is docked.  If _STA does not exist for this device, it
370161065Snjl	 * is always present.
371157774Siwasaki	 */
372161065Snjl	if (sc->_sta == ACPI_DOCK_STATUS_UNKNOWN ||
373161065Snjl	    ACPI_DEVICE_PRESENT(sc->_sta))
374157774Siwasaki		acpi_dock_insert(dev);
375161065Snjl	else if (sc->_sta == 0)
376157774Siwasaki		acpi_dock_removal(dev);
377157774Siwasaki}
378157774Siwasaki
379157774Siwasaki/*
380157774Siwasaki * Notify Handler
381157774Siwasaki */
382157774Siwasaki
383157774Siwasakistatic void
384157774Siwasakiacpi_dock_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context)
385157774Siwasaki{
386157774Siwasaki	device_t	dev;
387157774Siwasaki
388157774Siwasaki	dev = (device_t) context;
389157774Siwasaki	ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
390157774Siwasaki		    "got notification %#x\n", notify);
391157774Siwasaki
392157774Siwasaki	ACPI_SERIAL_BEGIN(dock);
393157774Siwasaki	switch (notify) {
394170148Stakawata	case ACPI_NOTIFY_BUS_CHECK:
395170148Stakawata	case ACPI_NOTIFY_DEVICE_CHECK:
396157774Siwasaki		acpi_dock_device_check(dev);
397157774Siwasaki		break;
398170148Stakawata	case ACPI_NOTIFY_EJECT_REQUEST:
399157774Siwasaki		acpi_dock_removal(dev);
400157774Siwasaki		break;
401157774Siwasaki	default:
402157774Siwasaki		device_printf(dev, "unknown notify %#x\n", notify);
403157774Siwasaki		break;
404157774Siwasaki	}
405157774Siwasaki	ACPI_SERIAL_END(dock);
406157774Siwasaki}
407157774Siwasaki
408157774Siwasakistatic int
409157774Siwasakiacpi_dock_status_sysctl(SYSCTL_HANDLER_ARGS)
410157774Siwasaki{
411157774Siwasaki	struct acpi_dock_softc *sc;
412157774Siwasaki	device_t	dev;
413161065Snjl	int		status, err;
414157774Siwasaki
415161065Snjl	dev = (device_t)arg1;
416161065Snjl
417157774Siwasaki	sc = device_get_softc(dev);
418161065Snjl	status = sc->status;
419157774Siwasaki
420157774Siwasaki	ACPI_SERIAL_BEGIN(dock);
421161065Snjl	err = sysctl_handle_int(oidp, &status, 0, req);
422161065Snjl	if (err != 0 || req->newptr == NULL)
423161065Snjl		goto out;
424157774Siwasaki
425157774Siwasaki	if (status != ACPI_DOCK_STATUS_UNDOCKED &&
426157774Siwasaki	    status != ACPI_DOCK_STATUS_DOCKED) {
427157774Siwasaki		err = EINVAL;
428161065Snjl		goto out;
429157774Siwasaki	}
430157774Siwasaki
431159855Snjl	if (status == sc->status)
432157774Siwasaki		goto out;
433157774Siwasaki
434157774Siwasaki	switch (status) {
435157774Siwasaki	case ACPI_DOCK_STATUS_UNDOCKED:
436157774Siwasaki		acpi_dock_removal(dev);
437157774Siwasaki		break;
438157774Siwasaki	case ACPI_DOCK_STATUS_DOCKED:
439157774Siwasaki		acpi_dock_device_check(dev);
440157774Siwasaki		break;
441157774Siwasaki	default:
442157774Siwasaki		err = EINVAL;
443157774Siwasaki		break;
444157774Siwasaki	}
445157774Siwasakiout:
446157774Siwasaki	ACPI_SERIAL_END(dock);
447157774Siwasaki	return (err);
448157774Siwasaki}
449157774Siwasaki
450157774Siwasakistatic int
451157774Siwasakiacpi_dock_probe(device_t dev)
452157774Siwasaki{
453157774Siwasaki	ACPI_HANDLE	h, tmp;
454157774Siwasaki
455157774Siwasaki	h = acpi_get_handle(dev);
456157774Siwasaki	if (acpi_disabled("dock") ||
457157774Siwasaki	    ACPI_FAILURE(AcpiGetHandle(h, "_DCK", &tmp)))
458157774Siwasaki		return (ENXIO);
459157774Siwasaki
460159855Snjl	device_set_desc(dev, "ACPI Docking Station");
461159855Snjl
462159855Snjl	/*
463159855Snjl	 * XXX Somewhere else in the kernel panics on "sysctl kern" if we
464159855Snjl	 * return a negative value here (reprobe ok).
465159855Snjl	 */
466157774Siwasaki	return (0);
467157774Siwasaki}
468157774Siwasaki
469157774Siwasakistatic int
470157774Siwasakiacpi_dock_attach(device_t dev)
471157774Siwasaki{
472157774Siwasaki	struct acpi_dock_softc *sc;
473157774Siwasaki	ACPI_HANDLE	h;
474157774Siwasaki
475157774Siwasaki	sc = device_get_softc(dev);
476157774Siwasaki	h = acpi_get_handle(dev);
477161065Snjl	if (sc == NULL || h == NULL)
478157774Siwasaki		return (ENXIO);
479157774Siwasaki
480157774Siwasaki	sc->status = ACPI_DOCK_STATUS_UNKNOWN;
481157774Siwasaki
482157774Siwasaki	AcpiEvaluateObject(h, "_INI", NULL, NULL);
483157774Siwasaki
484157774Siwasaki	ACPI_SERIAL_BEGIN(dock);
485157774Siwasaki
486157774Siwasaki	acpi_dock_device_check(dev);
487157774Siwasaki
488161065Snjl	/* Get the sysctl tree */
489157774Siwasaki	sc->sysctl_ctx = device_get_sysctl_ctx(dev);
490157774Siwasaki	sc->sysctl_tree = device_get_sysctl_tree(dev);
491157774Siwasaki
492157774Siwasaki	SYSCTL_ADD_INT(sc->sysctl_ctx,
493157774Siwasaki		SYSCTL_CHILDREN(sc->sysctl_tree),
494157774Siwasaki		OID_AUTO, "_sta", CTLFLAG_RD,
495157774Siwasaki		&sc->_sta, 0, "Dock _STA");
496157774Siwasaki	SYSCTL_ADD_INT(sc->sysctl_ctx,
497157774Siwasaki		SYSCTL_CHILDREN(sc->sysctl_tree),
498157774Siwasaki		OID_AUTO, "_bdn", CTLFLAG_RD,
499157774Siwasaki		&sc->_bdn, 0, "Dock _BDN");
500157774Siwasaki	SYSCTL_ADD_INT(sc->sysctl_ctx,
501157774Siwasaki		SYSCTL_CHILDREN(sc->sysctl_tree),
502157774Siwasaki		OID_AUTO, "_uid", CTLFLAG_RD,
503157774Siwasaki		&sc->_uid, 0, "Dock _UID");
504157774Siwasaki	SYSCTL_ADD_PROC(sc->sysctl_ctx,
505157774Siwasaki		SYSCTL_CHILDREN(sc->sysctl_tree),
506157774Siwasaki		OID_AUTO, "status",
507157774Siwasaki		CTLTYPE_INT|CTLFLAG_RW, dev, 0,
508157774Siwasaki		acpi_dock_status_sysctl, "I",
509157774Siwasaki		"Dock/Undock operation");
510157774Siwasaki
511157774Siwasaki	ACPI_SERIAL_END(dock);
512157774Siwasaki
513157774Siwasaki	AcpiInstallNotifyHandler(h, ACPI_ALL_NOTIFY,
514157774Siwasaki				 acpi_dock_notify_handler, dev);
515157774Siwasaki
516157774Siwasaki	return (0);
517157774Siwasaki}
518157774Siwasaki
519157774Siwasakistatic device_method_t acpi_dock_methods[] = {
520157774Siwasaki	/* Device interface */
521157774Siwasaki	DEVMETHOD(device_probe, acpi_dock_probe),
522157774Siwasaki	DEVMETHOD(device_attach, acpi_dock_attach),
523157774Siwasaki
524157774Siwasaki	{0, 0}
525157774Siwasaki};
526157774Siwasaki
527157774Siwasakistatic driver_t	acpi_dock_driver = {
528157774Siwasaki	"acpi_dock",
529157774Siwasaki	acpi_dock_methods,
530157774Siwasaki	sizeof(struct acpi_dock_softc),
531157774Siwasaki};
532157774Siwasaki
533157774Siwasakistatic devclass_t acpi_dock_devclass;
534157774Siwasaki
535157774SiwasakiDRIVER_MODULE(acpi_dock, acpi, acpi_dock_driver, acpi_dock_devclass, 0, 0);
536157774SiwasakiMODULE_DEPEND(acpi_dock, acpi, 1, 1, 1);
537157774Siwasaki
538