Skip to content

Commit

Permalink
sony-laptop: old Vaio models contain 2 IO port entries
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Mattia Dongili authored and Len Brown committed Aug 24, 2007
1 parent 015a916 commit fd1caae
Showing 1 changed file with 148 additions and 56 deletions.
204 changes: 148 additions & 56 deletions drivers/misc/sony-laptop.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};

Expand Down Expand Up @@ -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;
}
Expand All @@ -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;
}
Expand All @@ -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;
}
Expand Down Expand Up @@ -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:
Expand All @@ -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;
Expand All @@ -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:
Expand Down Expand Up @@ -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 };

Expand All @@ -2217,29 +2250,57 @@ 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");
status = acpi_set_current_resources(device->handle, &buffer);

/* 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;
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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();

Expand Down Expand Up @@ -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) {
Expand All @@ -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 - "
Expand Down Expand Up @@ -2462,8 +2551,11 @@ static int sony_pic_add(struct acpi_device *device)
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();
Expand Down

0 comments on commit fd1caae

Please sign in to comment.