From 38ff4ffc039ba5a5878f2dcbb03d87c3a1f02f1b Mon Sep 17 00:00:00 2001 From: Kristen Carlson Accardi Date: Wed, 9 May 2007 15:04:24 -0700 Subject: ACPI: dock: cleanup the uid patch Make uid sysfs file error path free memory, and cleanup sysfs file when removing driver. Also fix CodingStyle violations. Signed-off-by: Kristen Carlson Accardi Cc: Illya A. Volynets-Evenbakh Signed-off-by: Len Brown --- drivers/acpi/dock.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 4546bf873aea..9ddc3f189bb7 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -675,16 +675,15 @@ static ssize_t show_dock_uid(struct device *dev, struct device_attribute *attr, char *buf) { unsigned long lbuf; - acpi_status status = acpi_evaluate_integer(dock_station->handle, "_UID", NULL, &lbuf); - if(ACPI_FAILURE(status)) { + acpi_status status = acpi_evaluate_integer(dock_station->handle, + "_UID", NULL, &lbuf); + if (ACPI_FAILURE(status)) return 0; - } + return snprintf(buf, PAGE_SIZE, "%lx\n", lbuf); } DEVICE_ATTR(uid, S_IRUGO, show_dock_uid, NULL); - - /** * dock_add - add a new dock station * @handle: the dock station handle @@ -736,6 +735,8 @@ static int dock_add(acpi_handle handle) ret = device_create_file(&dock_device.dev, &dev_attr_uid); if (ret) { printk("Error %d adding sysfs file\n", ret); + device_remove_file(&dock_device.dev, &dev_attr_docked); + device_remove_file(&dock_device.dev, &dev_attr_undock); platform_device_unregister(&dock_device); kfree(dock_station); return ret; @@ -775,6 +776,7 @@ dock_add_err: dock_add_err_unregister: device_remove_file(&dock_device.dev, &dev_attr_docked); device_remove_file(&dock_device.dev, &dev_attr_undock); + device_remove_file(&dock_device.dev, &dev_attr_uid); platform_device_unregister(&dock_device); kfree(dock_station); return ret; @@ -806,6 +808,7 @@ static int dock_remove(void) /* cleanup sysfs */ device_remove_file(&dock_device.dev, &dev_attr_docked); device_remove_file(&dock_device.dev, &dev_attr_undock); + device_remove_file(&dock_device.dev, &dev_attr_uid); platform_device_unregister(&dock_device); /* free dock station memory */ -- cgit v1.2.3 From 22fe4c2114e29477ca6738729c074ee8f60d3b73 Mon Sep 17 00:00:00 2001 From: Chuck Ebbert Date: Wed, 9 May 2007 15:05:48 -0700 Subject: ACPI: dock: fix opps after dock driver fails to initialize The driver tests the dock_station pointer for nonnull to check whether it has initialized properly. But in some cases dock_station will be non-null after being freed when driver init fails. Fix by zeroing the pointer after freeing. Signed-off-by: Chuck Ebbert Signed-off-by: Kristen Carlson Accardi Signed-off-by: Len Brown --- drivers/acpi/dock.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/acpi') diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 9ddc3f189bb7..f66f4f7767ac 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -715,6 +715,7 @@ static int dock_add(acpi_handle handle) if (ret) { printk(KERN_ERR PREFIX "Error %d registering dock device\n", ret); kfree(dock_station); + dock_station = NULL; return ret; } ret = device_create_file(&dock_device.dev, &dev_attr_docked); @@ -722,6 +723,7 @@ static int dock_add(acpi_handle handle) printk("Error %d adding sysfs file\n", ret); platform_device_unregister(&dock_device); kfree(dock_station); + dock_station = NULL; return ret; } ret = device_create_file(&dock_device.dev, &dev_attr_undock); @@ -730,6 +732,7 @@ static int dock_add(acpi_handle handle) device_remove_file(&dock_device.dev, &dev_attr_docked); platform_device_unregister(&dock_device); kfree(dock_station); + dock_station = NULL; return ret; } ret = device_create_file(&dock_device.dev, &dev_attr_uid); @@ -739,6 +742,7 @@ static int dock_add(acpi_handle handle) device_remove_file(&dock_device.dev, &dev_attr_undock); platform_device_unregister(&dock_device); kfree(dock_station); + dock_station = NULL; return ret; } @@ -751,6 +755,7 @@ static int dock_add(acpi_handle handle) dd = alloc_dock_dependent_device(handle); if (!dd) { kfree(dock_station); + dock_station = NULL; ret = -ENOMEM; goto dock_add_err_unregister; } @@ -779,6 +784,7 @@ dock_add_err_unregister: device_remove_file(&dock_device.dev, &dev_attr_uid); platform_device_unregister(&dock_device); kfree(dock_station); + dock_station = NULL; return ret; } @@ -813,6 +819,7 @@ static int dock_remove(void) /* free dock station memory */ kfree(dock_station); + dock_station = NULL; return 0; } -- cgit v1.2.3 From 0f6f2804563eee64f0fc7cbcb009b98b6f332af6 Mon Sep 17 00:00:00 2001 From: Kristen Carlson Accardi Date: Wed, 9 May 2007 15:07:04 -0700 Subject: ACPI: dock: use dynamically allocated platform device Get rid of no release function warnings by switching to dynamically allocating the platform_device and using the platform device release routine in the base driver. Signed-off-by: Kristen Carlson Accardi Signed-off-by: Len Brown --- drivers/acpi/dock.c | 47 +++++++++++++++++++++++------------------------ 1 file changed, 23 insertions(+), 24 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index f66f4f7767ac..b5addd411b55 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -41,7 +41,7 @@ MODULE_DESCRIPTION(ACPI_DOCK_DRIVER_DESCRIPTION); MODULE_LICENSE("GPL"); static struct atomic_notifier_head dock_notifier_list; -static struct platform_device dock_device; +static struct platform_device *dock_device; static char dock_device_name[] = "dock"; struct dock_station { @@ -327,7 +327,7 @@ static void hotplug_dock_devices(struct dock_station *ds, u32 event) static void dock_event(struct dock_station *ds, u32 event, int num) { - struct device *dev = &dock_device.dev; + struct device *dev = &dock_device->dev; /* * Indicate that the status of the dock station has * changed. @@ -710,37 +710,36 @@ static int dock_add(acpi_handle handle) ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list); /* initialize platform device stuff */ - dock_device.name = dock_device_name; - ret = platform_device_register(&dock_device); - if (ret) { - printk(KERN_ERR PREFIX "Error %d registering dock device\n", ret); + dock_device = + platform_device_register_simple(dock_device_name, 0, NULL, 0); + if (IS_ERR(dock_device)) { kfree(dock_station); dock_station = NULL; - return ret; + return PTR_ERR(dock_device); } - ret = device_create_file(&dock_device.dev, &dev_attr_docked); + ret = device_create_file(&dock_device->dev, &dev_attr_docked); if (ret) { printk("Error %d adding sysfs file\n", ret); - platform_device_unregister(&dock_device); + platform_device_unregister(dock_device); kfree(dock_station); dock_station = NULL; return ret; } - ret = device_create_file(&dock_device.dev, &dev_attr_undock); + ret = device_create_file(&dock_device->dev, &dev_attr_undock); if (ret) { printk("Error %d adding sysfs file\n", ret); - device_remove_file(&dock_device.dev, &dev_attr_docked); - platform_device_unregister(&dock_device); + device_remove_file(&dock_device->dev, &dev_attr_docked); + platform_device_unregister(dock_device); kfree(dock_station); dock_station = NULL; return ret; } - ret = device_create_file(&dock_device.dev, &dev_attr_uid); + ret = device_create_file(&dock_device->dev, &dev_attr_uid); if (ret) { printk("Error %d adding sysfs file\n", ret); - device_remove_file(&dock_device.dev, &dev_attr_docked); - device_remove_file(&dock_device.dev, &dev_attr_undock); - platform_device_unregister(&dock_device); + device_remove_file(&dock_device->dev, &dev_attr_docked); + device_remove_file(&dock_device->dev, &dev_attr_undock); + platform_device_unregister(dock_device); kfree(dock_station); dock_station = NULL; return ret; @@ -779,10 +778,10 @@ static int dock_add(acpi_handle handle) dock_add_err: kfree(dd); dock_add_err_unregister: - device_remove_file(&dock_device.dev, &dev_attr_docked); - device_remove_file(&dock_device.dev, &dev_attr_undock); - device_remove_file(&dock_device.dev, &dev_attr_uid); - platform_device_unregister(&dock_device); + device_remove_file(&dock_device->dev, &dev_attr_docked); + device_remove_file(&dock_device->dev, &dev_attr_undock); + device_remove_file(&dock_device->dev, &dev_attr_uid); + platform_device_unregister(dock_device); kfree(dock_station); dock_station = NULL; return ret; @@ -812,10 +811,10 @@ static int dock_remove(void) printk(KERN_ERR "Error removing notify handler\n"); /* cleanup sysfs */ - device_remove_file(&dock_device.dev, &dev_attr_docked); - device_remove_file(&dock_device.dev, &dev_attr_undock); - device_remove_file(&dock_device.dev, &dev_attr_uid); - platform_device_unregister(&dock_device); + device_remove_file(&dock_device->dev, &dev_attr_docked); + device_remove_file(&dock_device->dev, &dev_attr_undock); + device_remove_file(&dock_device->dev, &dev_attr_uid); + platform_device_unregister(dock_device); /* free dock station memory */ kfree(dock_station); -- cgit v1.2.3 From a0cd35fdca0bb711854edeaf016cec6cdf82eeca Mon Sep 17 00:00:00 2001 From: Kristen Carlson Accardi Date: Wed, 9 May 2007 15:08:15 -0700 Subject: ACPI: dock: add immediate_undock option Allow the driver to be loaded with an option that will allow userspace to control whether the laptop is ejected immediately when the user presses the button, or only when the syfs undock file is written. if immediate_undock == 1, then when the user presses the undock button, the laptop will send an event to userspace to notify userspace of the undock, but then immediately undock without waiting for userspace. This is the current behavior, and I set this to be the default. if immediate_undock == 0, then when the user presses the undock button, the laptop will send an event to userspace and do nothing. User space can query the "flags" sysfs entry to determine if an undock request has been made by the user (if bit 1 is set). User space will then need to write the undock sysfs entry to complete the undocking process. Signed-off-by: Kristen Carlson Accardi Signed-off-by: Len Brown --- drivers/acpi/dock.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 2 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index b5addd411b55..98ec717b14cf 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -40,6 +40,13 @@ MODULE_AUTHOR("Kristen Carlson Accardi"); MODULE_DESCRIPTION(ACPI_DOCK_DRIVER_DESCRIPTION); MODULE_LICENSE("GPL"); +static int immediate_undock = 1; +module_param(immediate_undock, bool, 0644); +MODULE_PARM_DESC(immediate_undock, "1 (default) will cause the driver to " + "undock immediately when the undock button is pressed, 0 will cause" + " the driver to wait for userspace to write the undock sysfs file " + " before undocking"); + static struct atomic_notifier_head dock_notifier_list; static struct platform_device *dock_device; static char dock_device_name[] = "dock"; @@ -63,6 +70,7 @@ struct dock_dependent_device { }; #define DOCK_DOCKING 0x00000001 +#define DOCK_UNDOCKING 0x00000002 #define DOCK_EVENT 3 #define UNDOCK_EVENT 2 @@ -420,6 +428,16 @@ static inline void complete_dock(struct dock_station *ds) ds->last_dock_time = jiffies; } +static inline void begin_undock(struct dock_station *ds) +{ + ds->flags |= DOCK_UNDOCKING; +} + +static inline void complete_undock(struct dock_station *ds) +{ + ds->flags &= ~(DOCK_UNDOCKING); +} + /** * dock_in_progress - see if we are in the middle of handling a dock event * @ds: the dock station @@ -550,7 +568,7 @@ static int handle_eject_request(struct dock_station *ds, u32 event) printk(KERN_ERR PREFIX "Unable to undock!\n"); return -EBUSY; } - + complete_undock(ds); return 0; } @@ -594,7 +612,11 @@ static void dock_notify(acpi_handle handle, u32 event, void *data) * to the driver who wish to hotplug. */ case ACPI_NOTIFY_EJECT_REQUEST: - handle_eject_request(ds, event); + begin_undock(ds); + if (immediate_undock) + handle_eject_request(ds, event); + else + dock_event(ds, event, UNDOCK_EVENT); break; default: printk(KERN_ERR PREFIX "Unknown dock event %d\n", event); @@ -652,6 +674,17 @@ static ssize_t show_docked(struct device *dev, } DEVICE_ATTR(docked, S_IRUGO, show_docked, NULL); +/* + * show_flags - read method for flags file in sysfs + */ +static ssize_t show_flags(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", dock_station->flags); + +} +DEVICE_ATTR(flags, S_IRUGO, show_flags, NULL); + /* * write_undock - write method for "undock" file in sysfs */ @@ -717,6 +750,7 @@ static int dock_add(acpi_handle handle) dock_station = NULL; return PTR_ERR(dock_device); } + ret = device_create_file(&dock_device->dev, &dev_attr_docked); if (ret) { printk("Error %d adding sysfs file\n", ret); @@ -744,6 +778,17 @@ static int dock_add(acpi_handle handle) dock_station = NULL; return ret; } + ret = device_create_file(&dock_device->dev, &dev_attr_flags); + if (ret) { + printk("Error %d adding sysfs file\n", ret); + device_remove_file(&dock_device->dev, &dev_attr_docked); + device_remove_file(&dock_device->dev, &dev_attr_undock); + device_remove_file(&dock_device->dev, &dev_attr_uid); + platform_device_unregister(dock_device); + kfree(dock_station); + dock_station = NULL; + return ret; + } /* Find dependent devices */ acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, @@ -781,6 +826,7 @@ dock_add_err_unregister: device_remove_file(&dock_device->dev, &dev_attr_docked); device_remove_file(&dock_device->dev, &dev_attr_undock); device_remove_file(&dock_device->dev, &dev_attr_uid); + device_remove_file(&dock_device->dev, &dev_attr_flags); platform_device_unregister(dock_device); kfree(dock_station); dock_station = NULL; @@ -814,6 +860,7 @@ static int dock_remove(void) device_remove_file(&dock_device->dev, &dev_attr_docked); device_remove_file(&dock_device->dev, &dev_attr_undock); device_remove_file(&dock_device->dev, &dev_attr_uid); + device_remove_file(&dock_device->dev, &dev_attr_flags); platform_device_unregister(dock_device); /* free dock station memory */ -- cgit v1.2.3 From 9ef2a9a9f08722998540ed2ff38bccd0c54344c8 Mon Sep 17 00:00:00 2001 From: Kristen Carlson Accardi Date: Wed, 9 May 2007 15:09:12 -0700 Subject: ACPI: dock: unsuppress uevents Platform devices may not send uevents by default - override the setting so that we can send uevents on dock/undock. Signed-off-by: Kristen Carlson Accardi Signed-off-by: Len Brown --- drivers/acpi/dock.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/acpi') diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 98ec717b14cf..4efc12cf6173 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -751,6 +751,9 @@ static int dock_add(acpi_handle handle) return PTR_ERR(dock_device); } + /* we want the dock device to send uevents */ + dock_device->dev.uevent_suppress = 0; + ret = device_create_file(&dock_device->dev, &dev_attr_docked); if (ret) { printk("Error %d adding sysfs file\n", ret); -- cgit v1.2.3 From 79a8f70b4b9127eacfc91dd1436c4a7be05e62ab Mon Sep 17 00:00:00 2001 From: Kristen Carlson Accardi Date: Wed, 9 May 2007 15:10:22 -0700 Subject: ACPI: dock: send envp with uevent Send an env along with our KOBJ_CHANGE uevent so that user space has the option of checking for that to see if a dock or undock has occurred. Signed-off-by: Kristen Carlson Accardi Signed-off-by: Len Brown --- drivers/acpi/dock.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 4efc12cf6173..dc3df93d2310 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -336,11 +336,19 @@ static void hotplug_dock_devices(struct dock_station *ds, u32 event) static void dock_event(struct dock_station *ds, u32 event, int num) { struct device *dev = &dock_device->dev; + char event_string[7]; + char *envp[] = { event_string, NULL }; + + if (num == UNDOCK_EVENT) + sprintf(event_string, "UNDOCK"); + else + sprintf(event_string, "DOCK"); + /* * Indicate that the status of the dock station has * changed. */ - kobject_uevent(&dev->kobj, KOBJ_CHANGE); + kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp); } /** -- cgit v1.2.3 From 1f9767df1346c9ce09d6e51b9f34b851e3d94fad Mon Sep 17 00:00:00 2001 From: Kristen Carlson Accardi Date: Wed, 9 May 2007 15:55:53 -0700 Subject: ACPI: bay: unsuppress uevents Since platform devices seem to get uevents suppressed by default, manually unsuppress for the bay device since we want to be able to send uevents. Signed-off-by: Kristen Carlson Accardi Signed-off-by: Len Brown --- drivers/acpi/bay.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/acpi') diff --git a/drivers/acpi/bay.c b/drivers/acpi/bay.c index fb3f31b5e69f..00d3f3f17a2a 100644 --- a/drivers/acpi/bay.c +++ b/drivers/acpi/bay.c @@ -288,6 +288,11 @@ static int bay_add(acpi_handle handle, int id) new_bay->pdev = pdev; platform_set_drvdata(pdev, new_bay); + /* + * we want the bay driver to be able to send uevents + */ + pdev->dev.uevent_suppress = 0; + if (acpi_bay_add_fs(new_bay)) { platform_device_unregister(new_bay->pdev); goto bay_add_err; -- cgit v1.2.3 From 3f8698d4d3f72252980575fb8d7b4cafeb5dd0a2 Mon Sep 17 00:00:00 2001 From: Kristen Carlson Accardi Date: Wed, 23 May 2007 14:12:29 -0700 Subject: ACPI: bay: send envp with uevent Make the bay driver send env information on bay events. Upon any bay event, we will send the string "BAY_EVENT=%d" along with the KOBJ_CHANGE, and report the event number. What the event number means will be platform specific. Event 3 is always an eject request, but an insert may be either event 1, or it may be event 0. Event 1 may also be a remove request. It would be best if you check the number of your event with udevmonitor before writing any udev scripts for inserting and removing drive bays. Signed-off-by: Kristen Carlson Accardi Cc: Stephan Berberig Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- drivers/acpi/bay.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/bay.c b/drivers/acpi/bay.c index 00d3f3f17a2a..56a5b3fffeb3 100644 --- a/drivers/acpi/bay.c +++ b/drivers/acpi/bay.c @@ -333,18 +333,12 @@ static void bay_notify(acpi_handle handle, u32 event, void *data) { struct bay *bay_dev = (struct bay *)data; struct device *dev = &bay_dev->pdev->dev; + char event_string[12]; + char *envp[] = { event_string, NULL }; bay_dprintk(handle, "Bay event"); - - switch(event) { - case ACPI_NOTIFY_BUS_CHECK: - case ACPI_NOTIFY_DEVICE_CHECK: - case ACPI_NOTIFY_EJECT_REQUEST: - kobject_uevent(&dev->kobj, KOBJ_CHANGE); - break; - default: - printk(KERN_ERR PREFIX "Bay: unknown event %d\n", event); - } + sprintf(event_string, "BAY_EVENT=%d\n", event); + kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp); } static acpi_status -- cgit v1.2.3 From 9254bc845db90a123cf992e983539d0ee409f22a Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 18 Jul 2007 01:10:24 -0400 Subject: ACPI: dock: fix oops when _DCK evaluation fails Data returned by acpi_get_name in acpi_buffer is not acpi_object and therefore should not be cast to it, otherwise we'll get an nice oops trying to print error message. Also print name of the ACPI object corresponding to the docking station and elevate severity of the message printed when _DCK fails to KERN_ERR. Signed-off-by: Dmitry Torokhov Cc: Kristen Carlson Accardi Signed-off-by: Len Brown --- drivers/acpi/dock.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index dc3df93d2310..6192c8be66df 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -396,12 +396,11 @@ static void handle_dock(struct dock_station *ds, int dock) 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"); + printk(KERN_INFO PREFIX "%s - %s\n", + (char *)name_buffer.pointer, dock ? "docking" : "undocking"); /* _DCK method has one argument */ arg_list.count = 1; @@ -410,7 +409,8 @@ static void handle_dock(struct dock_station *ds, int dock) 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); + printk(KERN_ERR PREFIX "%s - failed to execute _DCK\n", + (char *)name_buffer.pointer); kfree(buffer.pointer); kfree(name_buffer.pointer); } -- cgit v1.2.3