14
* @defgroup PROMint PROM information (PowerPC)
15
* @ingroup libhdINFOint
16
* @brief PowerPC PROM information
18
* Note: make sure that hd_scan_sysfs_pci() has been run!
25
static devtree_t *add_devtree_entry(devtree_t **devtree, devtree_t *new);
26
static devtree_t *new_devtree_entry(devtree_t *parent);
27
static void read_str(char *path, char *name, char **str);
28
static void read_mem(char *path, char *name, unsigned char **mem, unsigned len);
29
static void read_int(char *path, char *name, int *val);
30
static void read_devtree(hd_data_t *hd_data);
31
static void add_pci_prom_devices(hd_data_t *hd_data, hd_t *hd_parent, devtree_t *parent);
32
static void add_legacy_prom_devices(hd_data_t *hd_data, devtree_t *dt);
33
static int add_prom_display(hd_data_t *hd_data, devtree_t *dt);
34
static void add_devices(hd_data_t *hd_data);
35
static void dump_devtree_data(hd_data_t *hd_data);
37
static unsigned veth_cnt, vscsi_cnt;
39
int detect_smp_prom(hd_data_t *hd_data)
44
if(!(devtree = hd_data->devtree)) return -1; /* hd_scan_prom() not called */
46
for(cpus = 0; devtree; devtree = devtree->next) {
47
if(devtree->device_type && !strcmp(devtree->device_type, "cpu")) cpus++;
50
return cpus > 1 ? cpus : 0;
53
void hd_scan_prom(hd_data_t *hd_data)
56
unsigned char buf[16];
60
if(!hd_probe_feature(hd_data, pr_prom)) return;
62
hd_data->module = mod_prom;
65
remove_hd_entries(hd_data);
66
hd_data->devtree = free_devtree(hd_data);
68
veth_cnt = vscsi_cnt = 0;
70
PROGRESS(1, 0, "devtree");
72
read_devtree(hd_data);
73
if(hd_data->debug) dump_devtree_data(hd_data);
76
PROGRESS(2, 0, "color");
78
hd = add_hd_entry(hd_data, __LINE__, 0);
79
hd->base_class.id = bc_internal;
80
hd->sub_class.id = sc_int_prom;
81
hd->detail = new_mem(sizeof *hd->detail);
82
hd->detail->type = hd_detail_prom;
83
hd->detail->prom.data = pt = new_mem(sizeof *pt);
85
if((f = fopen(PROC_PROM "/color-code", "r"))) {
86
if(fread(buf, 1, 2, f) == 2) {
89
hd_data->color_code = pt->color | 0x10000;
90
ADD2LOG("color-code: 0x%04x\n", (buf[0] << 8) + buf[1]);
98
/* store a device tree entry */
99
devtree_t *add_devtree_entry(devtree_t **devtree, devtree_t *new)
101
while(*devtree) devtree = &(*devtree)->next;
102
return *devtree = new;
105
/* create a new device tree entry */
106
devtree_t *new_devtree_entry(devtree_t *parent)
108
static unsigned idx = 0;
109
devtree_t *devtree = new_mem(sizeof *devtree);
112
devtree->idx = ++idx;
113
devtree->parent = parent;
115
devtree->interrupt = devtree->class_code =
116
devtree->device_id = devtree->vendor_id =
117
devtree->subdevice_id = devtree->subvendor_id =
118
devtree->revision_id = -1;
123
void read_str(char *path, char *name, char **str)
128
str_printf(&s, 0, "%s/%s", path, name);
129
if((sl = read_file(s, 0, 1))) {
132
sl = free_str_list(sl);
137
void read_mem(char *path, char *name, unsigned char **mem, unsigned len)
141
unsigned char *m = new_mem(len);
143
str_printf(&s, 0, "%s/%s", path, name);
144
if((f = fopen(s, "r"))) {
145
if(fread(m, len, 1, f) == 1) {
155
void read_int(char *path, char *name, int *val)
157
unsigned char *p = NULL;
159
read_mem(path, name, &p, sizeof (int));
160
if(p) memcpy(val, p, sizeof (int));
164
void read_devtree_entry(hd_data_t *hd_data, devtree_t *parent, char *dirname)
170
devtree_t *devtree, *dt2;
172
devtree = add_devtree_entry(&hd_data->devtree, new_devtree_entry(parent));
174
devtree->filename = new_str(dirname);
176
str_printf(&devtree->path, 0, "%s%s%s",
177
parent ? parent->path : "", parent && *parent->path ? "/" : "", dirname
181
str_printf(&path, 0, PROC_PROM "/%s", devtree->path);
183
if((dir = opendir(path))) {
184
while((de = readdir(dir))) {
185
if(!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) continue;
187
str_printf(&s, 0, "%s/%s", path, de->d_name);
188
if(!lstat(s, &sbuf)) {
189
if(S_ISDIR(sbuf.st_mode)) {
190
/* prom entries don't always have unique names, unfortunately... */
191
for(dt2 = hd_data->devtree; dt2; dt2 = dt2->next) {
193
dt2->parent == devtree &&
194
!strcmp(dt2->filename, de->d_name)
197
if(!dt2) read_devtree_entry(hd_data, devtree, de->d_name);
205
read_str(path, "name", &devtree->name);
206
read_str(path, "model", &devtree->model);
207
read_str(path, "device_type", &devtree->device_type);
208
read_str(path, "compatible", &devtree->compatible);
210
read_int(path, "interrupts", &devtree->interrupt);
211
read_int(path, "AAPL,interrupts", &devtree->interrupt);
212
read_int(path, "class-code", &devtree->class_code);
213
read_int(path, "vendor-id", &devtree->vendor_id);
214
read_int(path, "device-id", &devtree->device_id);
215
read_int(path, "subsystem-vendor-id", &devtree->subvendor_id);
216
read_int(path, "subsystem-id", &devtree->subdevice_id);
217
read_int(path, "revision-id", &devtree->revision_id);
219
read_mem(path, "EDID", &devtree->edid, 0x80);
220
if(!devtree->edid) read_mem(path, "DFP,EDID", &devtree->edid, 0x80);
221
if(!devtree->edid) read_mem(path, "LCD,EDID", &devtree->edid, 0x80);
224
devtree->class_code != -1 && devtree->vendor_id != -1 &&
225
devtree->device_id != -1
230
path = free_mem(path);
233
void read_devtree(hd_data_t *hd_data)
235
read_devtree_entry(hd_data, NULL, "");
239
void add_pci_prom_devices(hd_data_t *hd_data, hd_t *hd_parent, devtree_t *parent)
244
int irq, floppy_ctrl_idx;
245
unsigned sound_ok = 0, net_ok = 0, scsi_ok = 0;
249
for(dt = hd_data->devtree; dt; dt = dt->next) {
251
dt->parent == parent ||
253
/* special magic to reach some sound chips */
255
dt->parent->parent == parent &&
262
(!strcmp(dt->device_type, "block") || !strcmp(dt->device_type, "swim3"))
266
s = dt->compatible ? dt->compatible : dt->name;
270
if(strstr(s, "swim3")) {
271
id = MAKE_ID(TAG_SPECIAL, 0x0040);
276
hd = add_hd_entry(hd_data, __LINE__, 0);
277
hd->bus.id = bus_none;
278
hd->base_class.id = bc_storage;
279
hd->sub_class.id = sc_sto_floppy;
281
hd->vendor.id = MAKE_ID(TAG_SPECIAL, 0x0401);
283
hd->attached_to = hd_parent->idx;
284
hd->rom_id = new_str(dt->path);
286
res = add_res_entry(&hd->res, new_mem(sizeof *res));
287
res->irq.type = res_irq;
288
res->irq.enabled = 1;
289
res->irq.base = dt->interrupt;
291
floppy_ctrl_idx = hd->idx;
293
hd = add_hd_entry(hd_data, __LINE__, 0);
294
hd->base_class.id = bc_storage_device;
295
hd->sub_class.id = sc_sdev_floppy;
296
hd->bus.id = bus_floppy;
297
hd->unix_dev_name = new_str("/dev/fd0");
299
res = add_res_entry(&hd->res, new_mem(sizeof *res));
300
res->size.type = res_size;
301
res->size.val1 = str2float("3.5", 2);
302
res->size.unit = size_unit_cinch;
304
res = add_res_entry(&hd->res, new_mem(sizeof *res));
305
res->size.type = res_size;
306
res->size.val1 = 2880;
307
res->size.val2 = 0x200;
308
res->size.unit = size_unit_sectors;
310
hd->attached_to = floppy_ctrl_idx;
317
!strcmp(dt->device_type, "scsi")
320
scsi_ok = 1; /* max. 1 controller */
322
s = dt->compatible ? dt->compatible : dt->name;
326
if(strstr(s, "mesh")) { /* mesh || chrp,mesh0 */
327
id = MAKE_ID(TAG_SPECIAL, 0x0030);
329
else if(!strcmp(s, "53c94")) {
330
id = MAKE_ID(TAG_SPECIAL, 0x0031);
335
hd = add_hd_entry(hd_data, __LINE__, 0);
336
hd->bus.id = bus_none;
337
hd->base_class.id = bc_storage;
338
hd->sub_class.id = sc_sto_scsi;
340
hd->vendor.id = MAKE_ID(TAG_SPECIAL, 0x0401);
342
hd->attached_to = hd_parent->idx;
343
hd->rom_id = new_str(dt->path);
345
res = add_res_entry(&hd->res, new_mem(sizeof *res));
346
res->irq.type = res_irq;
347
res->irq.enabled = 1;
348
res->irq.base = dt->interrupt;
356
!strcmp(dt->device_type, "network")
359
net_ok = 1; /* max. 1 controller */
361
s = dt->compatible ? dt->compatible : dt->name;
365
if(!strcmp(s, "mace")) {
366
id = MAKE_ID(TAG_SPECIAL, 0x0020);
368
else if(!strcmp(s, "bmac")) {
369
id = MAKE_ID(TAG_SPECIAL, 0x0021);
371
else if(!strcmp(s, "bmac+")) {
372
id = MAKE_ID(TAG_SPECIAL, 0x0022);
377
hd = add_hd_entry(hd_data, __LINE__, 0);
378
hd->bus.id = bus_none;
379
hd->base_class.id = bc_network;
380
hd->sub_class.id = 0; /* ethernet */
382
hd->vendor.id = MAKE_ID(TAG_SPECIAL, 0x0401);
384
hd->attached_to = hd_parent->idx;
385
hd->rom_id = new_str(dt->path);
387
res = add_res_entry(&hd->res, new_mem(sizeof *res));
388
res->irq.type = res_irq;
389
res->irq.enabled = 1;
390
res->irq.base = dt->interrupt;
398
strstr(dt->device_type, "sound") == dt->device_type
401
sound_ok = 1; /* max 1 controller */
403
for(dt2 = dt; dt2; dt2 = dt2->next) {
407
(dt2->parent && dt2->parent == dt)
410
!strcmp(dt2->device_type, "sound") ||
411
!strcmp(dt2->device_type, "soundchip")
417
hd = add_hd_entry(hd_data, __LINE__, 0);
418
hd->bus.id = bus_none;
419
hd->base_class.id = bc_multimedia;
420
hd->sub_class.id = sc_multi_audio;
421
hd->attached_to = hd_parent->idx;
422
hd->rom_id = new_str(dt2->path);
423
irq = dt2->interrupt;
424
if(irq <= 1 && dt2->parent && !dt2->parent->pci) {
425
irq = dt2->parent->interrupt;
428
res = add_res_entry(&hd->res, new_mem(sizeof *res));
429
res->irq.type = res_irq;
430
res->irq.enabled = 1;
434
hd->vendor.id = MAKE_ID(TAG_SPECIAL, 0x401); /* Apple */
435
hd->device.id = MAKE_ID(TAG_SPECIAL, 0x0010);
437
if(dt2->compatible) {
438
if(!strcmp(dt2->compatible, "screamer")) {
439
hd->device.id = MAKE_ID(TAG_SPECIAL, 0x0011);
441
else if(!strcmp(dt2->compatible, "burgundy")) {
442
hd->device.id = MAKE_ID(TAG_SPECIAL, 0x0012);
444
else if(!strcmp(dt2->compatible, "daca")) {
445
hd->device.id = MAKE_ID(TAG_SPECIAL, 0x0013);
447
else if(!strcmp(dt2->compatible, "CRUS,CS4236B")) {
448
hd->vendor.id = MAKE_ID(TAG_SPECIAL, 0x402); /* IBM */
449
hd->device.id = MAKE_ID(TAG_SPECIAL, 0x0014);
458
void add_legacy_prom_devices(hd_data_t *hd_data, devtree_t *dt)
462
if(add_prom_display(hd_data, dt)) return;
465
int add_prom_display(hd_data_t *hd_data, devtree_t *dt)
473
!strcmp(dt->device_type, "display")
475
/* display devices */
480
if(!strcmp(dt->name, "valkyrie")) {
481
id = MAKE_ID(TAG_SPECIAL, 0x3000);
483
else if(!strcmp(dt->name, "platinum")) {
484
id = MAKE_ID(TAG_SPECIAL, 0x3001);
489
hd = add_hd_entry(hd_data, __LINE__, 0);
490
hd->bus.id = bus_none;
491
hd->base_class.id = bc_display;
492
hd->sub_class.id = sc_dis_other;
494
hd->vendor.id = MAKE_ID(TAG_SPECIAL, 0x0401);
496
hd->rom_id = new_str(dt->path);
498
res = add_res_entry(&hd->res, new_mem(sizeof *res));
499
res->irq.type = res_irq;
500
res->irq.enabled = 1;
501
res->irq.base = dt->interrupt;
511
void add_devices(hd_data_t *hd_data)
517
unsigned pci_slot = 0, u;
520
/* remove old assignments */
521
for(hd = hd_data->hd; hd; hd = hd->next) {
522
if(ID_TAG(hd->device.id) == TAG_PCI && ID_TAG(hd->vendor.id) == TAG_PCI) {
523
hd->rom_id = free_mem(hd->rom_id);
524
hd->detail = free_hd_detail(hd->detail);
528
for(dt = hd_data->devtree; dt; dt = dt->next) {
530
for(hd = hd_data->hd; hd; hd = hd->next) {
532
/* do *not* compare class ids */
533
/* It would be better to check the slot numbers instead but
534
* as they are not stored within /proc/device-tree in a consistent
535
* way, we can't do that.
538
ID_TAG(hd->device.id) == TAG_PCI &&
539
ID_TAG(hd->vendor.id) == TAG_PCI &&
540
ID_VALUE(hd->device.id) == dt->device_id &&
541
ID_VALUE(hd->vendor.id) == dt->vendor_id &&
542
(dt->subvendor_id == -1 || ID_VALUE(hd->sub_vendor.id) == dt->subvendor_id) &&
543
(dt->subdevice_id == -1 || ID_VALUE(hd->sub_device.id) == dt->subdevice_id) &&
544
hd->revision.id == dt->revision_id
549
hd->rom_id = new_str(dt->path);
550
hd->detail = new_mem(sizeof *hd->detail);
551
hd->detail->type = hd_detail_devtree;
552
hd->detail->devtree.data = dt;
553
add_pci_prom_devices(hd_data, hd, dt);
557
add_legacy_prom_devices(hd_data, dt);
562
void dump_devtree_data(hd_data_t *hd_data)
567
devtree = hd_data->devtree;
570
ADD2LOG("----- /proc device tree -----\n");
572
for(; devtree; devtree = devtree->next) {
573
u = devtree->parent ? devtree->parent->idx : 0;
574
ADD2LOG(" %02u @%02u %s", devtree->idx, u, devtree->path);
575
if(devtree->pci) ADD2LOG(" [pci]");
579
" name \"%s\", model \"%s\", dtype \"%s\", compat \"%s\"\n",
580
devtree->name ? devtree->name : "",
581
devtree->model ? devtree->model : "",
582
devtree->device_type ? devtree->device_type : "",
583
devtree->compatible ? devtree->compatible : ""
587
devtree->class_code != -1 || devtree->vendor_id != -1 ||
588
devtree->device_id != -1 || devtree->revision_id != -1 ||
589
devtree->subdevice_id != -1 || devtree->subvendor_id != -1 ||
590
devtree->interrupt != -1
593
if(devtree->class_code != -1) ADD2LOG(" class 0x%06x", devtree->class_code);
594
if(devtree->vendor_id != -1) ADD2LOG(" vend 0x%04x", devtree->vendor_id);
595
if(devtree->device_id != -1) ADD2LOG(" dev 0x%04x", devtree->device_id);
596
if(devtree->subvendor_id != -1) ADD2LOG(" svend 0x%04x", devtree->subvendor_id);
597
if(devtree->subdevice_id != -1) ADD2LOG(" sdev 0x%04x", devtree->subdevice_id);
598
if(devtree->revision_id != -1) ADD2LOG(" rev 0x%02x", devtree->revision_id);
599
if(devtree->interrupt != -1) ADD2LOG(" irq %d", devtree->interrupt);
604
ADD2LOG(" EDID record:\n");
605
for(u = 0; u < 0x80; u += 0x10) {
606
ADD2LOG(" %02x ", u);
607
hexdump(&hd_data->log, 1, 0x10, devtree->edid + u);
612
if(devtree->next) ADD2LOG("\n");
615
ADD2LOG("----- /proc device tree end -----\n");
618
#endif /* defined(__PPC__) */