summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorDominik Brodowski <linux@dominikbrodowski.net>2010-07-24 13:14:44 +0200
committerDominik Brodowski <linux@dominikbrodowski.net>2010-08-03 09:02:44 +0200
commit2ce4905e4da9f512b38f56a53ece9da2072dd164 (patch)
tree64ca3ecc0dea9b4fbdca2c9b1353ee282e9afc82 /drivers
parent3dace8cf15ae1dd7c9384758b3a29556b441a90a (diff)
downloadop-kernel-dev-2ce4905e4da9f512b38f56a53ece9da2072dd164.zip
op-kernel-dev-2ce4905e4da9f512b38f56a53ece9da2072dd164.tar.gz
pcmcia: use struct resource for PCMCIA devices
Introduce a new field into struct pcmcia_device named "resource" and of type struct resource *, which contains the IO port ranges allocated for this device. Memory window ranges and registration with the resource trees will follow at a later date. Signed-off-by: Dominik Brodowski <linux@dominikbrodowski.net>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/pcmcia/cs_internal.h4
-rw-r--r--drivers/pcmcia/ds.c17
-rw-r--r--drivers/pcmcia/pcmcia_resource.c141
3 files changed, 93 insertions, 69 deletions
diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h
index cebd40d..a85558f 100644
--- a/drivers/pcmcia/cs_internal.h
+++ b/drivers/pcmcia/cs_internal.h
@@ -35,7 +35,9 @@ typedef struct config_t {
unsigned int ConfigBase;
unsigned char Status, Pin, Copy, Option, ExtStatus;
unsigned int CardValues;
- io_req_t io;
+
+ struct resource io[MAX_IO_WIN]; /* io ports */
+
struct {
u_int Attributes;
} irq;
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
index bacfc55..7ddd19a 100644
--- a/drivers/pcmcia/ds.c
+++ b/drivers/pcmcia/ds.c
@@ -531,7 +531,6 @@ static struct pcmcia_device *pcmcia_device_add(struct pcmcia_socket *s,
list_for_each_entry(tmp_dev, &s->devices_list, socket_device_list)
if (p_dev->func == tmp_dev->func) {
p_dev->function_config = tmp_dev->function_config;
- p_dev->io = tmp_dev->io;
p_dev->irq = tmp_dev->irq;
kref_get(&p_dev->function_config->ref);
}
@@ -544,15 +543,23 @@ static struct pcmcia_device *pcmcia_device_add(struct pcmcia_socket *s,
"IRQ setup failed -- device might not work\n");
if (!p_dev->function_config) {
+ config_t *c;
dev_dbg(&p_dev->dev, "creating config_t\n");
- p_dev->function_config = kzalloc(sizeof(struct config_t),
- GFP_KERNEL);
- if (!p_dev->function_config) {
+ c = kzalloc(sizeof(struct config_t), GFP_KERNEL);
+ if (!c) {
mutex_unlock(&s->ops_mutex);
goto err_unreg;
}
- kref_init(&p_dev->function_config->ref);
+ p_dev->function_config = c;
+ kref_init(&c->ref);
+ for (i = 0; i < MAX_IO_WIN; i++) {
+ c->io[i].name = dev_name(&p_dev->dev);
+ c->io[i].flags = IORESOURCE_IO;
+ }
}
+ for (i = 0; i < MAX_IO_WIN; i++)
+ p_dev->resource[i] = &p_dev->function_config->io[i];
+
mutex_unlock(&s->ops_mutex);
dev_printk(KERN_NOTICE, &p_dev->dev,
diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c
index 563750e..fcd48da 100644
--- a/drivers/pcmcia/pcmcia_resource.c
+++ b/drivers/pcmcia/pcmcia_resource.c
@@ -60,43 +60,60 @@ struct resource *pcmcia_find_mem_region(u_long base, u_long num, u_long align,
*
* Special stuff for managing IO windows, because they are scarce
*/
-
-static int alloc_io_space(struct pcmcia_socket *s, u_int attr,
- unsigned int *base, unsigned int num, u_int lines)
+static int alloc_io_space(struct pcmcia_socket *s, struct resource *res,
+ unsigned int lines)
{
unsigned int align;
+ unsigned int base = res->start;
+ unsigned int num = res->end;
+ int ret;
+
+ res->flags |= IORESOURCE_IO;
- align = (*base) ? (lines ? 1<<lines : 0) : 1;
+ dev_dbg(&s->dev, "alloc_io_space request for %pR\n", res);
+
+ align = base ? (lines ? 1<<lines : 0) : 1;
if (align && (align < num)) {
- if (*base) {
- dev_dbg(&s->dev, "odd IO request: num %#x align %#x\n",
- num, align);
+ if (base) {
+ dev_dbg(&s->dev, "odd IO request\n");
align = 0;
} else
while (align && (align < num))
align <<= 1;
}
- if (*base & ~(align-1)) {
- dev_dbg(&s->dev, "odd IO request: base %#x align %#x\n",
- *base, align);
+ if (base & ~(align-1)) {
+ dev_dbg(&s->dev, "odd IO request\n");
align = 0;
}
- return s->resource_ops->find_io(s, attr, base, num, align);
+ ret = s->resource_ops->find_io(s, res->flags, &base, num, align);
+ if (ret) {
+ dev_dbg(&s->dev, "alloc_io_space request returned %d", ret);
+ return -EINVAL;
+ }
+
+ res->start = base;
+ res->end = res->start + num - 1;
+ dev_dbg(&s->dev, "alloc_io_space request returned %pR, %d\n", res, ret);
+ return 0;
} /* alloc_io_space */
-static void release_io_space(struct pcmcia_socket *s, unsigned int base,
- unsigned int num)
+static void release_io_space(struct pcmcia_socket *s, struct resource *res)
{
+ resource_size_t num = resource_size(res);
int i;
+ dev_dbg(&s->dev, "release_io_space for %pR\n", res);
+
for (i = 0; i < MAX_IO_WIN; i++) {
if (!s->io[i].res)
continue;
- if ((s->io[i].res->start <= base) &&
- (s->io[i].res->end >= base+num-1)) {
+ if ((s->io[i].res->start <= res->start) &&
+ (s->io[i].res->end >= res->end)) {
s->io[i].InUse -= num;
+ res->start = res->end = 0;
+ res->flags = IORESOURCE_IO;
/* Free the window if no one else is using it */
if (s->io[i].InUse == 0) {
release_resource(s->io[i].res);
@@ -329,31 +346,25 @@ int pcmcia_release_configuration(struct pcmcia_device *p_dev)
* don't bother checking the port ranges against the current socket
* values.
*/
-static int pcmcia_release_io(struct pcmcia_device *p_dev, io_req_t *req)
+static int pcmcia_release_io(struct pcmcia_device *p_dev)
{
struct pcmcia_socket *s = p_dev->socket;
int ret = -EINVAL;
config_t *c;
mutex_lock(&s->ops_mutex);
- c = p_dev->function_config;
-
if (!p_dev->_io)
goto out;
- p_dev->_io = 0;
+ c = p_dev->function_config;
- if ((c->io.BasePort1 != req->BasePort1) ||
- (c->io.NumPorts1 != req->NumPorts1) ||
- (c->io.BasePort2 != req->BasePort2) ||
- (c->io.NumPorts2 != req->NumPorts2))
- goto out;
+ release_io_space(s, &c->io[0]);
- c->state &= ~CONFIG_IO_REQ;
+ if (c->io[1].end)
+ release_io_space(s, &c->io[1]);
- release_io_space(s, req->BasePort1, req->NumPorts1);
- if (req->NumPorts2)
- release_io_space(s, req->BasePort2, req->NumPorts2);
+ p_dev->_io = 0;
+ c->state &= ~CONFIG_IO_REQ;
out:
mutex_unlock(&s->ops_mutex);
@@ -486,13 +497,13 @@ int pcmcia_request_configuration(struct pcmcia_device *p_dev,
pcmcia_write_cis_mem(s, 1, (base + CISREG_ESR)>>1, 1, &c->ExtStatus);
}
if (req->Present & PRESENT_IOBASE_0) {
- u_char b = c->io.BasePort1 & 0xff;
+ u8 b = c->io[0].start & 0xff;
pcmcia_write_cis_mem(s, 1, (base + CISREG_IOBASE_0)>>1, 1, &b);
- b = (c->io.BasePort1 >> 8) & 0xff;
+ b = (c->io[0].start >> 8) & 0xff;
pcmcia_write_cis_mem(s, 1, (base + CISREG_IOBASE_1)>>1, 1, &b);
}
if (req->Present & PRESENT_IOSIZE) {
- u_char b = c->io.NumPorts1 + c->io.NumPorts2 - 1;
+ u8 b = resource_size(&c->io[0]) + resource_size(&c->io[1]) - 1;
pcmcia_write_cis_mem(s, 1, (base + CISREG_IOSIZE)>>1, 1, &b);
}
@@ -526,28 +537,42 @@ int pcmcia_request_configuration(struct pcmcia_device *p_dev,
EXPORT_SYMBOL(pcmcia_request_configuration);
-/** pcmcia_request_io
+/**
+ * pcmcia_request_io() - attempt to reserve port ranges for PCMCIA devices
+ *
+ * pcmcia_request_io() attepts to reserve the IO port ranges specified in
+ * struct pcmcia_device *p_dev->resource[0] and *p_dev->resource[1]. The
+ * "start" value is the requested start of the IO port resource; "end"
+ * relfects the number of ports requested.
*
- * Request_io() reserves ranges of port addresses for a socket.
- * I have not implemented range sharing or alias addressing.
+ * If io_req_t is passed, those values are converted automatically.
*/
int pcmcia_request_io(struct pcmcia_device *p_dev, io_req_t *req)
{
struct pcmcia_socket *s = p_dev->socket;
config_t *c;
int ret = -EINVAL;
+ unsigned int lines = req->IOAddrLines;
mutex_lock(&s->ops_mutex);
if (!(s->state & SOCKET_PRESENT)) {
- dev_dbg(&s->dev, "No card present\n");
+ dev_dbg(&s->dev, "pcmcia_request_io: No card present\n");
goto out;
}
- if (!req)
- goto out;
-
c = p_dev->function_config;
+ if (req) {
+ c->io[0].start = req->BasePort1;
+ c->io[0].end = req->NumPorts1;
+ c->io[0].flags |= req->Attributes1;
+ c->io[1].start = req->BasePort2;
+ c->io[1].end = req->NumPorts2;
+ c->io[1].flags |= req->Attributes2;
+ }
+
+ dev_dbg(&s->dev, "pcmcia_request_io: %pR , %pR", &c->io[0], &c->io[1]);
+
if (c->state & CONFIG_LOCKED) {
dev_dbg(&s->dev, "Configuration is locked\n");
goto out;
@@ -556,40 +581,30 @@ int pcmcia_request_io(struct pcmcia_device *p_dev, io_req_t *req)
dev_dbg(&s->dev, "IO already configured\n");
goto out;
}
- if (req->Attributes1 & (IO_SHARED | IO_FORCE_ALIAS_ACCESS)) {
- dev_dbg(&s->dev, "bad attribute setting for IO region 1\n");
- goto out;
- }
- if ((req->NumPorts2 > 0) &&
- (req->Attributes2 & (IO_SHARED | IO_FORCE_ALIAS_ACCESS))) {
- dev_dbg(&s->dev, "bad attribute setting for IO region 2\n");
- goto out;
- }
- dev_dbg(&s->dev, "trying to allocate resource 1\n");
- ret = alloc_io_space(s, req->Attributes1, &req->BasePort1,
- req->NumPorts1, req->IOAddrLines);
- if (ret) {
- dev_dbg(&s->dev, "allocation of resource 1 failed\n");
+ ret = alloc_io_space(s, &c->io[0], lines);
+ if (ret)
goto out;
- }
- if (req->NumPorts2) {
- dev_dbg(&s->dev, "trying to allocate resource 2\n");
- ret = alloc_io_space(s, req->Attributes2, &req->BasePort2,
- req->NumPorts2, req->IOAddrLines);
+ if (c->io[1].end) {
+ ret = alloc_io_space(s, &c->io[1], lines);
if (ret) {
- dev_dbg(&s->dev, "allocation of resource 2 failed\n");
- release_io_space(s, req->BasePort1, req->NumPorts1);
+ release_io_space(s, &c->io[0]);
goto out;
}
- }
+ } else
+ c->io[1].start = 0;
- c->io = *req;
c->state |= CONFIG_IO_REQ;
p_dev->_io = 1;
- dev_dbg(&s->dev, "allocating resources succeeded: %d\n", ret);
+ if (!ret) {
+ req->BasePort1 = c->io[0].start;
+ req->BasePort2 = c->io[1].start;
+ }
+
+ dev_dbg(&s->dev, "pcmcia_request_io succeeded: %pR , %pR",
+ &c->io[0], &c->io[1]);
out:
mutex_unlock(&s->ops_mutex);
@@ -869,7 +884,7 @@ EXPORT_SYMBOL(pcmcia_request_window);
void pcmcia_disable_device(struct pcmcia_device *p_dev)
{
pcmcia_release_configuration(p_dev);
- pcmcia_release_io(p_dev, &p_dev->io);
+ pcmcia_release_io(p_dev);
if (p_dev->_irq) {
free_irq(p_dev->irq, p_dev->priv);
p_dev->_irq = 0;
OpenPOWER on IntegriCloud