From: Jean Delvare <khali@linux-fr.org>
To: lm-sensors@vger.kernel.org
Subject: [lm-sensors] [PATCH] hwmon: (smsc47m1) Only request I/O ports we
Date: Wed, 11 Nov 2009 21:43:00 +0000 [thread overview]
Message-ID: <20091111224300.7ff99bda@hyperion.delvare> (raw)
The I/O area of the SMSC LPC47M1xx/292 chips which we use, gives access
to a lot of registers, some of which are related to fan speed monitoring
and control, but many are not. At the moment, the smsc47m1 driver
requests the whole I/O port range. This could easily result in
resource conflicts with either ACPI or other drivers.
Request only the I/O ports we really use, to prevent such conflicts.
Signed-off-by: Jean Delvare <khali@linux-fr.org>
---
This needs testing! If anyone around has a device supported by the
smsc47m1 driver and has the possibility to test this patch, please do
and report.
drivers/hwmon/smsc47m1.c | 89 ++++++++++++++++++++++++++++++++++++++++------
1 file changed, 79 insertions(+), 10 deletions(-)
--- linux-2.6.32-rc6.orig/drivers/hwmon/smsc47m1.c 2009-11-11 15:29:11.000000000 +0100
+++ linux-2.6.32-rc6/drivers/hwmon/smsc47m1.c 2009-11-11 22:15:21.000000000 +0100
@@ -481,13 +481,85 @@ static int __init smsc47m1_find(unsigned
return 0;
}
+/*
+ * This function can be used to:
+ * - test for resource conflicts with ACPI (dev = NULL, request = 0)
+ * - request the resources (dev != NULL, request = 1)
+ * - release the resources (dev != NULL, request = 0)
+ * We only allocate the I/O ports we really need, to minimize the risk of
+ * conflicts with ACPI or with other drivers.
+ */
+static int smsc47m1_handle_resources(unsigned short address, enum chips type,
+ struct device *dev, int request)
+{
+ static const u8 ports_m1[] = {
+ /* register, region length */
+ 0x04, 1,
+ 0x33, 4,
+ 0x56, 7,
+ };
+
+ static const u8 ports_m2[] = {
+ /* register, region length */
+ 0x04, 1,
+ 0x09, 1,
+ 0x2c, 2,
+ 0x35, 4,
+ 0x56, 7,
+ 0x69, 4,
+ };
+
+ int i, ports_size, err;
+ const u8 *ports;
+
+ switch (type) {
+ case smsc47m1:
+ default:
+ ports = ports_m1;
+ ports_size = ARRAY_SIZE(ports_m1);
+ break;
+ case smsc47m2:
+ ports = ports_m2;
+ ports_size = ARRAY_SIZE(ports_m2);
+ break;
+ }
+
+ for (i = 0; i + 1 < ports_size; i += 2) {
+ unsigned short start = address + ports[i];
+ unsigned short len = ports[i + 1];
+
+ if (!dev) {
+ /* Only check for conflicts */
+ err = acpi_check_region(start, len, DRVNAME);
+ if (err)
+ return err;
+ } else if (request) {
+ /* Request the resources */
+ if (!request_region(start, len, DRVNAME)) {
+ dev_err(dev, "Region 0x%hx-0x%hx already in "
+ "use!\n", start, start + len);
+
+ /* Undo all requests */
+ for (i -= 2; i >= 0; i -= 2)
+ release_region(start, len);
+ return -EBUSY;
+ }
+ } else {
+ /* Release the resources */
+ release_region(start, len);
+ }
+ }
+
+ return 0;
+}
+
static int __devinit smsc47m1_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct smsc47m1_sio_data *sio_data = dev->platform_data;
struct smsc47m1_data *data;
struct resource *res;
- int err = 0;
+ int err;
int fan1, fan2, fan3, pwm1, pwm2, pwm3;
static const char *names[] = {
@@ -496,12 +568,9 @@ static int __devinit smsc47m1_probe(stru
};
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
- if (!request_region(res->start, SMSC_EXTENT, DRVNAME)) {
- dev_err(dev, "Region 0x%lx-0x%lx already in use!\n",
- (unsigned long)res->start,
- (unsigned long)res->end);
- return -EBUSY;
- }
+ err = smsc47m1_handle_resources(res->start, sio_data->type, dev, 1);
+ if (err < 0)
+ return err;
if (!(data = kzalloc(sizeof(struct smsc47m1_data), GFP_KERNEL))) {
err = -ENOMEM;
@@ -637,7 +706,7 @@ error_free:
platform_set_drvdata(pdev, NULL);
kfree(data);
error_release:
- release_region(res->start, SMSC_EXTENT);
+ smsc47m1_handle_resources(res->start, sio_data->type, dev, 0);
return err;
}
@@ -650,7 +719,7 @@ static int __devexit smsc47m1_remove(str
sysfs_remove_group(&pdev->dev.kobj, &smsc47m1_group);
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
- release_region(res->start, SMSC_EXTENT);
+ smsc47m1_handle_resources(res->start, data->type, &pdev->dev, 0);
platform_set_drvdata(pdev, NULL);
kfree(data);
@@ -717,7 +786,7 @@ static int __init smsc47m1_device_add(un
};
int err;
- err = acpi_check_resource_conflict(&res);
+ err = smsc47m1_handle_resources(address, sio_data->type, NULL, 0);
if (err)
goto exit;
--
Jean Delvare
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
reply other threads:[~2009-11-11 21:43 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20091111224300.7ff99bda@hyperion.delvare \
--to=khali@linux-fr.org \
--cc=lm-sensors@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.