|
@@ -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();
|