diff options
Diffstat (limited to 'drivers/pcmcia/socket_sysfs.c')
-rw-r--r-- | drivers/pcmcia/socket_sysfs.c | 166 |
1 files changed, 156 insertions, 10 deletions
diff --git a/drivers/pcmcia/socket_sysfs.c b/drivers/pcmcia/socket_sysfs.c index 8eed03938214..fcef54c1c2da 100644 --- a/drivers/pcmcia/socket_sysfs.c +++ b/drivers/pcmcia/socket_sysfs.c | |||
@@ -163,28 +163,164 @@ static ssize_t pccard_store_resource(struct class_device *dev, const char *buf, | |||
163 | return -EINVAL; | 163 | return -EINVAL; |
164 | 164 | ||
165 | spin_lock_irqsave(&s->lock, flags); | 165 | spin_lock_irqsave(&s->lock, flags); |
166 | if (!s->resource_setup_done) { | 166 | if (!s->resource_setup_done) |
167 | s->resource_setup_done = 1; | 167 | s->resource_setup_done = 1; |
168 | spin_unlock_irqrestore(&s->lock, flags); | 168 | spin_unlock_irqrestore(&s->lock, flags); |
169 | |||
170 | down(&s->skt_sem); | ||
171 | if ((s->callback) && | ||
172 | (s->state & SOCKET_PRESENT) && | ||
173 | !(s->state & SOCKET_CARDBUS)) { | ||
174 | if (try_module_get(s->callback->owner)) { | ||
175 | s->callback->requery(s); | ||
176 | module_put(s->callback->owner); | ||
177 | } | ||
178 | } | ||
179 | up(&s->skt_sem); | ||
180 | |||
181 | return count; | ||
182 | } | ||
183 | static CLASS_DEVICE_ATTR(available_resources_setup_done, 0600, pccard_show_resource, pccard_store_resource); | ||
184 | |||
185 | |||
186 | static ssize_t pccard_extract_cis(struct pcmcia_socket *s, char *buf, loff_t off, size_t count) | ||
187 | { | ||
188 | tuple_t tuple; | ||
189 | int status, i; | ||
190 | loff_t pointer = 0; | ||
191 | ssize_t ret = 0; | ||
192 | u_char *tuplebuffer; | ||
193 | u_char *tempbuffer; | ||
194 | |||
195 | tuplebuffer = kmalloc(sizeof(u_char) * 256, GFP_KERNEL); | ||
196 | if (!tuplebuffer) | ||
197 | return -ENOMEM; | ||
198 | |||
199 | tempbuffer = kmalloc(sizeof(u_char) * 258, GFP_KERNEL); | ||
200 | if (!tempbuffer) { | ||
201 | ret = -ENOMEM; | ||
202 | goto free_tuple; | ||
203 | } | ||
204 | |||
205 | memset(&tuple, 0, sizeof(tuple_t)); | ||
206 | |||
207 | tuple.Attributes = TUPLE_RETURN_LINK | TUPLE_RETURN_COMMON; | ||
208 | tuple.DesiredTuple = RETURN_FIRST_TUPLE; | ||
209 | tuple.TupleOffset = 0; | ||
210 | |||
211 | status = pccard_get_first_tuple(s, BIND_FN_ALL, &tuple); | ||
212 | while (!status) { | ||
213 | tuple.TupleData = tuplebuffer; | ||
214 | tuple.TupleDataMax = 255; | ||
215 | memset(tuplebuffer, 0, sizeof(u_char) * 255); | ||
169 | 216 | ||
217 | status = pccard_get_tuple_data(s, &tuple); | ||
218 | if (status) | ||
219 | break; | ||
220 | |||
221 | if (off < (pointer + 2 + tuple.TupleDataLen)) { | ||
222 | tempbuffer[0] = tuple.TupleCode & 0xff; | ||
223 | tempbuffer[1] = tuple.TupleLink & 0xff; | ||
224 | for (i = 0; i < tuple.TupleDataLen; i++) | ||
225 | tempbuffer[i + 2] = tuplebuffer[i] & 0xff; | ||
226 | |||
227 | for (i = 0; i < (2 + tuple.TupleDataLen); i++) { | ||
228 | if (((i + pointer) >= off) && | ||
229 | (i + pointer) < (off + count)) { | ||
230 | buf[ret] = tempbuffer[i]; | ||
231 | ret++; | ||
232 | } | ||
233 | } | ||
234 | } | ||
235 | |||
236 | pointer += 2 + tuple.TupleDataLen; | ||
237 | |||
238 | if (pointer >= (off + count)) | ||
239 | break; | ||
240 | |||
241 | if (tuple.TupleCode == CISTPL_END) | ||
242 | break; | ||
243 | status = pccard_get_next_tuple(s, BIND_FN_ALL, &tuple); | ||
244 | } | ||
245 | |||
246 | kfree(tempbuffer); | ||
247 | free_tuple: | ||
248 | kfree(tuplebuffer); | ||
249 | |||
250 | return (ret); | ||
251 | } | ||
252 | |||
253 | static ssize_t pccard_show_cis(struct kobject *kobj, char *buf, loff_t off, size_t count) | ||
254 | { | ||
255 | unsigned int size = 0x200; | ||
256 | |||
257 | if (off >= size) | ||
258 | count = 0; | ||
259 | else { | ||
260 | struct pcmcia_socket *s; | ||
261 | cisinfo_t cisinfo; | ||
262 | |||
263 | if (off + count > size) | ||
264 | count = size - off; | ||
265 | |||
266 | s = to_socket(container_of(kobj, struct class_device, kobj)); | ||
267 | |||
268 | if (!(s->state & SOCKET_PRESENT)) | ||
269 | return -ENODEV; | ||
270 | if (pccard_validate_cis(s, BIND_FN_ALL, &cisinfo)) | ||
271 | return -EIO; | ||
272 | if (!cisinfo.Chains) | ||
273 | return -ENODATA; | ||
274 | |||
275 | count = pccard_extract_cis(s, buf, off, count); | ||
276 | } | ||
277 | |||
278 | return (count); | ||
279 | } | ||
280 | |||
281 | static ssize_t pccard_store_cis(struct kobject *kobj, char *buf, loff_t off, size_t count) | ||
282 | { | ||
283 | struct pcmcia_socket *s = to_socket(container_of(kobj, struct class_device, kobj)); | ||
284 | cisdump_t *cis; | ||
285 | ssize_t ret = count; | ||
286 | |||
287 | if (off) | ||
288 | return -EINVAL; | ||
289 | |||
290 | if (count >= 0x200) | ||
291 | return -EINVAL; | ||
292 | |||
293 | if (!(s->state & SOCKET_PRESENT)) | ||
294 | return -ENODEV; | ||
295 | |||
296 | cis = kmalloc(sizeof(cisdump_t), GFP_KERNEL); | ||
297 | if (!cis) | ||
298 | return -ENOMEM; | ||
299 | memset(cis, 0, sizeof(cisdump_t)); | ||
300 | |||
301 | cis->Length = count + 1; | ||
302 | memcpy(cis->Data, buf, count); | ||
303 | |||
304 | if (pcmcia_replace_cis(s, cis)) | ||
305 | ret = -EIO; | ||
306 | |||
307 | kfree(cis); | ||
308 | |||
309 | if (!ret) { | ||
170 | down(&s->skt_sem); | 310 | down(&s->skt_sem); |
171 | if ((s->callback) && | 311 | if ((s->callback) && (s->state & SOCKET_PRESENT) && |
172 | (s->state & SOCKET_PRESENT) && | ||
173 | !(s->state & SOCKET_CARDBUS)) { | 312 | !(s->state & SOCKET_CARDBUS)) { |
174 | if (try_module_get(s->callback->owner)) { | 313 | if (try_module_get(s->callback->owner)) { |
175 | s->callback->resources_done(s); | 314 | s->callback->requery(s); |
176 | module_put(s->callback->owner); | 315 | module_put(s->callback->owner); |
177 | } | 316 | } |
178 | } | 317 | } |
179 | up(&s->skt_sem); | 318 | up(&s->skt_sem); |
180 | |||
181 | return count; | ||
182 | } | 319 | } |
183 | spin_unlock_irqrestore(&s->lock, flags); | ||
184 | 320 | ||
185 | return count; | 321 | |
322 | return (ret); | ||
186 | } | 323 | } |
187 | static CLASS_DEVICE_ATTR(available_resources_setup_done, 0600, pccard_show_resource, pccard_store_resource); | ||
188 | 324 | ||
189 | 325 | ||
190 | static struct class_device_attribute *pccard_socket_attributes[] = { | 326 | static struct class_device_attribute *pccard_socket_attributes[] = { |
@@ -199,6 +335,13 @@ static struct class_device_attribute *pccard_socket_attributes[] = { | |||
199 | NULL, | 335 | NULL, |
200 | }; | 336 | }; |
201 | 337 | ||
338 | static struct bin_attribute pccard_cis_attr = { | ||
339 | .attr = { .name = "cis", .mode = S_IRUGO | S_IWUSR, .owner = THIS_MODULE}, | ||
340 | .size = 0x200, | ||
341 | .read = pccard_show_cis, | ||
342 | .write = pccard_store_cis, | ||
343 | }; | ||
344 | |||
202 | static int __devinit pccard_sysfs_add_socket(struct class_device *class_dev) | 345 | static int __devinit pccard_sysfs_add_socket(struct class_device *class_dev) |
203 | { | 346 | { |
204 | struct class_device_attribute **attr; | 347 | struct class_device_attribute **attr; |
@@ -209,6 +352,8 @@ static int __devinit pccard_sysfs_add_socket(struct class_device *class_dev) | |||
209 | if (ret) | 352 | if (ret) |
210 | break; | 353 | break; |
211 | } | 354 | } |
355 | if (!ret) | ||
356 | ret = sysfs_create_bin_file(&class_dev->kobj, &pccard_cis_attr); | ||
212 | 357 | ||
213 | return ret; | 358 | return ret; |
214 | } | 359 | } |
@@ -217,6 +362,7 @@ static void __devexit pccard_sysfs_remove_socket(struct class_device *class_dev) | |||
217 | { | 362 | { |
218 | struct class_device_attribute **attr; | 363 | struct class_device_attribute **attr; |
219 | 364 | ||
365 | sysfs_remove_bin_file(&class_dev->kobj, &pccard_cis_attr); | ||
220 | for (attr = pccard_socket_attributes; *attr; attr++) | 366 | for (attr = pccard_socket_attributes; *attr; attr++) |
221 | class_device_remove_file(class_dev, *attr); | 367 | class_device_remove_file(class_dev, *attr); |
222 | } | 368 | } |