aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/powerpc/kernel/ibmebus.c167
-rw-r--r--include/asm-powerpc/ibmebus.h2
2 files changed, 134 insertions, 35 deletions
diff --git a/arch/powerpc/kernel/ibmebus.c b/arch/powerpc/kernel/ibmebus.c
index 061df3a066ae..8ed1163c0bd4 100644
--- a/arch/powerpc/kernel/ibmebus.c
+++ b/arch/powerpc/kernel/ibmebus.c
@@ -2,6 +2,7 @@
2 * IBM PowerPC IBM eBus Infrastructure Support. 2 * IBM PowerPC IBM eBus Infrastructure Support.
3 * 3 *
4 * Copyright (c) 2005 IBM Corporation 4 * Copyright (c) 2005 IBM Corporation
5 * Joachim Fenkes <fenkes@de.ibm.com>
5 * Heiko J Schick <schickhj@de.ibm.com> 6 * Heiko J Schick <schickhj@de.ibm.com>
6 * 7 *
7 * All rights reserved. 8 * All rights reserved.
@@ -43,12 +44,14 @@
43#include <asm/ibmebus.h> 44#include <asm/ibmebus.h>
44#include <asm/abs_addr.h> 45#include <asm/abs_addr.h>
45 46
46static struct ibmebus_dev ibmebus_bus_device = { /* fake "parent" device */ 47#define MAX_LOC_CODE_LENGTH 80
47 .name = ibmebus_bus_device.ofdev.dev.bus_id, 48
48 .ofdev.dev.bus_id = "ibmebus", 49static struct device ibmebus_bus_device = { /* fake "parent" device */
49 .ofdev.dev.bus = &ibmebus_bus_type, 50 .bus_id = "ibmebus",
50}; 51};
51 52
53struct bus_type ibmebus_bus_type;
54
52static void *ibmebus_alloc_coherent(struct device *dev, 55static void *ibmebus_alloc_coherent(struct device *dev,
53 size_t size, 56 size_t size,
54 dma_addr_t *dma_handle, 57 dma_addr_t *dma_handle,
@@ -158,21 +161,12 @@ static void __devinit ibmebus_dev_release(struct device *dev)
158 kfree(to_ibmebus_dev(dev)); 161 kfree(to_ibmebus_dev(dev));
159} 162}
160 163
161static ssize_t ibmebusdev_show_name(struct device *dev, 164static int __devinit ibmebus_register_device_common(
162 struct device_attribute *attr, char *buf)
163{
164 return sprintf(buf, "%s\n", to_ibmebus_dev(dev)->name);
165}
166static DEVICE_ATTR(name, S_IRUSR | S_IRGRP | S_IROTH, ibmebusdev_show_name,
167 NULL);
168
169static struct ibmebus_dev* __devinit ibmebus_register_device_common(
170 struct ibmebus_dev *dev, const char *name) 165 struct ibmebus_dev *dev, const char *name)
171{ 166{
172 int err = 0; 167 int err = 0;
173 168
174 dev->name = name; 169 dev->ofdev.dev.parent = &ibmebus_bus_device;
175 dev->ofdev.dev.parent = &ibmebus_bus_device.ofdev.dev;
176 dev->ofdev.dev.bus = &ibmebus_bus_type; 170 dev->ofdev.dev.bus = &ibmebus_bus_type;
177 dev->ofdev.dev.release = ibmebus_dev_release; 171 dev->ofdev.dev.release = ibmebus_dev_release;
178 172
@@ -186,12 +180,10 @@ static struct ibmebus_dev* __devinit ibmebus_register_device_common(
186 if ((err = of_device_register(&dev->ofdev)) != 0) { 180 if ((err = of_device_register(&dev->ofdev)) != 0) {
187 printk(KERN_ERR "%s: failed to register device (%d).\n", 181 printk(KERN_ERR "%s: failed to register device (%d).\n",
188 __FUNCTION__, err); 182 __FUNCTION__, err);
189 return NULL; 183 return -ENODEV;
190 } 184 }
191 185
192 device_create_file(&dev->ofdev.dev, &dev_attr_name); 186 return 0;
193
194 return dev;
195} 187}
196 188
197static struct ibmebus_dev* __devinit ibmebus_register_device_node( 189static struct ibmebus_dev* __devinit ibmebus_register_device_node(
@@ -205,18 +197,18 @@ static struct ibmebus_dev* __devinit ibmebus_register_device_node(
205 if (!loc_code) { 197 if (!loc_code) {
206 printk(KERN_WARNING "%s: node %s missing 'ibm,loc-code'\n", 198 printk(KERN_WARNING "%s: node %s missing 'ibm,loc-code'\n",
207 __FUNCTION__, dn->name ? dn->name : "<unknown>"); 199 __FUNCTION__, dn->name ? dn->name : "<unknown>");
208 return NULL; 200 return ERR_PTR(-EINVAL);
209 } 201 }
210 202
211 if (strlen(loc_code) == 0) { 203 if (strlen(loc_code) == 0) {
212 printk(KERN_WARNING "%s: 'ibm,loc-code' is invalid\n", 204 printk(KERN_WARNING "%s: 'ibm,loc-code' is invalid\n",
213 __FUNCTION__); 205 __FUNCTION__);
214 return NULL; 206 return ERR_PTR(-EINVAL);
215 } 207 }
216 208
217 dev = kzalloc(sizeof(struct ibmebus_dev), GFP_KERNEL); 209 dev = kzalloc(sizeof(struct ibmebus_dev), GFP_KERNEL);
218 if (!dev) { 210 if (!dev) {
219 return NULL; 211 return ERR_PTR(-ENOMEM);
220 } 212 }
221 213
222 dev->ofdev.node = of_node_get(dn); 214 dev->ofdev.node = of_node_get(dn);
@@ -227,9 +219,9 @@ static struct ibmebus_dev* __devinit ibmebus_register_device_node(
227 min(length, BUS_ID_SIZE - 1)); 219 min(length, BUS_ID_SIZE - 1));
228 220
229 /* Register with generic device framework. */ 221 /* Register with generic device framework. */
230 if (ibmebus_register_device_common(dev, dn->name) == NULL) { 222 if (ibmebus_register_device_common(dev, dn->name) != 0) {
231 kfree(dev); 223 kfree(dev);
232 return NULL; 224 return ERR_PTR(-ENODEV);
233 } 225 }
234 226
235 return dev; 227 return dev;
@@ -240,9 +232,8 @@ static void ibmebus_probe_of_nodes(char* name)
240 struct device_node *dn = NULL; 232 struct device_node *dn = NULL;
241 233
242 while ((dn = of_find_node_by_name(dn, name))) { 234 while ((dn = of_find_node_by_name(dn, name))) {
243 if (ibmebus_register_device_node(dn) == NULL) { 235 if (IS_ERR(ibmebus_register_device_node(dn))) {
244 of_node_put(dn); 236 of_node_put(dn);
245
246 return; 237 return;
247 } 238 }
248 } 239 }
@@ -262,9 +253,15 @@ static void ibmebus_add_devices_by_id(struct of_device_id *idt)
262 return; 253 return;
263} 254}
264 255
265static int ibmebus_match_helper(struct device *dev, void *data) 256static int ibmebus_match_helper_name(struct device *dev, void *data)
266{ 257{
267 if (strcmp((char*)data, to_ibmebus_dev(dev)->name) == 0) 258 const struct ibmebus_dev *ebus_dev = to_ibmebus_dev(dev);
259 char *name;
260
261 name = (char*)get_property(
262 ebus_dev->ofdev.node, "name", NULL);
263
264 if (name && (strcmp((char*)data, name) == 0))
268 return 1; 265 return 1;
269 266
270 return 0; 267 return 0;
@@ -272,7 +269,6 @@ static int ibmebus_match_helper(struct device *dev, void *data)
272 269
273static int ibmebus_unregister_device(struct device *dev) 270static int ibmebus_unregister_device(struct device *dev)
274{ 271{
275 device_remove_file(dev, &dev_attr_name);
276 of_device_unregister(to_of_device(dev)); 272 of_device_unregister(to_of_device(dev));
277 273
278 return 0; 274 return 0;
@@ -285,11 +281,10 @@ static void ibmebus_remove_devices_by_id(struct of_device_id *idt)
285 while (strlen(idt->name) > 0) { 281 while (strlen(idt->name) > 0) {
286 while ((dev = bus_find_device(&ibmebus_bus_type, NULL, 282 while ((dev = bus_find_device(&ibmebus_bus_type, NULL,
287 (void*)idt->name, 283 (void*)idt->name,
288 ibmebus_match_helper))) { 284 ibmebus_match_helper_name))) {
289 ibmebus_unregister_device(dev); 285 ibmebus_unregister_device(dev);
290 } 286 }
291 idt++; 287 idt++;
292
293 } 288 }
294 289
295 return; 290 return;
@@ -307,6 +302,9 @@ int ibmebus_register_driver(struct ibmebus_driver *drv)
307 if ((err = driver_register(&drv->driver) != 0)) 302 if ((err = driver_register(&drv->driver) != 0))
308 return err; 303 return err;
309 304
305 /* remove all supported devices first, in case someone
306 * probed them manually before registering the driver */
307 ibmebus_remove_devices_by_id(drv->id_table);
310 ibmebus_add_devices_by_id(drv->id_table); 308 ibmebus_add_devices_by_id(drv->id_table);
311 309
312 return 0; 310 return 0;
@@ -361,9 +359,110 @@ static int ibmebus_bus_match(struct device *dev, struct device_driver *drv)
361 return 0; 359 return 0;
362} 360}
363 361
362static ssize_t name_show(struct device *dev,
363 struct device_attribute *attr, char *buf)
364{
365 struct ibmebus_dev *ebus_dev = to_ibmebus_dev(dev);
366 char *name = (char*)get_property(ebus_dev->ofdev.node, "name", NULL);
367 return sprintf(buf, "%s\n", name);
368}
369
370static struct device_attribute ibmebus_dev_attrs[] = {
371 __ATTR_RO(name),
372 __ATTR_NULL
373};
374
375static int ibmebus_match_helper_loc_code(struct device *dev, void *data)
376{
377 const struct ibmebus_dev *ebus_dev = to_ibmebus_dev(dev);
378 char *loc_code;
379
380 loc_code = (char*)get_property(
381 ebus_dev->ofdev.node, "ibm,loc-code", NULL);
382
383 if (loc_code && (strcmp((char*)data, loc_code) == 0))
384 return 1;
385
386 return 0;
387}
388
389static ssize_t ibmebus_store_probe(struct bus_type *bus,
390 const char *buf, size_t count)
391{
392 struct device_node *dn = NULL;
393 struct ibmebus_dev *dev;
394 char *loc_code;
395 char parm[MAX_LOC_CODE_LENGTH];
396
397 if (count >= MAX_LOC_CODE_LENGTH)
398 return -EINVAL;
399 memcpy(parm, buf, count);
400 parm[count] = '\0';
401 if (parm[count-1] == '\n')
402 parm[count-1] = '\0';
403
404 if (bus_find_device(&ibmebus_bus_type, NULL, parm,
405 ibmebus_match_helper_loc_code)) {
406 printk(KERN_WARNING "%s: loc_code %s has already been probed\n",
407 __FUNCTION__, parm);
408 return -EINVAL;
409 }
410
411 while ((dn = of_find_all_nodes(dn))) {
412 loc_code = (char *)get_property(dn, "ibm,loc-code", NULL);
413 if (loc_code && (strncmp(loc_code, parm, count) == 0)) {
414 dev = ibmebus_register_device_node(dn);
415 if (IS_ERR(dev)) {
416 of_node_put(dn);
417 return PTR_ERR(dev);
418 } else
419 return count; /* success */
420 }
421 }
422
423 /* if we drop out of the loop, the loc code was invalid */
424 printk(KERN_WARNING "%s: no device with loc_code %s found\n",
425 __FUNCTION__, parm);
426 return -ENODEV;
427}
428
429static ssize_t ibmebus_store_remove(struct bus_type *bus,
430 const char *buf, size_t count)
431{
432 struct device *dev;
433 char parm[MAX_LOC_CODE_LENGTH];
434
435 if (count >= MAX_LOC_CODE_LENGTH)
436 return -EINVAL;
437 memcpy(parm, buf, count);
438 parm[count] = '\0';
439 if (parm[count-1] == '\n')
440 parm[count-1] = '\0';
441
442 /* The location code is unique, so we will find one device at most */
443 if ((dev = bus_find_device(&ibmebus_bus_type, NULL, parm,
444 ibmebus_match_helper_loc_code))) {
445 ibmebus_unregister_device(dev);
446 } else {
447 printk(KERN_WARNING "%s: loc_code %s not on the bus\n",
448 __FUNCTION__, parm);
449 return -ENODEV;
450 }
451
452 return count;
453}
454
455static struct bus_attribute ibmebus_bus_attrs[] = {
456 __ATTR(probe, S_IWUSR, NULL, ibmebus_store_probe),
457 __ATTR(remove, S_IWUSR, NULL, ibmebus_store_remove),
458 __ATTR_NULL
459};
460
364struct bus_type ibmebus_bus_type = { 461struct bus_type ibmebus_bus_type = {
365 .name = "ibmebus", 462 .name = "ibmebus",
366 .match = ibmebus_bus_match, 463 .match = ibmebus_bus_match,
464 .dev_attrs = ibmebus_dev_attrs,
465 .bus_attrs = ibmebus_bus_attrs
367}; 466};
368EXPORT_SYMBOL(ibmebus_bus_type); 467EXPORT_SYMBOL(ibmebus_bus_type);
369 468
@@ -380,7 +479,7 @@ static int __init ibmebus_bus_init(void)
380 return err; 479 return err;
381 } 480 }
382 481
383 err = device_register(&ibmebus_bus_device.ofdev.dev); 482 err = device_register(&ibmebus_bus_device);
384 if (err) { 483 if (err) {
385 printk(KERN_WARNING "%s: device_register returned %i\n", 484 printk(KERN_WARNING "%s: device_register returned %i\n",
386 __FUNCTION__, err); 485 __FUNCTION__, err);
diff --git a/include/asm-powerpc/ibmebus.h b/include/asm-powerpc/ibmebus.h
index 8d3c9e39b90f..87d396e28db2 100644
--- a/include/asm-powerpc/ibmebus.h
+++ b/include/asm-powerpc/ibmebus.h
@@ -2,6 +2,7 @@
2 * IBM PowerPC eBus Infrastructure Support. 2 * IBM PowerPC eBus Infrastructure Support.
3 * 3 *
4 * Copyright (c) 2005 IBM Corporation 4 * Copyright (c) 2005 IBM Corporation
5 * Joachim Fenkes <fenkes@de.ibm.com>
5 * Heiko J Schick <schickhj@de.ibm.com> 6 * Heiko J Schick <schickhj@de.ibm.com>
6 * 7 *
7 * All rights reserved. 8 * All rights reserved.
@@ -47,7 +48,6 @@
47extern struct bus_type ibmebus_bus_type; 48extern struct bus_type ibmebus_bus_type;
48 49
49struct ibmebus_dev { 50struct ibmebus_dev {
50 const char *name;
51 struct of_device ofdev; 51 struct of_device ofdev;
52}; 52};
53 53