Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
c8f7a62c
Commit
c8f7a62c
authored
Jul 09, 2006
by
Len Brown
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Revert "Revert "ACPI: dock driver""
This reverts
953969dd
commit.
parent
953969dd
Changes
6
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
788 additions
and
1 deletion
+788
-1
drivers/acpi/Kconfig
drivers/acpi/Kconfig
+7
-0
drivers/acpi/Makefile
drivers/acpi/Makefile
+1
-0
drivers/acpi/dock.c
drivers/acpi/dock.c
+739
-0
drivers/acpi/scan.c
drivers/acpi/scan.c
+23
-0
include/acpi/acpi_bus.h
include/acpi/acpi_bus.h
+1
-1
include/acpi/acpi_drivers.h
include/acpi/acpi_drivers.h
+17
-0
No files found.
drivers/acpi/Kconfig
View file @
c8f7a62c
...
...
@@ -133,6 +133,13 @@ config ACPI_FAN
This driver adds support for ACPI fan devices, allowing user-mode
applications to perform basic fan control (on, off, status).
config ACPI_DOCK
tristate "Dock"
depends on !ACPI_IBM_DOCK
default y
help
This driver adds support for ACPI controlled docking stations
config ACPI_PROCESSOR
tristate "Processor"
default y
...
...
drivers/acpi/Makefile
View file @
c8f7a62c
...
...
@@ -42,6 +42,7 @@ obj-$(CONFIG_ACPI_BATTERY) += battery.o
obj-$(CONFIG_ACPI_BUTTON)
+=
button.o
obj-$(CONFIG_ACPI_EC)
+=
ec.o
obj-$(CONFIG_ACPI_FAN)
+=
fan.o
obj-$(CONFIG_ACPI_DOCK)
+=
dock.o
obj-$(CONFIG_ACPI_VIDEO)
+=
video.o
obj-$(CONFIG_ACPI_HOTKEY)
+=
hotkey.o
obj-y
+=
pci_root.o pci_link.o pci_irq.o pci_bind.o
...
...
drivers/acpi/dock.c
0 → 100644
View file @
c8f7a62c
/*
* dock.c - ACPI dock station driver
*
* Copyright (C) 2006 Kristen Carlson Accardi <kristen.c.accardi@intel.com>
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/notifier.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
#define ACPI_DOCK_DRIVER_NAME "ACPI Dock Station Driver"
ACPI_MODULE_NAME
(
"dock"
)
MODULE_AUTHOR
(
"Kristen Carlson Accardi"
);
MODULE_DESCRIPTION
(
ACPI_DOCK_DRIVER_NAME
);
MODULE_LICENSE
(
"GPL"
);
static
struct
atomic_notifier_head
dock_notifier_list
;
struct
dock_station
{
acpi_handle
handle
;
unsigned
long
last_dock_time
;
u32
flags
;
spinlock_t
dd_lock
;
spinlock_t
hp_lock
;
struct
list_head
dependent_devices
;
struct
list_head
hotplug_devices
;
};
struct
dock_dependent_device
{
struct
list_head
list
;
struct
list_head
hotplug_list
;
acpi_handle
handle
;
acpi_notify_handler
handler
;
void
*
context
;
};
#define DOCK_DOCKING 0x00000001
#define DOCK_EVENT KOBJ_DOCK
#define UNDOCK_EVENT KOBJ_UNDOCK
static
struct
dock_station
*
dock_station
;
/*****************************************************************************
* Dock Dependent device functions *
*****************************************************************************/
/**
* alloc_dock_dependent_device - allocate and init a dependent device
* @handle: the acpi_handle of the dependent device
*
* Allocate memory for a dependent device structure for a device referenced
* by the acpi handle
*/
static
struct
dock_dependent_device
*
alloc_dock_dependent_device
(
acpi_handle
handle
)
{
struct
dock_dependent_device
*
dd
;
dd
=
kzalloc
(
sizeof
(
*
dd
),
GFP_KERNEL
);
if
(
dd
)
{
dd
->
handle
=
handle
;
INIT_LIST_HEAD
(
&
dd
->
list
);
INIT_LIST_HEAD
(
&
dd
->
hotplug_list
);
}
return
dd
;
}
/**
* add_dock_dependent_device - associate a device with the dock station
* @ds: The dock station
* @dd: The dependent device
*
* Add the dependent device to the dock's dependent device list.
*/
static
void
add_dock_dependent_device
(
struct
dock_station
*
ds
,
struct
dock_dependent_device
*
dd
)
{
spin_lock
(
&
ds
->
dd_lock
);
list_add_tail
(
&
dd
->
list
,
&
ds
->
dependent_devices
);
spin_unlock
(
&
ds
->
dd_lock
);
}
/**
* dock_add_hotplug_device - associate a hotplug handler with the dock station
* @ds: The dock station
* @dd: The dependent device struct
*
* Add the dependent device to the dock's hotplug device list
*/
static
void
dock_add_hotplug_device
(
struct
dock_station
*
ds
,
struct
dock_dependent_device
*
dd
)
{
spin_lock
(
&
ds
->
hp_lock
);
list_add_tail
(
&
dd
->
hotplug_list
,
&
ds
->
hotplug_devices
);
spin_unlock
(
&
ds
->
hp_lock
);
}
/**
* dock_del_hotplug_device - remove a hotplug handler from the dock station
* @ds: The dock station
* @dd: the dependent device struct
*
* Delete the dependent device from the dock's hotplug device list
*/
static
void
dock_del_hotplug_device
(
struct
dock_station
*
ds
,
struct
dock_dependent_device
*
dd
)
{
spin_lock
(
&
ds
->
hp_lock
);
list_del
(
&
dd
->
hotplug_list
);
spin_unlock
(
&
ds
->
hp_lock
);
}
/**
* find_dock_dependent_device - get a device dependent on this dock
* @ds: the dock station
* @handle: the acpi_handle of the device we want
*
* iterate over the dependent device list for this dock. If the
* dependent device matches the handle, return.
*/
static
struct
dock_dependent_device
*
find_dock_dependent_device
(
struct
dock_station
*
ds
,
acpi_handle
handle
)
{
struct
dock_dependent_device
*
dd
;
spin_lock
(
&
ds
->
dd_lock
);
list_for_each_entry
(
dd
,
&
ds
->
dependent_devices
,
list
)
{
if
(
handle
==
dd
->
handle
)
{
spin_unlock
(
&
ds
->
dd_lock
);
return
dd
;
}
}
spin_unlock
(
&
ds
->
dd_lock
);
return
NULL
;
}
/*****************************************************************************
* Dock functions *
*****************************************************************************/
/**
* is_dock - see if a device is a dock station
* @handle: acpi handle of the device
*
* If an acpi object has a _DCK method, then it is by definition a dock
* station, so return true.
*/
static
int
is_dock
(
acpi_handle
handle
)
{
acpi_status
status
;
acpi_handle
tmp
;
status
=
acpi_get_handle
(
handle
,
"_DCK"
,
&
tmp
);
if
(
ACPI_FAILURE
(
status
))
return
0
;
return
1
;
}
/**
* is_dock_device - see if a device is on a dock station
* @handle: acpi handle of the device
*
* If this device is either the dock station itself,
* or is a device dependent on the dock station, then it
* is a dock device
*/
int
is_dock_device
(
acpi_handle
handle
)
{
if
(
!
dock_station
)
return
0
;
if
(
is_dock
(
handle
)
||
find_dock_dependent_device
(
dock_station
,
handle
))
return
1
;
return
0
;
}
EXPORT_SYMBOL_GPL
(
is_dock_device
);
/**
* dock_present - see if the dock station is present.
* @ds: the dock station
*
* execute the _STA method. note that present does not
* imply that we are docked.
*/
static
int
dock_present
(
struct
dock_station
*
ds
)
{
unsigned
long
sta
;
acpi_status
status
;
if
(
ds
)
{
status
=
acpi_evaluate_integer
(
ds
->
handle
,
"_STA"
,
NULL
,
&
sta
);
if
(
ACPI_SUCCESS
(
status
)
&&
sta
)
return
1
;
}
return
0
;
}
/**
* dock_create_acpi_device - add new devices to acpi
* @handle - handle of the device to add
*
* This function will create a new acpi_device for the given
* handle if one does not exist already. This should cause
* acpi to scan for drivers for the given devices, and call
* matching driver's add routine.
*
* Returns a pointer to the acpi_device corresponding to the handle.
*/
static
struct
acpi_device
*
dock_create_acpi_device
(
acpi_handle
handle
)
{
struct
acpi_device
*
device
=
NULL
;
struct
acpi_device
*
parent_device
;
acpi_handle
parent
;
int
ret
;
if
(
acpi_bus_get_device
(
handle
,
&
device
))
{
/*
* no device created for this object,
* so we should create one.
*/
acpi_get_parent
(
handle
,
&
parent
);
if
(
acpi_bus_get_device
(
parent
,
&
parent_device
))
parent_device
=
NULL
;
ret
=
acpi_bus_add
(
&
device
,
parent_device
,
handle
,
ACPI_BUS_TYPE_DEVICE
);
if
(
ret
)
{
pr_debug
(
"error adding bus, %x
\n
"
,
-
ret
);
return
NULL
;
}
}
return
device
;
}
/**
* dock_remove_acpi_device - remove the acpi_device struct from acpi
* @handle - the handle of the device to remove
*
* Tell acpi to remove the acpi_device. This should cause any loaded
* driver to have it's remove routine called.
*/
static
void
dock_remove_acpi_device
(
acpi_handle
handle
)
{
struct
acpi_device
*
device
;
int
ret
;
if
(
!
acpi_bus_get_device
(
handle
,
&
device
))
{
ret
=
acpi_bus_trim
(
device
,
1
);
if
(
ret
)
pr_debug
(
"error removing bus, %x
\n
"
,
-
ret
);
}
}
/**
* hotplug_dock_devices - insert or remove devices on the dock station
* @ds: the dock station
* @event: either bus check or eject request
*
* Some devices on the dock station need to have drivers called
* to perform hotplug operations after a dock event has occurred.
* Traverse the list of dock devices that have registered a
* hotplug handler, and call the handler.
*/
static
void
hotplug_dock_devices
(
struct
dock_station
*
ds
,
u32
event
)
{
struct
dock_dependent_device
*
dd
;
spin_lock
(
&
ds
->
hp_lock
);
/*
* First call driver specific hotplug functions
*/
list_for_each_entry
(
dd
,
&
ds
->
hotplug_devices
,
hotplug_list
)
{
if
(
dd
->
handler
)
dd
->
handler
(
dd
->
handle
,
event
,
dd
->
context
);
}
/*
* Now make sure that an acpi_device is created for each
* dependent device, or removed if this is an eject request.
* This will cause acpi_drivers to be stopped/started if they
* exist
*/
list_for_each_entry
(
dd
,
&
ds
->
dependent_devices
,
list
)
{
if
(
event
==
ACPI_NOTIFY_EJECT_REQUEST
)
dock_remove_acpi_device
(
dd
->
handle
);
else
dock_create_acpi_device
(
dd
->
handle
);
}
spin_unlock
(
&
ds
->
hp_lock
);
}
static
void
dock_event
(
struct
dock_station
*
ds
,
u32
event
,
int
num
)
{
struct
acpi_device
*
device
;
device
=
dock_create_acpi_device
(
ds
->
handle
);
if
(
device
)
kobject_uevent
(
&
device
->
kobj
,
num
);
}
/**
* eject_dock - respond to a dock eject request
* @ds: the dock station
*
* This is called after _DCK is called, to execute the dock station's
* _EJ0 method.
*/
static
void
eject_dock
(
struct
dock_station
*
ds
)
{
struct
acpi_object_list
arg_list
;
union
acpi_object
arg
;
acpi_status
status
;
acpi_handle
tmp
;
/* all dock devices should have _EJ0, but check anyway */
status
=
acpi_get_handle
(
ds
->
handle
,
"_EJ0"
,
&
tmp
);
if
(
ACPI_FAILURE
(
status
))
{
pr_debug
(
"No _EJ0 support for dock device
\n
"
);
return
;
}
arg_list
.
count
=
1
;
arg_list
.
pointer
=
&
arg
;
arg
.
type
=
ACPI_TYPE_INTEGER
;
arg
.
integer
.
value
=
1
;
if
(
ACPI_FAILURE
(
acpi_evaluate_object
(
ds
->
handle
,
"_EJ0"
,
&
arg_list
,
NULL
)))
pr_debug
(
"Failed to evaluate _EJ0!
\n
"
);
}
/**
* handle_dock - handle a dock event
* @ds: the dock station
* @dock: to dock, or undock - that is the question
*
* Execute the _DCK method in response to an acpi event
*/
static
void
handle_dock
(
struct
dock_station
*
ds
,
int
dock
)
{
acpi_status
status
;
struct
acpi_object_list
arg_list
;
union
acpi_object
arg
;
struct
acpi_buffer
buffer
=
{
ACPI_ALLOCATE_BUFFER
,
NULL
};
struct
acpi_buffer
name_buffer
=
{
ACPI_ALLOCATE_BUFFER
,
NULL
};
union
acpi_object
*
obj
;
acpi_get_name
(
ds
->
handle
,
ACPI_FULL_PATHNAME
,
&
name_buffer
);
obj
=
name_buffer
.
pointer
;
printk
(
KERN_INFO
PREFIX
"%s
\n
"
,
dock
?
"docking"
:
"undocking"
);
/* _DCK method has one argument */
arg_list
.
count
=
1
;
arg_list
.
pointer
=
&
arg
;
arg
.
type
=
ACPI_TYPE_INTEGER
;
arg
.
integer
.
value
=
dock
;
status
=
acpi_evaluate_object
(
ds
->
handle
,
"_DCK"
,
&
arg_list
,
&
buffer
);
if
(
ACPI_FAILURE
(
status
))
pr_debug
(
"%s: failed to execute _DCK
\n
"
,
obj
->
string
.
pointer
);
kfree
(
buffer
.
pointer
);
kfree
(
name_buffer
.
pointer
);
}
static
inline
void
dock
(
struct
dock_station
*
ds
)
{
handle_dock
(
ds
,
1
);
}
static
inline
void
undock
(
struct
dock_station
*
ds
)
{
handle_dock
(
ds
,
0
);
}
static
inline
void
begin_dock
(
struct
dock_station
*
ds
)
{
ds
->
flags
|=
DOCK_DOCKING
;
}
static
inline
void
complete_dock
(
struct
dock_station
*
ds
)
{
ds
->
flags
&=
~
(
DOCK_DOCKING
);
ds
->
last_dock_time
=
jiffies
;
}
/**
* dock_in_progress - see if we are in the middle of handling a dock event
* @ds: the dock station
*
* Sometimes while docking, false dock events can be sent to the driver
* because good connections aren't made or some other reason. Ignore these
* if we are in the middle of doing something.
*/
static
int
dock_in_progress
(
struct
dock_station
*
ds
)
{
if
((
ds
->
flags
&
DOCK_DOCKING
)
||
time_before
(
jiffies
,
(
ds
->
last_dock_time
+
HZ
)))
return
1
;
return
0
;
}
/**
* register_dock_notifier - add yourself to the dock notifier list
* @nb: the callers notifier block
*
* If a driver wishes to be notified about dock events, they can
* use this function to put a notifier block on the dock notifier list.
* this notifier call chain will be called after a dock event, but
* before hotplugging any new devices.
*/
int
register_dock_notifier
(
struct
notifier_block
*
nb
)
{
return
atomic_notifier_chain_register
(
&
dock_notifier_list
,
nb
);
}
EXPORT_SYMBOL_GPL
(
register_dock_notifier
);
/**
* unregister_dock_notifier - remove yourself from the dock notifier list
* @nb: the callers notifier block
*/
void
unregister_dock_notifier
(
struct
notifier_block
*
nb
)
{
atomic_notifier_chain_unregister
(
&
dock_notifier_list
,
nb
);
}
EXPORT_SYMBOL_GPL
(
unregister_dock_notifier
);
/**
* register_hotplug_dock_device - register a hotplug function
* @handle: the handle of the device
* @handler: the acpi_notifier_handler to call after docking
* @context: device specific data
*
* If a driver would like to perform a hotplug operation after a dock
* event, they can register an acpi_notifiy_handler to be called by
* the dock driver after _DCK is executed.
*/
int
register_hotplug_dock_device
(
acpi_handle
handle
,
acpi_notify_handler
handler
,
void
*
context
)
{
struct
dock_dependent_device
*
dd
;
if
(
!
dock_station
)
return
-
ENODEV
;
/*
* make sure this handle is for a device dependent on the dock,
* this would include the dock station itself
*/
dd
=
find_dock_dependent_device
(
dock_station
,
handle
);
if
(
dd
)
{
dd
->
handler
=
handler
;
dd
->
context
=
context
;
dock_add_hotplug_device
(
dock_station
,
dd
);
return
0
;
}
return
-
EINVAL
;
}
EXPORT_SYMBOL_GPL
(
register_hotplug_dock_device
);
/**
* unregister_hotplug_dock_device - remove yourself from the hotplug list
* @handle: the acpi handle of the device
*/
void
unregister_hotplug_dock_device
(
acpi_handle
handle
)
{
struct
dock_dependent_device
*
dd
;
if
(
!
dock_station
)
return
;
dd
=
find_dock_dependent_device
(
dock_station
,
handle
);
if
(
dd
)
dock_del_hotplug_device
(
dock_station
,
dd
);
}
EXPORT_SYMBOL_GPL
(
unregister_hotplug_dock_device
);
/**
* dock_notify - act upon an acpi dock notification
* @handle: the dock station handle
* @event: the acpi event
* @data: our driver data struct
*
* If we are notified to dock, then check to see if the dock is
* present and then dock. Notify all drivers of the dock event,
* and then hotplug and devices that may need hotplugging. For undock
* check to make sure the dock device is still present, then undock
* and hotremove all the devices that may need removing.
*/
static
void
dock_notify
(
acpi_handle
handle
,
u32
event
,
void
*
data
)
{
struct
dock_station
*
ds
=
(
struct
dock_station
*
)
data
;
switch
(
event
)
{
case
ACPI_NOTIFY_BUS_CHECK
:
if
(
!
dock_in_progress
(
ds
)
&&
dock_present
(
ds
))
{
begin_dock
(
ds
);
dock
(
ds
);
if
(
!
dock_present
(
ds
))
{
printk
(
KERN_ERR
PREFIX
"Unable to dock!
\n
"
);
break
;
}
atomic_notifier_call_chain
(
&
dock_notifier_list
,
event
,
NULL
);
hotplug_dock_devices
(
ds
,
event
);
complete_dock
(
ds
);
dock_event
(
ds
,
event
,
DOCK_EVENT
);
}
break
;
case
ACPI_NOTIFY_DEVICE_CHECK
:
/*
* According to acpi spec 3.0a, if a DEVICE_CHECK notification
* is sent and _DCK is present, it is assumed to mean an
* undock request. This notify routine will only be called
* for objects defining _DCK, so we will fall through to eject
* request here. However, we will pass an eject request through
* to the driver who wish to hotplug.
*/
case
ACPI_NOTIFY_EJECT_REQUEST
:
if
(
!
dock_in_progress
(
ds
)
&&
dock_present
(
ds
))
{
/*
* here we need to generate the undock
* event prior to actually doing the undock
* so that the device struct still exists.
*/
dock_event
(
ds
,
event
,
UNDOCK_EVENT
);
hotplug_dock_devices
(
ds
,
ACPI_NOTIFY_EJECT_REQUEST
);
undock
(
ds
);
eject_dock
(
ds
);
if
(
dock_present
(
ds
))
printk
(
KERN_ERR
PREFIX
"Unable to undock!
\n
"
);
}
break
;
default:
printk
(
KERN_ERR
PREFIX
"Unknown dock event %d
\n
"
,
event
);
}
}
/**
* find_dock_devices - find devices on the dock station
* @handle: the handle of the device we are examining
* @lvl: unused
* @context: the dock station private data
* @rv: unused
*
* This function is called by acpi_walk_namespace. It will
* check to see if an object has an _EJD method. If it does, then it
* will see if it is dependent on the dock station.
*/
static
acpi_status
find_dock_devices
(
acpi_handle
handle
,
u32
lvl
,
void
*
context
,
void
**
rv
)
{
acpi_status
status
;
acpi_handle
tmp
;
struct
dock_station
*
ds
=
(
struct
dock_station
*
)
context
;
struct
dock_dependent_device
*
dd
;
status
=
acpi_bus_get_ejd
(
handle
,
&
tmp
);
if
(
ACPI_FAILURE
(
status
))
return
AE_OK
;
if
(
tmp
==
ds
->
handle
)
{
dd
=
alloc_dock_dependent_device
(
handle
);
if
(
dd
)
add_dock_dependent_device
(
ds
,
dd
);
}
return
AE_OK
;
}
/**
* dock_add - add a new dock station
* @handle: the dock station handle
*
* allocated and initialize a new dock station device. Find all devices
* that are on the dock station, and register for dock event notifications.
*/
static
int
dock_add
(
acpi_handle
handle
)
{
int
ret
;
acpi_status
status
;
struct
dock_dependent_device
*
dd
;
/* allocate & initialize the dock_station private data */
dock_station
=
kzalloc
(
sizeof
(
*
dock_station
),
GFP_KERNEL
);
if
(
!
dock_station
)
return
-
ENOMEM
;
dock_station
->
handle
=
handle
;
dock_station
->
last_dock_time
=
jiffies
-
HZ
;
INIT_LIST_HEAD
(
&
dock_station
->
dependent_devices
);
INIT_LIST_HEAD
(
&
dock_station
->
hotplug_devices
);
spin_lock_init
(
&
dock_station
->
dd_lock
);
spin_lock_init
(
&
dock_station
->
hp_lock
);
/* Find dependent devices */
acpi_walk_namespace
(
ACPI_TYPE_DEVICE
,
ACPI_ROOT_OBJECT
,
ACPI_UINT32_MAX
,
find_dock_devices
,
dock_station
,
NULL
);
/* add the dock station as a device dependent on itself */
dd
=
alloc_dock_dependent_device
(
handle
);
if
(
!
dd
)
{
kfree
(
dock_station
);
return
-
ENOMEM
;
}
add_dock_dependent_device
(
dock_station
,
dd
);
/* register for dock events */
status
=
acpi_install_notify_handler
(
dock_station
->
handle
,
ACPI_SYSTEM_NOTIFY
,
dock_notify
,
dock_station
);
if
(
ACPI_FAILURE
(
status
))
{
printk
(
KERN_ERR
PREFIX
"Error installing notify handler
\n
"
);
ret
=
-
ENODEV
;
goto
dock_add_err
;
}
printk
(
KERN_INFO
PREFIX
"%s
\n
"
,
ACPI_DOCK_DRIVER_NAME
);
return
0
;
dock_add_err:
kfree
(
dock_station
);
kfree
(
dd
);
return
ret
;
}
/**
* dock_remove - free up resources related to the dock station
*/
static
int
dock_remove
(
void
)
{
struct
dock_dependent_device
*
dd
,
*
tmp
;
acpi_status
status
;
if
(
!
dock_station
)
return
0
;
/* remove dependent devices */
list_for_each_entry_safe
(
dd
,
tmp
,
&
dock_station
->
dependent_devices
,
list
)
kfree
(
dd
);
/* remove dock notify handler */
status
=
acpi_remove_notify_handler
(
dock_station
->
handle
,
ACPI_SYSTEM_NOTIFY
,
dock_notify
);
if
(
ACPI_FAILURE
(
status
))
printk
(
KERN_ERR
"Error removing notify handler
\n
"
);
/* free dock station memory */
kfree
(
dock_station
);
return
0
;
}
/**
* find_dock - look for a dock station
* @handle: acpi handle of a device
* @lvl: unused
* @context: counter of dock stations found
* @rv: unused
*
* This is called by acpi_walk_namespace to look for dock stations.
*/
static
acpi_status
find_dock
(
acpi_handle
handle
,
u32
lvl
,
void
*
context
,
void
**
rv
)
{
int
*
count
=
(
int
*
)
context
;
acpi_status
status
=
AE_OK
;
if
(
is_dock
(
handle
))
{
if
(
dock_add
(
handle
)
>=
0
)
{
(
*
count
)
++
;
status
=
AE_CTRL_TERMINATE
;
}
}
return
status
;
}
static
int
__init
dock_init
(
void
)
{
int
num
=
0
;
dock_station
=
NULL
;
/* look for a dock station */
acpi_walk_namespace
(
ACPI_TYPE_DEVICE
,
ACPI_ROOT_OBJECT
,
ACPI_UINT32_MAX
,
find_dock
,
&
num
,
NULL
);
if
(
!
num
)
return
-
ENODEV
;
return
0
;
}
static
void
__exit
dock_exit
(
void
)
{
dock_remove
();
}
postcore_initcall
(
dock_init
);
module_exit
(
dock_exit
);
drivers/acpi/scan.c
View file @
c8f7a62c
...
...
@@ -663,6 +663,29 @@ static int acpi_bus_find_driver(struct acpi_device *device)
Device Enumeration
-------------------------------------------------------------------------- */
acpi_status
acpi_bus_get_ejd
(
acpi_handle
handle
,
acpi_handle
*
ejd
)
{
acpi_status
status
;
acpi_handle
tmp
;
struct
acpi_buffer
buffer
=
{
ACPI_ALLOCATE_BUFFER
,
NULL
};
union
acpi_object
*
obj
;
status
=
acpi_get_handle
(
handle
,
"_EJD"
,
&
tmp
);
if
(
ACPI_FAILURE
(
status
))
return
status
;
status
=
acpi_evaluate_object
(
handle
,
"_EJD"
,
NULL
,
&
buffer
);
if
(
ACPI_SUCCESS
(
status
))
{
obj
=
buffer
.
pointer
;
status
=
acpi_get_handle
(
NULL
,
obj
->
string
.
pointer
,
ejd
);
kfree
(
buffer
.
pointer
);
}
return
status
;
}
EXPORT_SYMBOL_GPL
(
acpi_bus_get_ejd
);
static
int
acpi_bus_get_flags
(
struct
acpi_device
*
device
)
{
acpi_status
status
=
AE_OK
;
...
...
include/acpi/acpi_bus.h
View file @
c8f7a62c
...
...
@@ -334,7 +334,7 @@ int acpi_bus_add(struct acpi_device **child, struct acpi_device *parent,
acpi_handle
handle
,
int
type
);
int
acpi_bus_trim
(
struct
acpi_device
*
start
,
int
rmdevice
);
int
acpi_bus_start
(
struct
acpi_device
*
device
);
acpi_status
acpi_bus_get_ejd
(
acpi_handle
handle
,
acpi_handle
*
ejd
);
int
acpi_match_ids
(
struct
acpi_device
*
device
,
char
*
ids
);
int
acpi_create_dir
(
struct
acpi_device
*
);
void
acpi_remove_dir
(
struct
acpi_device
*
);
...
...
include/acpi/acpi_drivers.h
View file @
c8f7a62c
...
...
@@ -110,4 +110,21 @@ int acpi_processor_set_thermal_limit(acpi_handle handle, int type);
extern
int
acpi_specific_hotkey_enabled
;
/*--------------------------------------------------------------------------
Dock Station
-------------------------------------------------------------------------- */
#if defined(CONFIG_ACPI_DOCK) || defined(CONFIG_ACPI_DOCK_MODULE)
extern
int
is_dock_device
(
acpi_handle
handle
);
extern
int
register_dock_notifier
(
struct
notifier_block
*
nb
);
extern
void
unregister_dock_notifier
(
struct
notifier_block
*
nb
);
extern
int
register_hotplug_dock_device
(
acpi_handle
handle
,
acpi_notify_handler
handler
,
void
*
context
);
extern
void
unregister_hotplug_dock_device
(
acpi_handle
handle
);
#else
#define is_dock_device(h) (0)
#define register_dock_notifier(nb) (-ENODEV)
#define unregister_dock_notifier(nb) do { } while(0)
#define register_hotplug_dock_device(h1, h2, c) (-ENODEV)
#define unregister_hotplug_dock_device(h) do { } while(0)
#endif
#endif
/*__ACPI_DRIVERS_H__*/
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment