aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorDominik Brodowski <linux@dominikbrodowski.net>2010-07-24 07:14:44 -0400
committerDominik Brodowski <linux@dominikbrodowski.net>2010-08-03 03:02:44 -0400
commit2ce4905e4da9f512b38f56a53ece9da2072dd164 (patch)
tree64ca3ecc0dea9b4fbdca2c9b1353ee282e9afc82 /drivers
parent3dace8cf15ae1dd7c9384758b3a29556b441a90a (diff)
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 cebd40da8b9b..a85558fc71f3 100644
--- a/drivers/pcmcia/cs_internal.h
+++ b/drivers/pcmcia/cs_internal.h
@@ -35,7 +35,9 @@ typedef struct config_t {
35 unsigned int ConfigBase; 35 unsigned int ConfigBase;
36 unsigned char Status, Pin, Copy, Option, ExtStatus; 36 unsigned char Status, Pin, Copy, Option, ExtStatus;
37 unsigned int CardValues; 37 unsigned int CardValues;
38 io_req_t io; 38
39 struct resource io[MAX_IO_WIN]; /* io ports */
40
39 struct { 41 struct {
40 u_int Attributes; 42 u_int Attributes;
41 } irq; 43 } irq;
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
index bacfc55f2026..7ddd19a4033d 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,
531 list_for_each_entry(tmp_dev, &s->devices_list, socket_device_list) 531 list_for_each_entry(tmp_dev, &s->devices_list, socket_device_list)
532 if (p_dev->func == tmp_dev->func) { 532 if (p_dev->func == tmp_dev->func) {
533 p_dev->function_config = tmp_dev->function_config; 533 p_dev->function_config = tmp_dev->function_config;
534 p_dev->io = tmp_dev->io;
535 p_dev->irq = tmp_dev->irq; 534 p_dev->irq = tmp_dev->irq;
536 kref_get(&p_dev->function_config->ref); 535 kref_get(&p_dev->function_config->ref);
537 } 536 }
@@ -544,15 +543,23 @@ static struct pcmcia_device *pcmcia_device_add(struct pcmcia_socket *s,
544 "IRQ setup failed -- device might not work\n"); 543 "IRQ setup failed -- device might not work\n");
545 544
546 if (!p_dev->function_config) { 545 if (!p_dev->function_config) {
546 config_t *c;
547 dev_dbg(&p_dev->dev, "creating config_t\n"); 547 dev_dbg(&p_dev->dev, "creating config_t\n");
548 p_dev->function_config = kzalloc(sizeof(struct config_t), 548 c = kzalloc(sizeof(struct config_t), GFP_KERNEL);
549 GFP_KERNEL); 549 if (!c) {
550 if (!p_dev->function_config) {
551 mutex_unlock(&s->ops_mutex); 550 mutex_unlock(&s->ops_mutex);
552 goto err_unreg; 551 goto err_unreg;
553 } 552 }
554 kref_init(&p_dev->function_config->ref); 553 p_dev->function_config = c;
554 kref_init(&c->ref);
555 for (i = 0; i < MAX_IO_WIN; i++) {
556 c->io[i].name = dev_name(&p_dev->dev);
557 c->io[i].flags = IORESOURCE_IO;
558 }
555 } 559 }
560 for (i = 0; i < MAX_IO_WIN; i++)
561 p_dev->resource[i] = &p_dev->function_config->io[i];
562
556 mutex_unlock(&s->ops_mutex); 563 mutex_unlock(&s->ops_mutex);
557 564
558 dev_printk(KERN_NOTICE, &p_dev->dev, 565 dev_printk(KERN_NOTICE, &p_dev->dev,
diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c
index 563750e77eaf..fcd48dae79bc 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,
60 * 60 *
61 * Special stuff for managing IO windows, because they are scarce 61 * Special stuff for managing IO windows, because they are scarce
62 */ 62 */
63 63static int alloc_io_space(struct pcmcia_socket *s, struct resource *res,
64static int alloc_io_space(struct pcmcia_socket *s, u_int attr, 64 unsigned int lines)
65 unsigned int *base, unsigned int num, u_int lines)
66{ 65{
67 unsigned int align; 66 unsigned int align;
67 unsigned int base = res->start;
68 unsigned int num = res->end;
69 int ret;
70
71 res->flags |= IORESOURCE_IO;
68 72
69 align = (*base) ? (lines ? 1<<lines : 0) : 1; 73 dev_dbg(&s->dev, "alloc_io_space request for %pR\n", res);
74
75 align = base ? (lines ? 1<<lines : 0) : 1;
70 if (align && (align < num)) { 76 if (align && (align < num)) {
71 if (*base) { 77 if (base) {
72 dev_dbg(&s->dev, "odd IO request: num %#x align %#x\n", 78 dev_dbg(&s->dev, "odd IO request\n");
73 num, align);
74 align = 0; 79 align = 0;
75 } else 80 } else
76 while (align && (align < num)) 81 while (align && (align < num))
77 align <<= 1; 82 align <<= 1;
78 } 83 }
79 if (*base & ~(align-1)) { 84 if (base & ~(align-1)) {
80 dev_dbg(&s->dev, "odd IO request: base %#x align %#x\n", 85 dev_dbg(&s->dev, "odd IO request\n");
81 *base, align);
82 align = 0; 86 align = 0;
83 } 87 }
84 88
85 return s->resource_ops->find_io(s, attr, base, num, align); 89 ret = s->resource_ops->find_io(s, res->flags, &base, num, align);
90 if (ret) {
91 dev_dbg(&s->dev, "alloc_io_space request returned %d", ret);
92 return -EINVAL;
93 }
94
95 res->start = base;
96 res->end = res->start + num - 1;
97 dev_dbg(&s->dev, "alloc_io_space request returned %pR, %d\n", res, ret);
98 return 0;
86} /* alloc_io_space */ 99} /* alloc_io_space */
87 100
88 101
89static void release_io_space(struct pcmcia_socket *s, unsigned int base, 102static void release_io_space(struct pcmcia_socket *s, struct resource *res)
90 unsigned int num)
91{ 103{
104 resource_size_t num = resource_size(res);
92 int i; 105 int i;
93 106
107 dev_dbg(&s->dev, "release_io_space for %pR\n", res);
108
94 for (i = 0; i < MAX_IO_WIN; i++) { 109 for (i = 0; i < MAX_IO_WIN; i++) {
95 if (!s->io[i].res) 110 if (!s->io[i].res)
96 continue; 111 continue;
97 if ((s->io[i].res->start <= base) && 112 if ((s->io[i].res->start <= res->start) &&
98 (s->io[i].res->end >= base+num-1)) { 113 (s->io[i].res->end >= res->end)) {
99 s->io[i].InUse -= num; 114 s->io[i].InUse -= num;
115 res->start = res->end = 0;
116 res->flags = IORESOURCE_IO;
100 /* Free the window if no one else is using it */ 117 /* Free the window if no one else is using it */
101 if (s->io[i].InUse == 0) { 118 if (s->io[i].InUse == 0) {
102 release_resource(s->io[i].res); 119 release_resource(s->io[i].res);
@@ -329,31 +346,25 @@ int pcmcia_release_configuration(struct pcmcia_device *p_dev)
329 * don't bother checking the port ranges against the current socket 346 * don't bother checking the port ranges against the current socket
330 * values. 347 * values.
331 */ 348 */
332static int pcmcia_release_io(struct pcmcia_device *p_dev, io_req_t *req) 349static int pcmcia_release_io(struct pcmcia_device *p_dev)
333{ 350{
334 struct pcmcia_socket *s = p_dev->socket; 351 struct pcmcia_socket *s = p_dev->socket;
335 int ret = -EINVAL; 352 int ret = -EINVAL;
336 config_t *c; 353 config_t *c;
337 354
338 mutex_lock(&s->ops_mutex); 355 mutex_lock(&s->ops_mutex);
339 c = p_dev->function_config;
340
341 if (!p_dev->_io) 356 if (!p_dev->_io)
342 goto out; 357 goto out;
343 358
344 p_dev->_io = 0; 359 c = p_dev->function_config;
345 360
346 if ((c->io.BasePort1 != req->BasePort1) || 361 release_io_space(s, &c->io[0]);
347 (c->io.NumPorts1 != req->NumPorts1) ||
348 (c->io.BasePort2 != req->BasePort2) ||
349 (c->io.NumPorts2 != req->NumPorts2))
350 goto out;
351 362
352 c->state &= ~CONFIG_IO_REQ; 363 if (c->io[1].end)
364 release_io_space(s, &c->io[1]);
353 365
354 release_io_space(s, req->BasePort1, req->NumPorts1); 366 p_dev->_io = 0;
355 if (req->NumPorts2) 367 c->state &= ~CONFIG_IO_REQ;
356 release_io_space(s, req->BasePort2, req->NumPorts2);
357 368
358out: 369out:
359 mutex_unlock(&s->ops_mutex); 370 mutex_unlock(&s->ops_mutex);
@@ -486,13 +497,13 @@ int pcmcia_request_configuration(struct pcmcia_device *p_dev,
486 pcmcia_write_cis_mem(s, 1, (base + CISREG_ESR)>>1, 1, &c->ExtStatus); 497 pcmcia_write_cis_mem(s, 1, (base + CISREG_ESR)>>1, 1, &c->ExtStatus);
487 } 498 }
488 if (req->Present & PRESENT_IOBASE_0) { 499 if (req->Present & PRESENT_IOBASE_0) {
489 u_char b = c->io.BasePort1 & 0xff; 500 u8 b = c->io[0].start & 0xff;
490 pcmcia_write_cis_mem(s, 1, (base + CISREG_IOBASE_0)>>1, 1, &b); 501 pcmcia_write_cis_mem(s, 1, (base + CISREG_IOBASE_0)>>1, 1, &b);
491 b = (c->io.BasePort1 >> 8) & 0xff; 502 b = (c->io[0].start >> 8) & 0xff;
492 pcmcia_write_cis_mem(s, 1, (base + CISREG_IOBASE_1)>>1, 1, &b); 503 pcmcia_write_cis_mem(s, 1, (base + CISREG_IOBASE_1)>>1, 1, &b);
493 } 504 }
494 if (req->Present & PRESENT_IOSIZE) { 505 if (req->Present & PRESENT_IOSIZE) {
495 u_char b = c->io.NumPorts1 + c->io.NumPorts2 - 1; 506 u8 b = resource_size(&c->io[0]) + resource_size(&c->io[1]) - 1;
496 pcmcia_write_cis_mem(s, 1, (base + CISREG_IOSIZE)>>1, 1, &b); 507 pcmcia_write_cis_mem(s, 1, (base + CISREG_IOSIZE)>>1, 1, &b);
497 } 508 }
498 509
@@ -526,28 +537,42 @@ int pcmcia_request_configuration(struct pcmcia_device *p_dev,
526EXPORT_SYMBOL(pcmcia_request_configuration); 537EXPORT_SYMBOL(pcmcia_request_configuration);
527 538
528 539
529/** pcmcia_request_io 540/**
541 * pcmcia_request_io() - attempt to reserve port ranges for PCMCIA devices
542 *
543 * pcmcia_request_io() attepts to reserve the IO port ranges specified in
544 * struct pcmcia_device *p_dev->resource[0] and *p_dev->resource[1]. The
545 * "start" value is the requested start of the IO port resource; "end"
546 * relfects the number of ports requested.
530 * 547 *
531 * Request_io() reserves ranges of port addresses for a socket. 548 * If io_req_t is passed, those values are converted automatically.
532 * I have not implemented range sharing or alias addressing.
533 */ 549 */
534int pcmcia_request_io(struct pcmcia_device *p_dev, io_req_t *req) 550int pcmcia_request_io(struct pcmcia_device *p_dev, io_req_t *req)
535{ 551{
536 struct pcmcia_socket *s = p_dev->socket; 552 struct pcmcia_socket *s = p_dev->socket;
537 config_t *c; 553 config_t *c;
538 int ret = -EINVAL; 554 int ret = -EINVAL;
555 unsigned int lines = req->IOAddrLines;
539 556
540 mutex_lock(&s->ops_mutex); 557 mutex_lock(&s->ops_mutex);
541 558
542 if (!(s->state & SOCKET_PRESENT)) { 559 if (!(s->state & SOCKET_PRESENT)) {
543 dev_dbg(&s->dev, "No card present\n"); 560 dev_dbg(&s->dev, "pcmcia_request_io: No card present\n");
544 goto out; 561 goto out;
545 } 562 }
546 563
547 if (!req)
548 goto out;
549
550 c = p_dev->function_config; 564 c = p_dev->function_config;
565 if (req) {
566 c->io[0].start = req->BasePort1;
567 c->io[0].end = req->NumPorts1;
568 c->io[0].flags |= req->Attributes1;
569 c->io[1].start = req->BasePort2;
570 c->io[1].end = req->NumPorts2;
571 c->io[1].flags |= req->Attributes2;
572 }
573
574 dev_dbg(&s->dev, "pcmcia_request_io: %pR , %pR", &c->io[0], &c->io[1]);
575
551 if (c->state & CONFIG_LOCKED) { 576 if (c->state & CONFIG_LOCKED) {
552 dev_dbg(&s->dev, "Configuration is locked\n"); 577 dev_dbg(&s->dev, "Configuration is locked\n");
553 goto out; 578 goto out;
@@ -556,40 +581,30 @@ int pcmcia_request_io(struct pcmcia_device *p_dev, io_req_t *req)
556 dev_dbg(&s->dev, "IO already configured\n"); 581 dev_dbg(&s->dev, "IO already configured\n");
557 goto out; 582 goto out;
558 } 583 }
559 if (req->Attributes1 & (IO_SHARED | IO_FORCE_ALIAS_ACCESS)) {
560 dev_dbg(&s->dev, "bad attribute setting for IO region 1\n");
561 goto out;
562 }
563 if ((req->NumPorts2 > 0) &&
564 (req->Attributes2 & (IO_SHARED | IO_FORCE_ALIAS_ACCESS))) {
565 dev_dbg(&s->dev, "bad attribute setting for IO region 2\n");
566 goto out;
567 }
568 584
569 dev_dbg(&s->dev, "trying to allocate resource 1\n"); 585 ret = alloc_io_space(s, &c->io[0], lines);
570 ret = alloc_io_space(s, req->Attributes1, &req->BasePort1, 586 if (ret)
571 req->NumPorts1, req->IOAddrLines);
572 if (ret) {
573 dev_dbg(&s->dev, "allocation of resource 1 failed\n");
574 goto out; 587 goto out;
575 }
576 588
577 if (req->NumPorts2) { 589 if (c->io[1].end) {
578 dev_dbg(&s->dev, "trying to allocate resource 2\n"); 590 ret = alloc_io_space(s, &c->io[1], lines);
579 ret = alloc_io_space(s, req->Attributes2, &req->BasePort2,
580 req->NumPorts2, req->IOAddrLines);
581 if (ret) { 591 if (ret) {
582 dev_dbg(&s->dev, "allocation of resource 2 failed\n"); 592 release_io_space(s, &c->io[0]);
583 release_io_space(s, req->BasePort1, req->NumPorts1);
584 goto out; 593 goto out;
585 } 594 }
586 } 595 } else
596 c->io[1].start = 0;
587 597
588 c->io = *req;
589 c->state |= CONFIG_IO_REQ; 598 c->state |= CONFIG_IO_REQ;
590 p_dev->_io = 1; 599 p_dev->_io = 1;
591 dev_dbg(&s->dev, "allocating resources succeeded: %d\n", ret);
592 600
601 if (!ret) {
602 req->BasePort1 = c->io[0].start;
603 req->BasePort2 = c->io[1].start;
604 }
605
606 dev_dbg(&s->dev, "pcmcia_request_io succeeded: %pR , %pR",
607 &c->io[0], &c->io[1]);
593out: 608out:
594 mutex_unlock(&s->ops_mutex); 609 mutex_unlock(&s->ops_mutex);
595 610
@@ -869,7 +884,7 @@ EXPORT_SYMBOL(pcmcia_request_window);
869void pcmcia_disable_device(struct pcmcia_device *p_dev) 884void pcmcia_disable_device(struct pcmcia_device *p_dev)
870{ 885{
871 pcmcia_release_configuration(p_dev); 886 pcmcia_release_configuration(p_dev);
872 pcmcia_release_io(p_dev, &p_dev->io); 887 pcmcia_release_io(p_dev);
873 if (p_dev->_irq) { 888 if (p_dev->_irq) {
874 free_irq(p_dev->irq, p_dev->priv); 889 free_irq(p_dev->irq, p_dev->priv);
875 p_dev->_irq = 0; 890 p_dev->_irq = 0;