1
0
Fork 0

sony-laptop: old Vaio models contain 2 IO port entries

Make the driver aware of this case and manage the existence of a
second separate IO port.

Signed-off-by: Mattia Dongili <malattia@linux.it>
Signed-off-by: Len Brown <len.brown@intel.com>
hifive-unleashed-5.1
Mattia Dongili 2007-08-12 16:20:28 +09:00 committed by Len Brown
parent 015a916fbb
commit fd1caaed46
1 changed files with 148 additions and 56 deletions

View File

@ -1173,7 +1173,8 @@ static struct acpi_driver sony_nc_driver = {
#define SONYPI_TYPE3_OFFSET 0x12
struct sony_pic_ioport {
struct acpi_resource_io io;
struct acpi_resource_io io1;
struct acpi_resource_io io2;
struct list_head list;
};
@ -1443,11 +1444,11 @@ static u8 sony_pic_call1(u8 dev)
{
u8 v1, v2;
wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2,
wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2,
ITERATIONS_LONG);
outb(dev, spic_dev.cur_ioport->io.minimum + 4);
v1 = inb_p(spic_dev.cur_ioport->io.minimum + 4);
v2 = inb_p(spic_dev.cur_ioport->io.minimum);
outb(dev, spic_dev.cur_ioport->io1.minimum + 4);
v1 = inb_p(spic_dev.cur_ioport->io1.minimum + 4);
v2 = inb_p(spic_dev.cur_ioport->io1.minimum);
dprintk("sony_pic_call1: 0x%.4x\n", (v2 << 8) | v1);
return v2;
}
@ -1456,13 +1457,13 @@ static u8 sony_pic_call2(u8 dev, u8 fn)
{
u8 v1;
wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2,
wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2,
ITERATIONS_LONG);
outb(dev, spic_dev.cur_ioport->io.minimum + 4);
wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2,
outb(dev, spic_dev.cur_ioport->io1.minimum + 4);
wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2,
ITERATIONS_LONG);
outb(fn, spic_dev.cur_ioport->io.minimum);
v1 = inb_p(spic_dev.cur_ioport->io.minimum);
outb(fn, spic_dev.cur_ioport->io1.minimum);
v1 = inb_p(spic_dev.cur_ioport->io1.minimum);
dprintk("sony_pic_call2: 0x%.4x\n", v1);
return v1;
}
@ -1471,13 +1472,13 @@ static u8 sony_pic_call3(u8 dev, u8 fn, u8 v)
{
u8 v1;
wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2, ITERATIONS_LONG);
outb(dev, spic_dev.cur_ioport->io.minimum + 4);
wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2, ITERATIONS_LONG);
outb(fn, spic_dev.cur_ioport->io.minimum);
wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2, ITERATIONS_LONG);
outb(v, spic_dev.cur_ioport->io.minimum);
v1 = inb_p(spic_dev.cur_ioport->io.minimum);
wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG);
outb(dev, spic_dev.cur_ioport->io1.minimum + 4);
wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG);
outb(fn, spic_dev.cur_ioport->io1.minimum);
wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG);
outb(v, spic_dev.cur_ioport->io1.minimum);
v1 = inb_p(spic_dev.cur_ioport->io1.minimum);
dprintk("sony_pic_call3: 0x%.4x\n", v1);
return v1;
}
@ -2074,7 +2075,18 @@ sony_pic_read_possible_resource(struct acpi_resource *resource, void *context)
switch (resource->type) {
case ACPI_RESOURCE_TYPE_START_DEPENDENT:
{
/* start IO enumeration */
struct sony_pic_ioport *ioport = kzalloc(sizeof(*ioport), GFP_KERNEL);
if (!ioport)
return AE_ERROR;
list_add(&ioport->list, &dev->ioports);
return AE_OK;
}
case ACPI_RESOURCE_TYPE_END_DEPENDENT:
/* end IO enumeration */
return AE_OK;
case ACPI_RESOURCE_TYPE_IRQ:
@ -2101,7 +2113,7 @@ sony_pic_read_possible_resource(struct acpi_resource *resource, void *context)
if (!interrupt)
return AE_ERROR;
list_add_tail(&interrupt->list, &dev->interrupts);
list_add(&interrupt->list, &dev->interrupts);
interrupt->irq.triggering = p->triggering;
interrupt->irq.polarity = p->polarity;
interrupt->irq.sharable = p->sharable;
@ -2113,18 +2125,27 @@ sony_pic_read_possible_resource(struct acpi_resource *resource, void *context)
case ACPI_RESOURCE_TYPE_IO:
{
struct acpi_resource_io *io = &resource->data.io;
struct sony_pic_ioport *ioport = NULL;
struct sony_pic_ioport *ioport =
list_first_entry(&dev->ioports, struct sony_pic_ioport, list);
if (!io) {
dprintk("Blank IO resource\n");
return AE_OK;
}
ioport = kzalloc(sizeof(*ioport), GFP_KERNEL);
if (!ioport)
if (!ioport->io1.minimum) {
memcpy(&ioport->io1, io, sizeof(*io));
dprintk("IO1 at 0x%.4x (0x%.2x)\n", ioport->io1.minimum,
ioport->io1.address_length);
}
else if (!ioport->io2.minimum) {
memcpy(&ioport->io2, io, sizeof(*io));
dprintk("IO2 at 0x%.4x (0x%.2x)\n", ioport->io2.minimum,
ioport->io2.address_length);
}
else {
printk(KERN_ERR DRV_PFX "Unknown SPIC Type, more than 2 IO Ports\n");
return AE_ERROR;
list_add_tail(&ioport->list, &dev->ioports);
memcpy(&ioport->io, io, sizeof(*io));
}
return AE_OK;
}
default:
@ -2199,10 +2220,22 @@ static int sony_pic_enable(struct acpi_device *device,
{
acpi_status status;
int result = 0;
/* Type 1 resource layout is:
* IO
* IO
* IRQNoFlags
* End
*
* Type 2 and 3 resource layout is:
* IO
* IRQNoFlags
* End
*/
struct {
struct acpi_resource io_res;
struct acpi_resource irq_res;
struct acpi_resource end;
struct acpi_resource res1;
struct acpi_resource res2;
struct acpi_resource res3;
struct acpi_resource res4;
} *resource;
struct acpi_buffer buffer = { 0, NULL };
@ -2217,21 +2250,49 @@ static int sony_pic_enable(struct acpi_device *device,
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 Type 1 resources */
if (spic_dev.model == SONYPI_DEVICE_TYPE1) {
/* 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;
/* setup io resources */
resource->res1.type = ACPI_RESOURCE_TYPE_IO;
resource->res1.length = sizeof(struct acpi_resource);
memcpy(&resource->res1.data.io, &ioport->io1,
sizeof(struct acpi_resource_io));
resource->end.type = ACPI_RESOURCE_TYPE_END_TAG;
resource->res2.type = ACPI_RESOURCE_TYPE_IO;
resource->res2.length = sizeof(struct acpi_resource);
memcpy(&resource->res2.data.io, &ioport->io2,
sizeof(struct acpi_resource_io));
/* setup irq resource */
resource->res3.type = ACPI_RESOURCE_TYPE_IRQ;
resource->res3.length = sizeof(struct acpi_resource);
memcpy(&resource->res3.data.irq, &irq->irq,
sizeof(struct acpi_resource_irq));
/* we requested a shared irq */
resource->res3.data.irq.sharable = ACPI_SHARED;
resource->res4.type = ACPI_RESOURCE_TYPE_END_TAG;
}
/* setup Type 2/3 resources */
else {
/* setup io resource */
resource->res1.type = ACPI_RESOURCE_TYPE_IO;
resource->res1.length = sizeof(struct acpi_resource);
memcpy(&resource->res1.data.io, &ioport->io1,
sizeof(struct acpi_resource_io));
/* setup irq resource */
resource->res2.type = ACPI_RESOURCE_TYPE_IRQ;
resource->res2.length = sizeof(struct acpi_resource);
memcpy(&resource->res2.data.irq, &irq->irq,
sizeof(struct acpi_resource_irq));
/* we requested a shared irq */
resource->res2.data.irq.sharable = ACPI_SHARED;
resource->res3.type = ACPI_RESOURCE_TYPE_END_TAG;
}
/* Attempt to set the resource */
dprintk("Evaluating _SRS\n");
@ -2239,7 +2300,7 @@ static int sony_pic_enable(struct acpi_device *device,
/* check for total failure */
if (ACPI_FAILURE(status)) {
printk(KERN_ERR DRV_PFX "Error evaluating _SRS");
printk(KERN_ERR DRV_PFX "Error evaluating _SRS\n");
result = -ENODEV;
goto end;
}
@ -2268,11 +2329,14 @@ static irqreturn_t sony_pic_irq(int irq, void *dev_id)
struct sony_pic_dev *dev = (struct sony_pic_dev *) dev_id;
ev = inb_p(dev->cur_ioport->io.minimum);
data_mask = inb_p(dev->cur_ioport->io.minimum + dev->evport_offset);
ev = inb_p(dev->cur_ioport->io1.minimum);
if (dev->cur_ioport->io2.minimum)
data_mask = inb_p(dev->cur_ioport->io2.minimum);
else
data_mask = inb_p(dev->cur_ioport->io1.minimum + dev->evport_offset);
dprintk("event ([%.2x] [%.2x]) at port 0x%.4x(+0x%.2x)\n",
ev, data_mask, dev->cur_ioport->io.minimum, dev->evport_offset);
ev, data_mask, dev->cur_ioport->io1.minimum, dev->evport_offset);
if (ev == 0x00 || ev == 0xff)
return IRQ_HANDLED;
@ -2323,8 +2387,11 @@ static int sony_pic_remove(struct acpi_device *device, int type)
}
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);
release_region(spic_dev.cur_ioport->io1.minimum,
spic_dev.cur_ioport->io1.address_length);
if (spic_dev.cur_ioport->io2.minimum)
release_region(spic_dev.cur_ioport->io2.minimum,
spic_dev.cur_ioport->io2.address_length);
sonypi_compat_exit();
@ -2397,14 +2464,36 @@ static int sony_pic_add(struct acpi_device *device)
goto err_remove_input;
/* request io port */
list_for_each_entry(io, &spic_dev.ioports, list) {
if (request_region(io->io.minimum, io->io.address_length,
list_for_each_entry_reverse(io, &spic_dev.ioports, list) {
if (request_region(io->io1.minimum, io->io1.address_length,
"Sony Programable I/O Device")) {
dprintk("I/O port: 0x%.4x (0x%.4x) + 0x%.2x\n",
io->io.minimum, io->io.maximum,
io->io.address_length);
spic_dev.cur_ioport = io;
break;
dprintk("I/O port1: 0x%.4x (0x%.4x) + 0x%.2x\n",
io->io1.minimum, io->io1.maximum,
io->io1.address_length);
/* Type 1 have 2 ioports */
if (io->io2.minimum) {
if (request_region(io->io2.minimum,
io->io2.address_length,
"Sony Programable I/O Device")) {
dprintk("I/O port2: 0x%.4x (0x%.4x) + 0x%.2x\n",
io->io2.minimum, io->io2.maximum,
io->io2.address_length);
spic_dev.cur_ioport = io;
break;
}
else {
dprintk("Unable to get I/O port2: "
"0x%.4x (0x%.4x) + 0x%.2x\n",
io->io2.minimum, io->io2.maximum,
io->io2.address_length);
release_region(io->io1.minimum,
io->io1.address_length);
}
}
else {
spic_dev.cur_ioport = io;
break;
}
}
}
if (!spic_dev.cur_ioport) {
@ -2414,7 +2503,7 @@ static int sony_pic_add(struct acpi_device *device)
}
/* request IRQ */
list_for_each_entry(irq, &spic_dev.interrupts, list) {
list_for_each_entry_reverse(irq, &spic_dev.interrupts, list) {
if (!request_irq(irq->irq.interrupts[0], sony_pic_irq,
IRQF_SHARED, "sony-laptop", &spic_dev)) {
dprintk("IRQ: %d - triggering: %d - "
@ -2462,8 +2551,11 @@ 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);
release_region(spic_dev.cur_ioport->io1.minimum,
spic_dev.cur_ioport->io1.address_length);
if (spic_dev.cur_ioport->io2.minimum)
release_region(spic_dev.cur_ioport->io2.minimum,
spic_dev.cur_ioport->io2.address_length);
err_remove_compat:
sonypi_compat_exit();