macio_asic.c 19.7 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1
2
3
4
5
/*
 * Bus & driver management routines for devices within
 * a MacIO ASIC. Interface to new driver model mostly
 * stolen from the PCI version.
 * 
6
7
8
9
10
11
12
 *  Copyright (C) 2005 Ben. Herrenschmidt (benh@kernel.crashing.org)
 *
 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU General Public License
 *  as published by the Free Software Foundation; either version
 *  2 of the License, or (at your option) any later version.
 *
Linus Torvalds's avatar
Linus Torvalds committed
13
14
15
16
17
18
19
20
21
22
23
24
25
26
 * TODO:
 * 
 *  - Don't probe below media bay by default, but instead provide
 *    some hooks for media bay to dynamically add/remove it's own
 *    sub-devices.
 */
 
#include <linux/config.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/pci_ids.h>
#include <linux/init.h>
#include <linux/module.h>
Tim Schmielau's avatar
Tim Schmielau committed
27
28
#include <linux/slab.h>

Linus Torvalds's avatar
Linus Torvalds committed
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <asm/machdep.h>
#include <asm/macio.h>
#include <asm/pmac_feature.h>
#include <asm/prom.h>
#include <asm/pci-bridge.h>

#undef DEBUG

#define MAX_NODE_NAME_SIZE (BUS_ID_SIZE - 12)

static struct macio_chip      *macio_on_hold;

static int macio_bus_match(struct device *dev, struct device_driver *drv) 
{
	struct macio_dev * macio_dev = to_macio_device(dev);
	struct macio_driver * macio_drv = to_macio_driver(drv);
45
	const struct of_device_id * matches = macio_drv->match_table;
Linus Torvalds's avatar
Linus Torvalds committed
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77

	if (!matches) 
		return 0;

	return of_match_device(matches, &macio_dev->ofdev) != NULL;
}

struct macio_dev *macio_dev_get(struct macio_dev *dev)
{
	struct device *tmp;

	if (!dev)
		return NULL;
	tmp = get_device(&dev->ofdev.dev);
	if (tmp)
		return to_macio_device(tmp);
	else
		return NULL;
}

void macio_dev_put(struct macio_dev *dev)
{
	if (dev)
		put_device(&dev->ofdev.dev);
}


static int macio_device_probe(struct device *dev)
{
	int error = -ENODEV;
	struct macio_driver *drv;
	struct macio_dev *macio_dev;
78
	const struct of_device_id *match;
Linus Torvalds's avatar
Linus Torvalds committed
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117

	drv = to_macio_driver(dev->driver);
	macio_dev = to_macio_device(dev);

	if (!drv->probe)
		return error;

	macio_dev_get(macio_dev);

	match = of_match_device(drv->match_table, &macio_dev->ofdev);
	if (match)
		error = drv->probe(macio_dev, match);
	if (error)
		macio_dev_put(macio_dev);

	return error;
}

static int macio_device_remove(struct device *dev)
{
	struct macio_dev * macio_dev = to_macio_device(dev);
	struct macio_driver * drv = to_macio_driver(dev->driver);

	if (dev->driver && drv->remove)
		drv->remove(macio_dev);
	macio_dev_put(macio_dev);

	return 0;
}

static void macio_device_shutdown(struct device *dev)
{
	struct macio_dev * macio_dev = to_macio_device(dev);
	struct macio_driver * drv = to_macio_driver(dev->driver);

	if (dev->driver && drv->shutdown)
		drv->shutdown(macio_dev);
}

118
static int macio_device_suspend(struct device *dev, pm_message_t state)
Linus Torvalds's avatar
Linus Torvalds committed
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
{
	struct macio_dev * macio_dev = to_macio_device(dev);
	struct macio_driver * drv = to_macio_driver(dev->driver);

	if (dev->driver && drv->suspend)
		return drv->suspend(macio_dev, state);
	return 0;
}

static int macio_device_resume(struct device * dev)
{
	struct macio_dev * macio_dev = to_macio_device(dev);
	struct macio_driver * drv = to_macio_driver(dev->driver);

	if (dev->driver && drv->resume)
		return drv->resume(macio_dev);
	return 0;
}

138
static int macio_uevent(struct device *dev, char **envp, int num_envp,
139
140
141
142
                          char *buffer, int buffer_size)
{
	struct macio_dev * macio_dev;
	struct of_device * of;
Olaf Hering's avatar
Olaf Hering committed
143
	char *scratch, *compat, *compat2;
144
	int i = 0;
Olaf Hering's avatar
Olaf Hering committed
145
	int length, cplen, cplen2, seen = 0;
146
147
148
149
150
151
152
153
154
155
156

	if (!dev)
		return -ENODEV;

	macio_dev = to_macio_device(dev);
	if (!macio_dev)
		return -ENODEV;

	of = &macio_dev->ofdev;

	/* stuff we want to pass to /sbin/hotplug */
Olaf Hering's avatar
Olaf Hering committed
157
158
	envp[i++] = scratch = buffer;
	length = scnprintf (scratch, buffer_size, "OF_NAME=%s", of->node->name);
159
	++length;
Olaf Hering's avatar
Olaf Hering committed
160
161
162
	buffer_size -= length;
	if ((buffer_size <= 0) || (i >= num_envp))
		return -ENOMEM;
163
164
165
	scratch += length;

	envp[i++] = scratch;
Olaf Hering's avatar
Olaf Hering committed
166
	length = scnprintf (scratch, buffer_size, "OF_TYPE=%s", of->node->type);
167
	++length;
Olaf Hering's avatar
Olaf Hering committed
168
169
170
	buffer_size -= length;
	if ((buffer_size <= 0) || (i >= num_envp))
		return -ENOMEM;
171
172
173
174
175
176
177
	scratch += length;

        /* Since the compatible field can contain pretty much anything
         * it's not really legal to split it out with commas. We split it
         * up using a number of environment variables instead. */

	compat = (char *) get_property(of->node, "compatible", &cplen);
Olaf Hering's avatar
Olaf Hering committed
178
179
	compat2 = compat;
	cplen2= cplen;
180
181
	while (compat && cplen > 0) {
                envp[i++] = scratch;
Olaf Hering's avatar
Olaf Hering committed
182
		length = scnprintf (scratch, buffer_size,
183
		                     "OF_COMPATIBLE_%d=%s", seen, compat);
Olaf Hering's avatar
Olaf Hering committed
184
185
186
		++length;
		buffer_size -= length;
		if ((buffer_size <= 0) || (i >= num_envp))
187
188
			return -ENOMEM;
		scratch += length;
Olaf Hering's avatar
Olaf Hering committed
189
190
191
		length = strlen (compat) + 1;
		compat += length;
		cplen -= length;
192
193
194
195
		seen++;
	}

	envp[i++] = scratch;
Olaf Hering's avatar
Olaf Hering committed
196
	length = scnprintf (scratch, buffer_size, "OF_COMPATIBLE_N=%d", seen);
197
	++length;
Olaf Hering's avatar
Olaf Hering committed
198
199
200
201
202
203
204
205
206
207
208
209
	buffer_size -= length;
	if ((buffer_size <= 0) || (i >= num_envp))
		return -ENOMEM;
	scratch += length;

	envp[i++] = scratch;
	length = scnprintf (scratch, buffer_size, "MODALIAS=of:N%sT%s",
			of->node->name, of->node->type);
	/* overwrite '\0' */
	buffer_size -= length;
	if ((buffer_size <= 0) || (i >= num_envp))
		return -ENOMEM;
210
211
	scratch += length;

Olaf Hering's avatar
Olaf Hering committed
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
	if (!compat2) {
		compat2 = "";
		cplen2 = 1;
	}
	while (cplen2 > 0) {
		length = snprintf (scratch, buffer_size, "C%s", compat2);
		buffer_size -= length;
		if (buffer_size <= 0)
			return -ENOMEM;
		scratch += length;
		length = strlen (compat2) + 1;
		compat2 += length;
		cplen2 -= length;
	}

227
228
229
230
231
	envp[i] = NULL;

	return 0;
}

232
233
extern struct device_attribute macio_dev_attrs[];

Linus Torvalds's avatar
Linus Torvalds committed
234
235
236
struct bus_type macio_bus_type = {
       .name	= "macio",
       .match	= macio_bus_match,
237
       .uevent = macio_uevent,
238
239
240
       .probe	= macio_device_probe,
       .remove	= macio_device_remove,
       .shutdown = macio_device_shutdown,
Linus Torvalds's avatar
Linus Torvalds committed
241
242
       .suspend	= macio_device_suspend,
       .resume	= macio_device_resume,
243
       .dev_attrs = macio_dev_attrs,
Linus Torvalds's avatar
Linus Torvalds committed
244
245
246
247
248
249
250
251
252
253
254
};

static int __init macio_bus_driver_init(void)
{
	return bus_register(&macio_bus_type);
}

postcore_initcall(macio_bus_driver_init);


/**
255
256
 * macio_release_dev - free a macio device structure when all users of it are
 * finished.
Linus Torvalds's avatar
Linus Torvalds committed
257
258
 * @dev: device that's been disconnected
 *
259
260
261
262
 * Will be called only by the device core when all users of this macio device
 * are done. This currently means never as we don't hot remove any macio
 * device yet, though that will happen with mediabay based devices in a later
 * implementation.
Linus Torvalds's avatar
Linus Torvalds committed
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
 */
static void macio_release_dev(struct device *dev)
{
	struct macio_dev *mdev;

        mdev = to_macio_device(dev);
	kfree(mdev);
}

/**
 * macio_resource_quirks - tweak or skip some resources for a device
 * @np: pointer to the device node
 * @res: resulting resource
 * @index: index of resource in node
 *
 * If this routine returns non-null, then the resource is completely
 * skipped.
 */
281
282
static int macio_resource_quirks(struct device_node *np, struct resource *res,
				 int index)
Linus Torvalds's avatar
Linus Torvalds committed
283
284
285
{
	if (res->flags & IORESOURCE_MEM) {
		/* Grand Central has too large resource 0 on some machines */
286
		if (index == 0 && !strcmp(np->name, "gc"))
Linus Torvalds's avatar
Linus Torvalds committed
287
			res->end = res->start + 0x1ffff;
288

Linus Torvalds's avatar
Linus Torvalds committed
289
290
291
		/* Airport has bogus resource 2 */
		if (index >= 2 && !strcmp(np->name, "radio"))
			return 1;
292
293

#ifndef CONFIG_PPC64
Linus Torvalds's avatar
Linus Torvalds committed
294
		/* DBDMAs may have bogus sizes */
295
		if ((res->start & 0x0001f000) == 0x00008000)
Linus Torvalds's avatar
Linus Torvalds committed
296
			res->end = res->start + 0xff;
297
298
#endif /* CONFIG_PPC64 */

299
300
301
302
		/* ESCC parent eats child resources. We could have added a
		 * level of hierarchy, but I don't really feel the need
		 * for it
		 */
Linus Torvalds's avatar
Linus Torvalds committed
303
304
		if (!strcmp(np->name, "escc"))
			return 1;
305

Linus Torvalds's avatar
Linus Torvalds committed
306
		/* ESCC has bogus resources >= 3 */
307
308
		if (index >= 3 && !(strcmp(np->name, "ch-a") &&
				    strcmp(np->name, "ch-b")))
Linus Torvalds's avatar
Linus Torvalds committed
309
			return 1;
310

Linus Torvalds's avatar
Linus Torvalds committed
311
312
313
		/* Media bay has too many resources, keep only first one */
		if (index > 0 && !strcmp(np->name, "media-bay"))
			return 1;
314

Linus Torvalds's avatar
Linus Torvalds committed
315
316
317
		/* Some older IDE resources have bogus sizes */
		if (!(strcmp(np->name, "IDE") && strcmp(np->name, "ATA") &&
		      strcmp(np->type, "ide") && strcmp(np->type, "ata"))) {
318
			if (index == 0 && (res->end - res->start) > 0xfff)
Linus Torvalds's avatar
Linus Torvalds committed
319
				res->end = res->start + 0xfff;
320
			if (index == 1 && (res->end - res->start) > 0xff)
Linus Torvalds's avatar
Linus Torvalds committed
321
322
323
324
325
326
327
				res->end = res->start + 0xff;
		}
	}
	return 0;
}


328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
static void macio_setup_interrupts(struct macio_dev *dev)
{
	struct device_node *np = dev->ofdev.node;
	int i,j;

	/* For now, we use pre-parsed entries in the device-tree for
	 * interrupt routing and addresses, but we should change that
	 * to dynamically parsed entries and so get rid of most of the
	 * clutter in struct device_node
	 */
	for (i = j = 0; i < np->n_intrs; i++) {
		struct resource *res = &dev->interrupt[j];

		if (j >= MACIO_DEV_COUNT_IRQS)
			break;
		res->start = np->intrs[i].line;
		res->flags = IORESOURCE_IO;
		if (np->intrs[j].sense)
			res->flags |= IORESOURCE_IRQ_LOWLEVEL;
		else
			res->flags |= IORESOURCE_IRQ_HIGHEDGE;
		res->name = dev->ofdev.dev.bus_id;
		if (macio_resource_quirks(np, res, i))
			memset(res, 0, sizeof(struct resource));
		else
			j++;
	}
	dev->n_interrupts = j;
}

static void macio_setup_resources(struct macio_dev *dev,
				  struct resource *parent_res)
{
	struct device_node *np = dev->ofdev.node;
362
	struct resource r;
363
364
	int index;

365
	for (index = 0; of_address_to_resource(np, index, &r) == 0; index++) {
366
367
368
		struct resource *res = &dev->resource[index];
		if (index >= MACIO_DEV_COUNT_RESOURCES)
			break;
369
		*res = r;
370
371
372
373
374
375
376
377
378
		res->name = dev->ofdev.dev.bus_id;

		if (macio_resource_quirks(np, res, index)) {
			memset(res, 0, sizeof(struct resource));
			continue;
		}
		/* Currently, we consider failure as harmless, this may
		 * change in the future, once I've found all the device
		 * tree bugs in older machines & worked around them
379
		 */
380
381
382
383
384
385
386
387
388
		if (insert_resource(parent_res, res)) {
			printk(KERN_WARNING "Can't request resource "
			       "%d for MacIO device %s\n",
			       index, dev->ofdev.dev.bus_id);
		}
	}
	dev->n_resources = index;
}

Linus Torvalds's avatar
Linus Torvalds committed
389
390
391
392
393
394
395
396
397
/**
 * macio_add_one_device - Add one device from OF node to the device tree
 * @chip: pointer to the macio_chip holding the device
 * @np: pointer to the device node in the OF tree
 * @in_bay: set to 1 if device is part of a media-bay
 *
 * When media-bay is changed to hotswap drivers, this function will
 * be exposed to the bay driver some way...
 */
398
399
400
401
static struct macio_dev * macio_add_one_device(struct macio_chip *chip,
					       struct device *parent,
					       struct device_node *np,
					       struct macio_dev *in_bay,
Linus Torvalds's avatar
Linus Torvalds committed
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
					       struct resource *parent_res)
{
	struct macio_dev *dev;
	u32 *reg;
	
	if (np == NULL)
		return NULL;

	dev = kmalloc(sizeof(*dev), GFP_KERNEL);
	if (!dev)
		return NULL;
	memset(dev, 0, sizeof(*dev));

	dev->bus = &chip->lbus;
	dev->media_bay = in_bay;
	dev->ofdev.node = np;
	dev->ofdev.dma_mask = 0xffffffffUL;
	dev->ofdev.dev.dma_mask = &dev->ofdev.dma_mask;
	dev->ofdev.dev.parent = parent;
	dev->ofdev.dev.bus = &macio_bus_type;
	dev->ofdev.dev.release = macio_release_dev;

#ifdef DEBUG
	printk("preparing mdev @%p, ofdev @%p, dev @%p, kobj @%p\n",
	       dev, &dev->ofdev, &dev->ofdev.dev, &dev->ofdev.dev.kobj);
#endif

	/* MacIO itself has a different reg, we use it's PCI base */
	if (np == chip->of_node) {
431
432
		sprintf(dev->ofdev.dev.bus_id, "%1d.%08lx:%.*s",
			chip->lbus.index,
Linus Torvalds's avatar
Linus Torvalds committed
433
434
435
436
437
438
439
440
#ifdef CONFIG_PCI
			pci_resource_start(chip->lbus.pdev, 0),
#else
			0, /* NuBus may want to do something better here */
#endif
			MAX_NODE_NAME_SIZE, np->name);
	} else {
		reg = (u32 *)get_property(np, "reg", NULL);
441
442
		sprintf(dev->ofdev.dev.bus_id, "%1d.%08x:%.*s",
			chip->lbus.index,
Linus Torvalds's avatar
Linus Torvalds committed
443
444
445
			reg ? *reg : 0, MAX_NODE_NAME_SIZE, np->name);
	}

446
447
448
	/* Setup interrupts & resources */
	macio_setup_interrupts(dev);
	macio_setup_resources(dev, parent_res);
Linus Torvalds's avatar
Linus Torvalds committed
449

450
	/* Register with core */
Linus Torvalds's avatar
Linus Torvalds committed
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
	if (of_device_register(&dev->ofdev) != 0) {
		printk(KERN_DEBUG"macio: device registration error for %s!\n",
		       dev->ofdev.dev.bus_id);
		kfree(dev);
		return NULL;
	}

	return dev;
}

static int macio_skip_device(struct device_node *np)
{
	if (strncmp(np->name, "battery", 7) == 0)
		return 1;
	if (strncmp(np->name, "escc-legacy", 11) == 0)
		return 1;
	return 0;
}

/**
 * macio_pci_add_devices - Adds sub-devices of mac-io to the device tree
 * @chip: pointer to the macio_chip holding the devices
 * 
 * This function will do the job of extracting devices from the
 * Open Firmware device tree, build macio_dev structures and add
 * them to the Linux device tree.
 * 
 * For now, childs of media-bay are added now as well. This will
 * change rsn though.
 */
static void macio_pci_add_devices(struct macio_chip *chip)
{
	struct device_node *np, *pnode;
	struct macio_dev *rdev, *mdev, *mbdev = NULL, *sdev = NULL;
	struct device *parent = NULL;
	struct resource *root_res = &iomem_resource;
	
	/* Add a node for the macio bus itself */
#ifdef CONFIG_PCI
	if (chip->lbus.pdev) {
		parent = &chip->lbus.pdev->dev;
		root_res = &chip->lbus.pdev->resource[0];
	}
#endif
	pnode = of_node_get(chip->of_node);
	if (pnode == NULL)
		return;

	/* Add macio itself to hierarchy */
	rdev = macio_add_one_device(chip, parent, pnode, NULL, root_res);
	if (rdev == NULL)
		return;
	root_res = &rdev->resource[0];

	/* First scan 1st level */
	for (np = NULL; (np = of_get_next_child(pnode, np)) != NULL;) {
507
508
509
510
511
512
513
514
515
516
517
		if (macio_skip_device(np))
			continue;
		of_node_get(np);
		mdev = macio_add_one_device(chip, &rdev->ofdev.dev, np, NULL,
					    root_res);
		if (mdev == NULL)
			of_node_put(np);
		else if (strncmp(np->name, "media-bay", 9) == 0)
			mbdev = mdev;
		else if (strncmp(np->name, "escc", 4) == 0)
			sdev = mdev;
Linus Torvalds's avatar
Linus Torvalds committed
518
519
520
521
	}

	/* Add media bay devices if any */
	if (mbdev)
522
523
524
525
526
527
528
529
530
531
		for (np = NULL; (np = of_get_next_child(mbdev->ofdev.node, np))
			     != NULL;) {
			if (macio_skip_device(np))
				continue;
			of_node_get(np);
			if (macio_add_one_device(chip, &mbdev->ofdev.dev, np,
						 mbdev,  root_res) == NULL)
				of_node_put(np);
		}

Linus Torvalds's avatar
Linus Torvalds committed
532
533
	/* Add serial ports if any */
	if (sdev) {
534
535
536
537
538
539
540
541
542
		for (np = NULL; (np = of_get_next_child(sdev->ofdev.node, np))
			     != NULL;) {
			if (macio_skip_device(np))
				continue;
			of_node_get(np);
			if (macio_add_one_device(chip, &sdev->ofdev.dev, np,
						 NULL, root_res) == NULL)
				of_node_put(np);
		}
Linus Torvalds's avatar
Linus Torvalds committed
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
	}
}


/**
 * macio_register_driver - Registers a new MacIO device driver
 * @drv: pointer to the driver definition structure
 */
int macio_register_driver(struct macio_driver *drv)
{
	/* initialize common driver fields */
	drv->driver.name = drv->name;
	drv->driver.bus = &macio_bus_type;

	/* register with core */
558
	return driver_register(&drv->driver);
Linus Torvalds's avatar
Linus Torvalds committed
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
}

/**
 * macio_unregister_driver - Unregisters a new MacIO device driver
 * @drv: pointer to the driver definition structure
 */
void macio_unregister_driver(struct macio_driver *drv)
{
	driver_unregister(&drv->driver);
}

/**
 *	macio_request_resource - Request an MMIO resource
 * 	@dev: pointer to the device holding the resource
 *	@resource_no: resource number to request
 *	@name: resource name
 *
 *	Mark  memory region number @resource_no associated with MacIO
 *	device @dev as being reserved by owner @name.  Do not access
 *	any address inside the memory regions unless this call returns
 *	successfully.
 *
 *	Returns 0 on success, or %EBUSY on error.  A warning
 *	message is also printed on failure.
 */
584
585
int macio_request_resource(struct macio_dev *dev, int resource_no,
			   const char *name)
Linus Torvalds's avatar
Linus Torvalds committed
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
{
	if (macio_resource_len(dev, resource_no) == 0)
		return 0;
		
	if (!request_mem_region(macio_resource_start(dev, resource_no),
				macio_resource_len(dev, resource_no),
				name))
		goto err_out;
	
	return 0;

err_out:
	printk (KERN_WARNING "MacIO: Unable to reserve resource #%d:%lx@%lx"
		" for device %s\n",
		resource_no,
		macio_resource_len(dev, resource_no),
		macio_resource_start(dev, resource_no),
		dev->ofdev.dev.bus_id);
	return -EBUSY;
}

/**
 * macio_release_resource - Release an MMIO resource
 * @dev: pointer to the device holding the resource
 * @resource_no: resource number to release
 */
void macio_release_resource(struct macio_dev *dev, int resource_no)
{
	if (macio_resource_len(dev, resource_no) == 0)
		return;
	release_mem_region(macio_resource_start(dev, resource_no),
			   macio_resource_len(dev, resource_no));
}

/**
 *	macio_request_resources - Reserve all memory resources
 *	@dev: MacIO device whose resources are to be reserved
 *	@name: Name to be associated with resource.
 *
 *	Mark all memory regions associated with MacIO device @dev as
 *	being reserved by owner @name.  Do not access any address inside
 *	the memory regions unless this call returns successfully.
 *
 *	Returns 0 on success, or %EBUSY on error.  A warning
 *	message is also printed on failure.
 */
int macio_request_resources(struct macio_dev *dev, const char *name)
{
	int i;
	
	for (i = 0; i < dev->n_resources; i++)
		if (macio_request_resource(dev, i, name))
			goto err_out;
	return 0;

err_out:
	while(--i >= 0)
		macio_release_resource(dev, i);
		
	return -EBUSY;
}

/**
 *	macio_release_resources - Release reserved memory resources
 *	@dev: MacIO device whose resources were previously reserved
 */

void macio_release_resources(struct macio_dev *dev)
{
	int i;
	
	for (i = 0; i < dev->n_resources; i++)
		macio_release_resource(dev, i);
}


#ifdef CONFIG_PCI

static int __devinit macio_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
	struct device_node* np;
	struct macio_chip* chip;
	
	if (ent->vendor != PCI_VENDOR_ID_APPLE)
		return -ENODEV;

672
673
	/* Note regarding refcounting: We assume pci_device_to_OF_node() is
	 * ported to new OF APIs and returns a node with refcount incremented.
Linus Torvalds's avatar
Linus Torvalds committed
674
675
676
677
678
	 */
	np = pci_device_to_OF_node(pdev);
	if (np == NULL)
		return -ENODEV;

679
680
681
	/* The above assumption is wrong !!!
	 * fix that here for now until I fix the arch code
	 */
Linus Torvalds's avatar
Linus Torvalds committed
682
683
	of_node_get(np);

684
685
	/* We also assume that pmac_feature will have done a get() on nodes
	 * stored in the macio chips array
Linus Torvalds's avatar
Linus Torvalds committed
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
	 */
	chip = macio_find(np, macio_unknown);
       	of_node_put(np);
	if (chip == NULL)
		return -ENODEV;

	/* XXX Need locking ??? */
	if (chip->lbus.pdev == NULL) {
		chip->lbus.pdev = pdev;
		chip->lbus.chip = chip;
		pci_set_drvdata(pdev, &chip->lbus);
		pci_set_master(pdev);
	}

	printk(KERN_INFO "MacIO PCI driver attached to %s chipset\n",
		chip->name);

	/*
	 * HACK ALERT: The WallStreet PowerBook and some OHare based machines
705
706
707
	 * have 2 macio ASICs. I must probe the "main" one first or IDE
	 * ordering will be incorrect. So I put on "hold" the second one since
	 * it seem to appear first on PCI
Linus Torvalds's avatar
Linus Torvalds committed
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
	 */
	if (chip->type == macio_gatwick || chip->type == macio_ohareII)
		if (macio_chips[0].lbus.pdev == NULL) {
			macio_on_hold = chip;
			return 0;
		}

	macio_pci_add_devices(chip);
	if (macio_on_hold && macio_chips[0].lbus.pdev != NULL) {
		macio_pci_add_devices(macio_on_hold);
		macio_on_hold = NULL;
	}

	return 0;
}

static void __devexit macio_pci_remove(struct pci_dev* pdev)
{
	panic("removing of macio-asic not supported !\n");
}

/*
 * MacIO is matched against any Apple ID, it's probe() function
 * will then decide wether it applies or not
 */
static const struct pci_device_id __devinitdata pci_ids [] = { {
	.vendor		= PCI_VENDOR_ID_APPLE,
	.device		= PCI_ANY_ID,
	.subvendor	= PCI_ANY_ID,
	.subdevice	= PCI_ANY_ID,

	}, { /* end: all zeroes */ }
};
MODULE_DEVICE_TABLE (pci, pci_ids);

/* pci driver glue; this is a "new style" PCI driver module */
static struct pci_driver macio_pci_driver = {
	.name		= (char *) "macio",
	.id_table	= pci_ids,

	.probe		= macio_pci_probe,
	.remove		= macio_pci_remove,
};

#endif /* CONFIG_PCI */

static int __init macio_module_init (void) 
{
#ifdef CONFIG_PCI
	int rc;

	rc = pci_register_driver(&macio_pci_driver);
	if (rc)
		return rc;
#endif /* CONFIG_PCI */
	return 0;
}

module_init(macio_module_init);

EXPORT_SYMBOL(macio_register_driver);
EXPORT_SYMBOL(macio_unregister_driver);
EXPORT_SYMBOL(macio_dev_get);
EXPORT_SYMBOL(macio_dev_put);
EXPORT_SYMBOL(macio_request_resource);
EXPORT_SYMBOL(macio_release_resource);
EXPORT_SYMBOL(macio_request_resources);
EXPORT_SYMBOL(macio_release_resources);