diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/pcmcia/cs_internal.h | 4 | ||||
-rw-r--r-- | drivers/pcmcia/ds.c | 17 | ||||
-rw-r--r-- | drivers/pcmcia/pcmcia_resource.c | 141 |
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 | 63 | static int alloc_io_space(struct pcmcia_socket *s, struct resource *res, | |
64 | static 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 | ||
89 | static void release_io_space(struct pcmcia_socket *s, unsigned int base, | 102 | static 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 | */ |
332 | static int pcmcia_release_io(struct pcmcia_device *p_dev, io_req_t *req) | 349 | static 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 | ||
358 | out: | 369 | out: |
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, | |||
526 | EXPORT_SYMBOL(pcmcia_request_configuration); | 537 | EXPORT_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 | */ |
534 | int pcmcia_request_io(struct pcmcia_device *p_dev, io_req_t *req) | 550 | int 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]); | ||
593 | out: | 608 | out: |
594 | mutex_unlock(&s->ops_mutex); | 609 | mutex_unlock(&s->ops_mutex); |
595 | 610 | ||
@@ -869,7 +884,7 @@ EXPORT_SYMBOL(pcmcia_request_window); | |||
869 | void pcmcia_disable_device(struct pcmcia_device *p_dev) | 884 | void 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; |