diff options
Diffstat (limited to 'drivers/pcmcia/pcmcia_resource.c')
| -rw-r--r-- | drivers/pcmcia/pcmcia_resource.c | 74 |
1 files changed, 46 insertions, 28 deletions
diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c index 01f8e56c8d2f..d48437f83acf 100644 --- a/drivers/pcmcia/pcmcia_resource.c +++ b/drivers/pcmcia/pcmcia_resource.c | |||
| @@ -56,6 +56,33 @@ struct resource *pcmcia_find_mem_region(u_long base, u_long num, u_long align, | |||
| 56 | } | 56 | } |
| 57 | 57 | ||
| 58 | 58 | ||
| 59 | static void release_io_space(struct pcmcia_socket *s, struct resource *res) | ||
| 60 | { | ||
| 61 | resource_size_t num = resource_size(res); | ||
| 62 | int i; | ||
| 63 | |||
| 64 | dev_dbg(&s->dev, "release_io_space for %pR\n", res); | ||
| 65 | |||
| 66 | for (i = 0; i < MAX_IO_WIN; i++) { | ||
| 67 | if (!s->io[i].res) | ||
| 68 | continue; | ||
| 69 | if ((s->io[i].res->start <= res->start) && | ||
| 70 | (s->io[i].res->end >= res->end)) { | ||
| 71 | s->io[i].InUse -= num; | ||
| 72 | if (res->parent) | ||
| 73 | release_resource(res); | ||
| 74 | res->start = res->end = 0; | ||
| 75 | res->flags = IORESOURCE_IO; | ||
| 76 | /* Free the window if no one else is using it */ | ||
| 77 | if (s->io[i].InUse == 0) { | ||
| 78 | release_resource(s->io[i].res); | ||
| 79 | kfree(s->io[i].res); | ||
| 80 | s->io[i].res = NULL; | ||
| 81 | } | ||
| 82 | } | ||
| 83 | } | ||
| 84 | } /* release_io_space */ | ||
| 85 | |||
| 59 | /** alloc_io_space | 86 | /** alloc_io_space |
| 60 | * | 87 | * |
| 61 | * Special stuff for managing IO windows, because they are scarce | 88 | * Special stuff for managing IO windows, because they are scarce |
| @@ -87,43 +114,28 @@ static int alloc_io_space(struct pcmcia_socket *s, struct resource *res, | |||
| 87 | align = 0; | 114 | align = 0; |
| 88 | } | 115 | } |
| 89 | 116 | ||
| 90 | ret = s->resource_ops->find_io(s, res->flags, &base, num, align); | 117 | ret = s->resource_ops->find_io(s, res->flags, &base, num, align, |
| 118 | &res->parent); | ||
| 91 | if (ret) { | 119 | if (ret) { |
| 92 | dev_dbg(&s->dev, "alloc_io_space request returned %d", ret); | 120 | dev_dbg(&s->dev, "alloc_io_space request failed (%d)\n", ret); |
| 93 | return -EINVAL; | 121 | return -EINVAL; |
| 94 | } | 122 | } |
| 95 | 123 | ||
| 96 | res->start = base; | 124 | res->start = base; |
| 97 | res->end = res->start + num - 1; | 125 | res->end = res->start + num - 1; |
| 98 | dev_dbg(&s->dev, "alloc_io_space request returned %pR, %d\n", res, ret); | ||
| 99 | return 0; | ||
| 100 | } /* alloc_io_space */ | ||
| 101 | 126 | ||
| 102 | 127 | if (res->parent) { | |
| 103 | static void release_io_space(struct pcmcia_socket *s, struct resource *res) | 128 | ret = request_resource(res->parent, res); |
| 104 | { | 129 | if (ret) { |
| 105 | resource_size_t num = resource_size(res); | 130 | dev_warn(&s->dev, |
| 106 | int i; | 131 | "request_resource %pR failed: %d\n", res, ret); |
| 107 | 132 | res->parent = NULL; | |
| 108 | dev_dbg(&s->dev, "release_io_space for %pR\n", res); | 133 | release_io_space(s, res); |
| 109 | |||
| 110 | for (i = 0; i < MAX_IO_WIN; i++) { | ||
| 111 | if (!s->io[i].res) | ||
| 112 | continue; | ||
| 113 | if ((s->io[i].res->start <= res->start) && | ||
| 114 | (s->io[i].res->end >= res->end)) { | ||
| 115 | s->io[i].InUse -= num; | ||
| 116 | res->start = res->end = 0; | ||
| 117 | res->flags = IORESOURCE_IO; | ||
| 118 | /* Free the window if no one else is using it */ | ||
| 119 | if (s->io[i].InUse == 0) { | ||
| 120 | release_resource(s->io[i].res); | ||
| 121 | kfree(s->io[i].res); | ||
| 122 | s->io[i].res = NULL; | ||
| 123 | } | ||
| 124 | } | 134 | } |
| 125 | } | 135 | } |
| 126 | } /* release_io_space */ | 136 | dev_dbg(&s->dev, "alloc_io_space request result %d: %pR\n", ret, res); |
| 137 | return ret; | ||
| 138 | } /* alloc_io_space */ | ||
| 127 | 139 | ||
| 128 | 140 | ||
| 129 | /** | 141 | /** |
| @@ -401,6 +413,7 @@ int pcmcia_release_window(struct pcmcia_device *p_dev, struct resource *res) | |||
| 401 | 413 | ||
| 402 | /* Release system memory */ | 414 | /* Release system memory */ |
| 403 | if (win->res) { | 415 | if (win->res) { |
| 416 | release_resource(res); | ||
| 404 | release_resource(win->res); | 417 | release_resource(win->res); |
| 405 | kfree(win->res); | 418 | kfree(win->res); |
| 406 | win->res = NULL; | 419 | win->res = NULL; |
| @@ -853,6 +866,11 @@ int pcmcia_request_window(struct pcmcia_device *p_dev, win_req_t *req, window_ha | |||
| 853 | res->end = req->Base + req->Size - 1; | 866 | res->end = req->Base + req->Size - 1; |
| 854 | res->flags &= ~IORESOURCE_BITS; | 867 | res->flags &= ~IORESOURCE_BITS; |
| 855 | res->flags |= (req->Attributes & WIN_FLAGS_MAP) | (win->map << 2); | 868 | res->flags |= (req->Attributes & WIN_FLAGS_MAP) | (win->map << 2); |
| 869 | res->flags |= IORESOURCE_MEM; | ||
| 870 | res->parent = win->res; | ||
| 871 | if (win->res) | ||
| 872 | request_resource(&iomem_resource, res); | ||
| 873 | |||
| 856 | dev_dbg(&s->dev, "request_window results in %pR\n", res); | 874 | dev_dbg(&s->dev, "request_window results in %pR\n", res); |
| 857 | 875 | ||
| 858 | mutex_unlock(&s->ops_mutex); | 876 | mutex_unlock(&s->ops_mutex); |
