From: Mattia Dongili <malattia@linux.it>
To: ACPI Devel Maling List <linux-acpi@vger.kernel.org>
Cc: Len Brown <lenb@kernel.org>, Stelian Pop <stelian@popies.net>
Subject: [HELP] sonypi going acpi-only
Date: Sun, 25 Feb 2007 20:02:46 +0100 [thread overview]
Message-ID: <20070225190246.GA29882@inferi.kami.home> (raw)
Hello,
I'm currently rewriting sonypi to use acpi-only functions for its
initialization. It seems I'm successful in this except that I don't get
IRQs on button or jogdial events. Actually 2 irqs are reported on device
enabling and disabling (_SRS and _DIS).
No irq is even reported in /proc/interrupts except the two mentioned.
This is sonypi v/s sony-pic (my driver) log, the 'event' is the irq
handling:
sonypi: Sony Programmable I/O Controller Driver v1.26.
sonypi: detected type3 model, verbose = 2, fnkeyinit = off, camera = off, compat = off, mask = 0xffffffff, useinput = on, acpi = on
sonypi: enabled at irq=11, port1=0x1080, port2=0x1084
sonypi: device allocated minor is 63
input: Sony Vaio Jogdial as /class/input/input25
input: Sony Vaio Keys as /class/input/input26
sonypi: event port1=0x00,port2=0xff
sonypi: event port1=0x00,port2=0xff
sonypi: unknown event port1=0x0e,port2=0xff <== end module loading
sonypi: event port1=0x5c,port2=0xff <== button press
sonypi: event port1=0x5c,port2=0xff
sonypi: event port1=0x00,port2=0xff <== module unload
sonypi: unknown event port1=0xff,port2=0xff
sonypi: removed.
sony-pic: Sony Programmable I/O Controller Driver v0.1.
sony-pic: Device disabled
sony-pic: I/O port: 0x1080 + 0x20
sony-pic: IRQ: 11 - triggering: 1
sony-pic: event (0xffffffff) at port 1080 <== irq after _SRS
sony-pic: Device enabled
sony-pic: Current IO port: 1080 + 0020
sony-pic: Current IRQ 11 <== end module loading
sony-pic: event (0xffffffff) at port 1080 <== module unload (_DIS)
sony-pic: removed.
sony-pic.c follows anyway something that is easily noticeable is that it
reads a different value when reading the ioport... I guess it's telling
me that the device has not been enabled correctly (??).
Can you see anything obvious I'm missing, especially in sony_pic_enable
or sony_pic_add?
Some useful info:
- a DSDT of a (formerly in sonypi) Type3 SPIC:
http://www.linux.it/~malattia/sony-pic/DSDT.sz72b.dsl
- a DSDT of a (formerly in sonypi) Type2 SPIC:
http://www.linux.it/~malattia/sony-pic/DSDT.gr7k.dsl
(Look for Device(SPIC) or SNY6001)
- a nice makefile to build the driver:
http://www.linux.it/~malattia/sony-pic/Makefile
- the driver itself (also included at the end of this mail):
http://www.linux.it/~malattia/sony-pic/sony-pic.c
- the driver didn't burn my HW on a Type2 and Type3 devices :)
Thanks for any suggestion/hint.
--
mattia
:wq!
/*
* Sony Programmable I/O Control Device driver for VAIO
*
* Copyright (C) 2007 Mattia Dongili <malattia@linux.it>
*
* This driver is based on previous work which includes material from:
*
* Copyright (C) 2001-2005 Stelian Pop <stelian@popies.net>
*
* Copyright (C) 2005 Narayanan R S <nars@kadamba.org>
*
* Copyright (C) 2001-2002 Alc?ve <www.alcove.com>
*
* Copyright (C) 2001 Michael Ashley <m.ashley@unsw.edu.au>
*
* Copyright (C) 2001 Junichi Morita <jun1m@mars.dti.ne.jp>
*
* Copyright (C) 2000 Takaya Kinjo <t-kinjo@tc4.so-net.ne.jp>
*
* Copyright (C) 2000 Andrew Tridgell <tridge@valinux.com>
*
* Earlier work by Werner Almesberger, Paul `Rusty' Russell and Paul Mackerras.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include <linux/module.h>
#include <linux/dmi.h>
#include <linux/acpi.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
#define SONY_PIC_DEBUG 1
#define SONYPIC_DRIVER_VERSION "0.1"
#define SONY_PIC_PREFIX "sony-pic: "
#ifdef SONY_PIC_DEBUG
#define dprintk(msg...) printk(KERN_WARNING SONY_PIC_PREFIX msg)
#else
#define dprintk(msg...)
#endif
#define ACPI_PIC_DRIVER_NAME "sony-pic"
#define ACPI_PIC_CLASS "sony"
#define ACPI_PIC_HID "SNY6001"
MODULE_AUTHOR("Mattia Dongili <malattia@linux.it>");
MODULE_DESCRIPTION("Sony Programmable I/O Control Device driver (ACPI based)");
MODULE_LICENSE("GPL");
MODULE_VERSION(SONYPIC_DRIVER_VERSION);
struct sony_pic_ioport {
struct acpi_resource_io io;
struct list_head list;
};
struct sony_pic_irq {
struct acpi_resource_irq irq;
struct list_head list;
};
struct sony_pic_dev {
acpi_handle *handle;
struct sony_pic_irq *cur_irq;
struct sony_pic_ioport *cur_ioport;
struct list_head interrupts;
struct list_head ioports;
};
static struct sony_pic_dev spic_dev = {
.interrupts = LIST_HEAD_INIT(spic_dev.interrupts),
.ioports = LIST_HEAD_INIT(spic_dev.ioports),
};
#ifdef SONY_PIC_DEBUG
static acpi_status
sony_pic_read_current_resource(struct acpi_resource *resource, void *context)
{
switch (resource->type) {
case ACPI_RESOURCE_TYPE_IRQ:
{
struct acpi_resource_irq *p = &resource->data.irq;
if (!p || !p->interrupt_count) {
/*
* IRQ descriptors may have no IRQ# bits set,
* particularly those those w/ _STA disabled
*/
dprintk("Blank IRQ resource\n");
return AE_OK;
}
dprintk("Current IRQ %d\n", p->interrupts[0]);
return AE_OK;
}
case ACPI_RESOURCE_TYPE_IO:
{
struct acpi_resource_io *io = &resource->data.io;
if (!io) {
dprintk("Blank IO resource\n");
return AE_OK;
}
dprintk("Current IO port: 0x%.4x + 0x%.2x\n",
io->minimum, io->address_length);
return AE_OK;
}
default:
dprintk("Resource %d isn't an IRQ nor an IO port\n",
resource->type);
case ACPI_RESOURCE_TYPE_END_TAG:
return AE_OK;
}
return AE_CTRL_TERMINATE;
}
#define sony_pic_current_resources(device) \
sony_pic_resources(device, METHOD_NAME__CRS, \
sony_pic_read_current_resource);
#endif /* SONY_PIC_DEBUG */
static acpi_status
sony_pic_read_possible_resource(struct acpi_resource *resource, void *context)
{
u32 i;
struct sony_pic_dev *dev = (struct sony_pic_dev *)context;
switch (resource->type) {
case ACPI_RESOURCE_TYPE_START_DEPENDENT:
case ACPI_RESOURCE_TYPE_END_DEPENDENT:
return AE_OK;
case ACPI_RESOURCE_TYPE_IRQ:
{
struct acpi_resource_irq *p = &resource->data.irq;
struct sony_pic_irq *interrupt = NULL;
if (!p || !p->interrupt_count) {
/*
* IRQ descriptors may have no IRQ# bits set,
* particularly those those w/ _STA disabled
*/
dprintk("Blank IRQ resource\n");
return AE_OK;
}
for (i = 0; i < p->interrupt_count; i++) {
if (!p->interrupts[i]) {
printk(KERN_WARNING SONY_PIC_PREFIX
"Invalid IRQ %d\n",
p->interrupts[i]);
continue;
}
interrupt = kzalloc(sizeof(*interrupt),
GFP_KERNEL);
if (!interrupt)
return AE_ERROR;
list_add(&interrupt->list, &dev->interrupts);
interrupt->irq.triggering = p->triggering;
interrupt->irq.polarity = p->polarity;
interrupt->irq.sharable = p->sharable;
interrupt->irq.interrupt_count = 1;
interrupt->irq.interrupts[0] = p->interrupts[i];
}
return AE_OK;
}
case ACPI_RESOURCE_TYPE_IO:
{
struct acpi_resource_io *io = &resource->data.io;
struct sony_pic_ioport *ioport = NULL;
if (!io) {
dprintk("Blank IO resource\n");
return AE_OK;
}
ioport = kzalloc(sizeof(*ioport), GFP_KERNEL);
if (!ioport)
return AE_ERROR;
list_add(&ioport->list, &dev->ioports);
memcpy(&ioport->io, io, sizeof(*io));
return AE_OK;
}
default:
dprintk("Resource %d isn't an IRQ nor an IO port\n",
resource->type);
case ACPI_RESOURCE_TYPE_END_TAG:
return AE_OK;
}
return AE_CTRL_TERMINATE;
}
#define sony_pic_possible_resources(device) \
sony_pic_resources(device, METHOD_NAME__PRS, \
sony_pic_read_possible_resource);
static int sony_pic_resources(struct acpi_device *device, char *method,
acpi_status (*callback) (struct acpi_resource *resource,
void *context))
{
int result = 0;
acpi_status status = AE_OK;
if (!device)
return -EINVAL;
dprintk("Evaluating %s\n", method);
/* get device status */
/* see acpi_pci_link_get_current acpi_pci_link_get_possible */
result = acpi_bus_get_status(device);
if (result) {
printk(KERN_WARNING SONY_PIC_PREFIX "Unable to read status\n");
goto end;
}
if (!device->status.enabled)
dprintk("Device disabled\n");
else
dprintk("Device enabled\n");
/*
* Query and parse 'method'
*/
status = acpi_walk_resources(device->handle, method, callback,
&spic_dev);
if (ACPI_FAILURE(status)) {
printk(KERN_WARNING SONY_PIC_PREFIX
"Failure evaluating %s\n", method);
result = -ENODEV;
}
end:
return result;
}
/*
* Disable the spic device by calling its _DIS method
*/
static int sony_pic_disable(struct acpi_device *device)
{
#ifdef SONY_PIC_DEBUG
/* debug: query _CRS and print current settings */
sony_pic_current_resources(device);
#endif
if (ACPI_FAILURE(acpi_evaluate_object(device->handle, "_DIS", 0, NULL)))
return -ENXIO;
dprintk("Device disabled\n");
return 0;
}
/*
* Based on drivers/acpi/pci_link.c:acpi_pci_link_set
*
* Call _SRS to set current resources
*/
static int sony_pic_enable(struct acpi_device *device,
struct sony_pic_ioport *ioport, struct sony_pic_irq *irq)
{
acpi_status status;
int result = 0;
struct {
struct acpi_resource io_res;
struct acpi_resource irq_res;
struct acpi_resource end;
} *resource;
struct acpi_buffer buffer = { 0, NULL };
if (!ioport || !irq)
return -EINVAL;
/* init acpi_buffer */
resource = kzalloc(sizeof(*resource) + 1, GFP_KERNEL);
if (!resource)
return -ENOMEM;
buffer.length = sizeof(*resource) + 1;
buffer.pointer = resource;
/* setup io resource */
resource->io_res.type = ACPI_RESOURCE_TYPE_IO;
resource->io_res.length = sizeof(struct acpi_resource);
memcpy(&resource->io_res.data.io, &ioport->io,
sizeof(struct acpi_resource_io));
/* setup irq resource */
resource->irq_res.type = ACPI_RESOURCE_TYPE_IRQ;
resource->irq_res.length = sizeof(struct acpi_resource);
memcpy(&resource->irq_res.data.irq, &irq->irq,
sizeof(struct acpi_resource_irq));
/* we requested a shared irq */
resource->irq_res.data.irq.sharable = ACPI_SHARED;
resource->end.type = ACPI_RESOURCE_TYPE_END_TAG;
/* Attempt to set the resource */
status = acpi_set_current_resources(device->handle, &buffer);
/* check for total failure */
if (ACPI_FAILURE(status)) {
printk(KERN_ERR SONY_PIC_PREFIX "Error evaluating _SRS");
result = -ENODEV;
goto end;
}
#ifdef SONY_PIC_DEBUG
/* debug: query _CRS and print current settings */
sony_pic_current_resources(device);
#endif
end:
kfree(resource);
return result;
}
/* Interrupt handler: some event is available */
static irqreturn_t sony_pic_irq(int irq, void *dev_id)
{
unsigned int v = 0;
struct sony_pic_dev *dev = (struct sony_pic_dev *) dev_id;
switch (dev->cur_ioport->io.address_length) {
case 8:
v = inb_p(dev->cur_ioport->io.minimum);
break;
case 16:
v = inw_p(dev->cur_ioport->io.minimum);
break;
case 32:
v = inl_p(dev->cur_ioport->io.minimum);
break;
default:
printk(KERN_WARNING SONY_PIC_PREFIX "unknown addr length "
"(0x%.2x)\n",
dev->cur_ioport->io.address_length);
return IRQ_HANDLED;
}
/* from SONYPI */
/*
u8 v1, v2, event = 0;
v1 = inb_p(sonypi_device.ioport1);
v2 = inb_p(sonypi_device.ioport1 + sonypi_device.evtype_offset);
printk(KERN_INFO "sonypi: event port1=0x%02x,port2=0x%02x\n", v1, v2);
*/
printk(KERN_INFO SONY_PIC_PREFIX "event (0x%.8x) at port %.4x\n", v,
dev->cur_ioport->io.minimum);
return IRQ_HANDLED;
}
/*****************
*
* ACPI driver
*
*****************/
static int sony_pic_remove(struct acpi_device *device, int type)
{
struct sony_pic_ioport *io, *tmp_io;
struct sony_pic_irq *irq, *tmp_irq;
if (sony_pic_disable(device)) {
printk(KERN_ERR SONY_PIC_PREFIX "Couldn't disable device.\n");
return -ENXIO;
}
free_irq(spic_dev.cur_irq->irq.interrupts[0], &spic_dev);
release_region(spic_dev.cur_ioport->io.minimum,
spic_dev.cur_ioport->io.address_length);
list_for_each_entry_safe(io, tmp_io, &spic_dev.ioports, list) {
list_del(&io->list);
kfree(io);
}
list_for_each_entry_safe(irq, tmp_irq, &spic_dev.interrupts, list) {
list_del(&irq->list);
kfree(irq);
}
spic_dev.cur_ioport = NULL;
spic_dev.cur_irq = NULL;
dprintk("removed.\n");
return 0;
}
static int sony_pic_add(struct acpi_device *device)
{
int result;
struct sony_pic_ioport *io, *tmp_io;
struct sony_pic_irq *irq, *tmp_irq;
printk(KERN_INFO
"sony-pic: Sony Programmable I/O Controller Driver v%s.\n",
SONYPIC_DRIVER_VERSION);
spic_dev.handle = device->handle;
/* read _PRS resources */
result = sony_pic_possible_resources(device);
if (result) {
printk(KERN_ERR SONY_PIC_PREFIX
"Unabe to read possible resources.\n");
goto err_free_resources;
}
/* request io port */
list_for_each_entry_reverse(io, &spic_dev.ioports, list) {
if (request_region(io->io.minimum, io->io.address_length,
"Sony Programable I/O Device")) {
dprintk("I/O port: 0x%.4x + 0x%.2x\n",
io->io.minimum, io->io.address_length);
spic_dev.cur_ioport = io;
break;
}
}
if (!spic_dev.cur_ioport) {
printk(KERN_ERR SONY_PIC_PREFIX "Failed to request_region.\n");
result = -ENODEV;
goto err_free_resources;
}
/* request IRQ */
list_for_each_entry(irq, &spic_dev.interrupts, list) {
if (!request_irq(irq->irq.interrupts[0], sony_pic_irq,
IRQF_SHARED, "sony-pic", &spic_dev)) {
dprintk("IRQ: %d - triggering: %d\n",
irq->irq.interrupts[0],
irq->irq.triggering);
spic_dev.cur_irq = irq;
break;
}
}
if (!spic_dev.cur_irq) {
printk(KERN_ERR SONY_PIC_PREFIX "Failed to request_irq.\n");
result = -ENODEV;
goto err_release_region;
}
/* set resource status _SRS */
result = sony_pic_enable(device, spic_dev.cur_ioport, spic_dev.cur_irq);
if (result) {
printk(KERN_ERR SONY_PIC_PREFIX "Couldn't enable device.\n");
goto err_free_irq;
}
return 0;
err_free_irq:
free_irq(spic_dev.cur_irq->irq.interrupts[0], &spic_dev);
err_release_region:
release_region(spic_dev.cur_ioport->io.minimum, spic_dev.cur_ioport->io.address_length);
err_free_resources:
list_for_each_entry_safe(io, tmp_io, &spic_dev.ioports, list) {
list_del(&io->list);
kfree(io);
}
list_for_each_entry_safe(irq, tmp_irq, &spic_dev.interrupts, list) {
list_del(&irq->list);
kfree(irq);
}
spic_dev.cur_ioport = NULL;
spic_dev.cur_irq = NULL;
return result;
}
static int sony_pic_suspend(struct acpi_device *device, pm_message_t state)
{
if (sony_pic_disable(device))
return -ENXIO;
return 0;
}
static int sony_pic_resume(struct acpi_device *device)
{
sony_pic_enable(device, spic_dev.cur_ioport, spic_dev.cur_irq);
return 0;
}
static struct acpi_driver sony_pic_driver = {
.name = ACPI_PIC_DRIVER_NAME,
.class = ACPI_PIC_CLASS,
.ids = ACPI_PIC_HID,
.ops = {
.add = sony_pic_add,
.remove = sony_pic_remove,
.suspend = sony_pic_suspend,
.resume = sony_pic_resume,
},
};
static struct dmi_system_id __initdata sonypi_dmi_table[] = {
{
.ident = "Sony Vaio",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
DMI_MATCH(DMI_PRODUCT_NAME, "PCG-"),
},
},
{
.ident = "Sony Vaio",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
DMI_MATCH(DMI_PRODUCT_NAME, "VGN-"),
},
},
{ }
};
static int __init sony_pic_init(void)
{
if (!dmi_check_system(sonypi_dmi_table))
return -ENODEV;
return acpi_bus_register_driver(&sony_pic_driver);
}
static void __exit sony_pic_exit(void)
{
acpi_bus_unregister_driver(&sony_pic_driver);
}
module_init(sony_pic_init);
module_exit(sony_pic_exit);
reply other threads:[~2007-02-25 19:02 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=20070225190246.GA29882@inferi.kami.home \
--to=malattia@linux.it \
--cc=lenb@kernel.org \
--cc=linux-acpi@vger.kernel.org \
--cc=stelian@popies.net \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox