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