]>
git.ipfire.org Git - people/stevee/ipfire-2.x.git/blob - src/hwinfo/src/hd/prom.c
13 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
16 * Note: make sure that hd_scan_sysfs_pci() has been run!
17 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
22 static devtree_t
*add_devtree_entry(devtree_t
**devtree
, devtree_t
*new);
23 static devtree_t
*new_devtree_entry(devtree_t
*parent
);
24 static void read_str(char *path
, char *name
, char **str
);
25 static void read_mem(char *path
, char *name
, unsigned char **mem
, unsigned len
);
26 static void read_int(char *path
, char *name
, int *val
);
27 static void read_devtree(hd_data_t
*hd_data
);
28 static void add_pci_prom_devices(hd_data_t
*hd_data
, hd_t
*hd_parent
, devtree_t
*parent
);
29 static void add_legacy_prom_devices(hd_data_t
*hd_data
, devtree_t
*dt
);
30 static int add_prom_display(hd_data_t
*hd_data
, devtree_t
*dt
);
31 static int add_prom_vscsi(hd_data_t
*hd_data
, devtree_t
*dt
);
32 static int add_prom_veth(hd_data_t
*hd_data
, devtree_t
*dt
);
33 static void add_devices(hd_data_t
*hd_data
);
34 static void dump_devtree_data(hd_data_t
*hd_data
);
36 static unsigned veth_cnt
, vscsi_cnt
;
38 int detect_smp_prom(hd_data_t
*hd_data
)
43 if(!(devtree
= hd_data
->devtree
)) return -1; /* hd_scan_prom() not called */
45 for(cpus
= 0; devtree
; devtree
= devtree
->next
) {
46 if(devtree
->device_type
&& !strcmp(devtree
->device_type
, "cpu")) cpus
++;
49 return cpus
> 1 ? cpus
: 0;
52 void hd_scan_prom(hd_data_t
*hd_data
)
55 unsigned char buf
[16];
59 if(!hd_probe_feature(hd_data
, pr_prom
)) return;
61 hd_data
->module
= mod_prom
;
64 remove_hd_entries(hd_data
);
65 hd_data
->devtree
= free_devtree(hd_data
);
67 veth_cnt
= vscsi_cnt
= 0;
69 PROGRESS(1, 0, "devtree");
71 read_devtree(hd_data
);
72 if(hd_data
->debug
) dump_devtree_data(hd_data
);
75 PROGRESS(2, 0, "color");
77 hd
= add_hd_entry(hd_data
, __LINE__
, 0);
78 hd
->base_class
.id
= bc_internal
;
79 hd
->sub_class
.id
= sc_int_prom
;
80 hd
->detail
= new_mem(sizeof *hd
->detail
);
81 hd
->detail
->type
= hd_detail_prom
;
82 hd
->detail
->prom
.data
= pt
= new_mem(sizeof *pt
);
84 if((f
= fopen(PROC_PROM
"/color-code", "r"))) {
85 if(fread(buf
, 1, 2, f
) == 2) {
88 hd_data
->color_code
= pt
->color
| 0x10000;
89 ADD2LOG("color-code: 0x%04x\n", (buf
[0] << 8) + buf
[1]);
97 /* store a device tree entry */
98 devtree_t
*add_devtree_entry(devtree_t
**devtree
, devtree_t
*new)
100 while(*devtree
) devtree
= &(*devtree
)->next
;
101 return *devtree
= new;
104 /* create a new device tree entry */
105 devtree_t
*new_devtree_entry(devtree_t
*parent
)
107 static unsigned idx
= 0;
108 devtree_t
*devtree
= new_mem(sizeof *devtree
);
111 devtree
->idx
= ++idx
;
112 devtree
->parent
= parent
;
114 devtree
->interrupt
= devtree
->class_code
=
115 devtree
->device_id
= devtree
->vendor_id
=
116 devtree
->subdevice_id
= devtree
->subvendor_id
=
117 devtree
->revision_id
= -1;
122 void read_str(char *path
, char *name
, char **str
)
127 str_printf(&s
, 0, "%s/%s", path
, name
);
128 if((sl
= read_file(s
, 0, 1))) {
131 sl
= free_str_list(sl
);
136 void read_mem(char *path
, char *name
, unsigned char **mem
, unsigned len
)
140 unsigned char *m
= new_mem(len
);
142 str_printf(&s
, 0, "%s/%s", path
, name
);
143 if((f
= fopen(s
, "r"))) {
144 if(fread(m
, len
, 1, f
) == 1) {
154 void read_int(char *path
, char *name
, int *val
)
156 unsigned char *p
= NULL
;
158 read_mem(path
, name
, &p
, sizeof (int));
159 if(p
) memcpy(val
, p
, sizeof (int));
163 void read_devtree_entry(hd_data_t
*hd_data
, devtree_t
*parent
, char *dirname
)
169 devtree_t
*devtree
, *dt2
;
171 devtree
= add_devtree_entry(&hd_data
->devtree
, new_devtree_entry(parent
));
173 devtree
->filename
= new_str(dirname
);
175 str_printf(&devtree
->path
, 0, "%s%s%s",
176 parent
? parent
->path
: "", parent
&& *parent
->path
? "/" : "", dirname
180 str_printf(&path
, 0, PROC_PROM
"/%s", devtree
->path
);
182 if((dir
= opendir(path
))) {
183 while((de
= readdir(dir
))) {
184 if(!strcmp(de
->d_name
, ".") || !strcmp(de
->d_name
, "..")) continue;
186 str_printf(&s
, 0, "%s/%s", path
, de
->d_name
);
187 if(!lstat(s
, &sbuf
)) {
188 if(S_ISDIR(sbuf
.st_mode
)) {
189 /* prom entries don't always have unique names, unfortunately... */
190 for(dt2
= hd_data
->devtree
; dt2
; dt2
= dt2
->next
) {
192 dt2
->parent
== devtree
&&
193 !strcmp(dt2
->filename
, de
->d_name
)
196 if(!dt2
) read_devtree_entry(hd_data
, devtree
, de
->d_name
);
204 read_str(path
, "name", &devtree
->name
);
205 read_str(path
, "model", &devtree
->model
);
206 read_str(path
, "device_type", &devtree
->device_type
);
207 read_str(path
, "compatible", &devtree
->compatible
);
209 read_int(path
, "interrupts", &devtree
->interrupt
);
210 read_int(path
, "AAPL,interrupts", &devtree
->interrupt
);
211 read_int(path
, "class-code", &devtree
->class_code
);
212 read_int(path
, "vendor-id", &devtree
->vendor_id
);
213 read_int(path
, "device-id", &devtree
->device_id
);
214 read_int(path
, "subsystem-vendor-id", &devtree
->subvendor_id
);
215 read_int(path
, "subsystem-id", &devtree
->subdevice_id
);
216 read_int(path
, "revision-id", &devtree
->revision_id
);
218 read_mem(path
, "EDID", &devtree
->edid
, 0x80);
219 if(!devtree
->edid
) read_mem(path
, "DFP,EDID", &devtree
->edid
, 0x80);
222 devtree
->class_code
!= -1 && devtree
->vendor_id
!= -1 &&
223 devtree
->device_id
!= -1
228 path
= free_mem(path
);
231 void read_devtree(hd_data_t
*hd_data
)
233 read_devtree_entry(hd_data
, NULL
, "");
237 void add_pci_prom_devices(hd_data_t
*hd_data
, hd_t
*hd_parent
, devtree_t
*parent
)
242 int irq
, floppy_ctrl_idx
;
243 unsigned sound_ok
= 0, net_ok
= 0, scsi_ok
= 0;
247 for(dt
= hd_data
->devtree
; dt
; dt
= dt
->next
) {
249 dt
->parent
== parent
||
251 /* special magic to reach some sound chips */
253 dt
->parent
->parent
== parent
&&
260 (!strcmp(dt
->device_type
, "block") || !strcmp(dt
->device_type
, "swim3"))
264 s
= dt
->compatible
? dt
->compatible
: dt
->name
;
268 if(strstr(s
, "swim3")) {
269 id
= MAKE_ID(TAG_SPECIAL
, 0x0040);
274 hd
= add_hd_entry(hd_data
, __LINE__
, 0);
275 hd
->bus
.id
= bus_none
;
276 hd
->base_class
.id
= bc_storage
;
277 hd
->sub_class
.id
= sc_sto_floppy
;
279 hd
->vendor
.id
= MAKE_ID(TAG_SPECIAL
, 0x0401);
281 hd
->attached_to
= hd_parent
->idx
;
282 hd
->rom_id
= new_str(dt
->path
);
284 res
= add_res_entry(&hd
->res
, new_mem(sizeof *res
));
285 res
->irq
.type
= res_irq
;
286 res
->irq
.enabled
= 1;
287 res
->irq
.base
= dt
->interrupt
;
289 floppy_ctrl_idx
= hd
->idx
;
291 hd
= add_hd_entry(hd_data
, __LINE__
, 0);
292 hd
->base_class
.id
= bc_storage_device
;
293 hd
->sub_class
.id
= sc_sdev_floppy
;
294 hd
->bus
.id
= bus_floppy
;
295 hd
->unix_dev_name
= new_str("/dev/fd0");
297 res
= add_res_entry(&hd
->res
, new_mem(sizeof *res
));
298 res
->size
.type
= res_size
;
299 res
->size
.val1
= str2float("3.5", 2);
300 res
->size
.unit
= size_unit_cinch
;
302 res
= add_res_entry(&hd
->res
, new_mem(sizeof *res
));
303 res
->size
.type
= res_size
;
304 res
->size
.val1
= 2880;
305 res
->size
.val2
= 0x200;
306 res
->size
.unit
= size_unit_sectors
;
308 hd
->attached_to
= floppy_ctrl_idx
;
315 !strcmp(dt
->device_type
, "scsi")
318 scsi_ok
= 1; /* max. 1 controller */
320 s
= dt
->compatible
? dt
->compatible
: dt
->name
;
324 if(strstr(s
, "mesh")) { /* mesh || chrp,mesh0 */
325 id
= MAKE_ID(TAG_SPECIAL
, 0x0030);
327 else if(!strcmp(s
, "53c94")) {
328 id
= MAKE_ID(TAG_SPECIAL
, 0x0031);
333 hd
= add_hd_entry(hd_data
, __LINE__
, 0);
334 hd
->bus
.id
= bus_none
;
335 hd
->base_class
.id
= bc_storage
;
336 hd
->sub_class
.id
= sc_sto_scsi
;
338 hd
->vendor
.id
= MAKE_ID(TAG_SPECIAL
, 0x0401);
340 hd
->attached_to
= hd_parent
->idx
;
341 hd
->rom_id
= new_str(dt
->path
);
343 res
= add_res_entry(&hd
->res
, new_mem(sizeof *res
));
344 res
->irq
.type
= res_irq
;
345 res
->irq
.enabled
= 1;
346 res
->irq
.base
= dt
->interrupt
;
354 !strcmp(dt
->device_type
, "network")
357 net_ok
= 1; /* max. 1 controller */
359 s
= dt
->compatible
? dt
->compatible
: dt
->name
;
363 if(!strcmp(s
, "mace")) {
364 id
= MAKE_ID(TAG_SPECIAL
, 0x0020);
366 else if(!strcmp(s
, "bmac")) {
367 id
= MAKE_ID(TAG_SPECIAL
, 0x0021);
369 else if(!strcmp(s
, "bmac+")) {
370 id
= MAKE_ID(TAG_SPECIAL
, 0x0022);
375 hd
= add_hd_entry(hd_data
, __LINE__
, 0);
376 hd
->bus
.id
= bus_none
;
377 hd
->base_class
.id
= bc_network
;
378 hd
->sub_class
.id
= 0; /* ethernet */
380 hd
->vendor
.id
= MAKE_ID(TAG_SPECIAL
, 0x0401);
382 hd
->attached_to
= hd_parent
->idx
;
383 hd
->rom_id
= new_str(dt
->path
);
385 res
= add_res_entry(&hd
->res
, new_mem(sizeof *res
));
386 res
->irq
.type
= res_irq
;
387 res
->irq
.enabled
= 1;
388 res
->irq
.base
= dt
->interrupt
;
396 strstr(dt
->device_type
, "sound") == dt
->device_type
399 sound_ok
= 1; /* max 1 controller */
401 for(dt2
= dt
; dt2
; dt2
= dt2
->next
) {
405 (dt2
->parent
&& dt2
->parent
== dt
)
408 !strcmp(dt2
->device_type
, "sound") ||
409 !strcmp(dt2
->device_type
, "soundchip")
415 hd
= add_hd_entry(hd_data
, __LINE__
, 0);
416 hd
->bus
.id
= bus_none
;
417 hd
->base_class
.id
= bc_multimedia
;
418 hd
->sub_class
.id
= sc_multi_audio
;
419 hd
->attached_to
= hd_parent
->idx
;
420 hd
->rom_id
= new_str(dt2
->path
);
421 irq
= dt2
->interrupt
;
422 if(irq
<= 1 && dt2
->parent
&& !dt2
->parent
->pci
) {
423 irq
= dt2
->parent
->interrupt
;
426 res
= add_res_entry(&hd
->res
, new_mem(sizeof *res
));
427 res
->irq
.type
= res_irq
;
428 res
->irq
.enabled
= 1;
432 hd
->vendor
.id
= MAKE_ID(TAG_SPECIAL
, 0x401); /* Apple */
433 hd
->device
.id
= MAKE_ID(TAG_SPECIAL
, 0x0010);
435 if(dt2
->compatible
) {
436 if(!strcmp(dt2
->compatible
, "screamer")) {
437 hd
->device
.id
= MAKE_ID(TAG_SPECIAL
, 0x0011);
439 else if(!strcmp(dt2
->compatible
, "burgundy")) {
440 hd
->device
.id
= MAKE_ID(TAG_SPECIAL
, 0x0012);
442 else if(!strcmp(dt2
->compatible
, "daca")) {
443 hd
->device
.id
= MAKE_ID(TAG_SPECIAL
, 0x0013);
445 else if(!strcmp(dt2
->compatible
, "CRUS,CS4236B")) {
446 hd
->vendor
.id
= MAKE_ID(TAG_SPECIAL
, 0x402); /* IBM */
447 hd
->device
.id
= MAKE_ID(TAG_SPECIAL
, 0x0014);
456 void add_legacy_prom_devices(hd_data_t
*hd_data
, devtree_t
*dt
)
460 if(add_prom_display(hd_data
, dt
)) return;
461 if(add_prom_vscsi(hd_data
, dt
)) return;
462 if(add_prom_veth(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 int add_prom_vscsi(hd_data_t
*hd_data
, devtree_t
*dt
)
519 !strcmp(dt
->device_type
, "vscsi")
524 (s
= strstr(dt
->path
, "v-scsi@")) &&
525 *(id
= s
+ sizeof "v-scsi@" - 1)
527 hd
= add_hd_entry(hd_data
, __LINE__
, 0);
528 hd
->bus
.id
= bus_none
;
529 hd
->base_class
.id
= bc_storage
;
530 hd
->sub_class
.id
= sc_sto_scsi
;
531 hd
->slot
= veth_cnt
++;
533 hd
->vendor
.id
= MAKE_ID(TAG_SPECIAL
, 0x6001);
534 hd
->device
.id
= MAKE_ID(TAG_SPECIAL
, 0x1001);
535 str_printf(&hd
->device
.name
, 0, "Virtual SCSI %d", hd
->slot
);
536 hd
->rom_id
= new_str(dt
->path
);
538 str_printf(&hd
->sysfs_id
, 0, "/devices/vio/%s", id
);
547 int add_prom_veth(hd_data_t
*hd_data
, devtree_t
*dt
)
556 !strcmp(dt
->device_type
, "network") &&
557 !strcmp(dt
->compatible
, "IBM,l-lan")
562 (s
= strstr(dt
->path
, "l-lan@")) &&
563 *(id
= s
+ sizeof "l-lan@" - 1)
565 hd
= add_hd_entry(hd_data
, __LINE__
, 0);
566 hd
->bus
.id
= bus_none
;
567 hd
->base_class
.id
= bc_network
;
568 hd
->sub_class
.id
= 0x00;
569 hd
->slot
= veth_cnt
++;
571 hd
->vendor
.id
= MAKE_ID(TAG_SPECIAL
, 0x6001);
572 hd
->device
.id
= MAKE_ID(TAG_SPECIAL
, 0x1002);
573 str_printf(&hd
->device
.name
, 0, "Virtual Ethernet card %d", hd
->slot
);
574 hd
->rom_id
= new_str(dt
->path
);
576 str_printf(&hd
->sysfs_id
, 0, "/devices/vio/%s", id
);
585 void add_devices(hd_data_t
*hd_data
)
591 unsigned pci_slot
= 0, u
;
594 /* remove old assignments */
595 for(hd
= hd_data
->hd
; hd
; hd
= hd
->next
) {
596 if(ID_TAG(hd
->device
.id
) == TAG_PCI
&& ID_TAG(hd
->vendor
.id
) == TAG_PCI
) {
597 hd
->rom_id
= free_mem(hd
->rom_id
);
598 hd
->detail
= free_hd_detail(hd
->detail
);
602 for(dt
= hd_data
->devtree
; dt
; dt
= dt
->next
) {
604 for(hd
= hd_data
->hd
; hd
; hd
= hd
->next
) {
606 /* do *not* compare class ids */
607 /* It would be better to check the slot numbers instead but
608 * as they are not stored within /proc/device-tree in a consistent
609 * way, we can't do that.
612 ID_TAG(hd
->device
.id
) == TAG_PCI
&&
613 ID_TAG(hd
->vendor
.id
) == TAG_PCI
&&
614 ID_VALUE(hd
->device
.id
) == dt
->device_id
&&
615 ID_VALUE(hd
->vendor
.id
) == dt
->vendor_id
&&
616 (dt
->subvendor_id
== -1 || ID_VALUE(hd
->sub_vendor
.id
) == dt
->subvendor_id
) &&
617 (dt
->subdevice_id
== -1 || ID_VALUE(hd
->sub_device
.id
) == dt
->subdevice_id
) &&
618 hd
->revision
.id
== dt
->revision_id
623 hd
->rom_id
= new_str(dt
->path
);
624 hd
->detail
= new_mem(sizeof *hd
->detail
);
625 hd
->detail
->type
= hd_detail_devtree
;
626 hd
->detail
->devtree
.data
= dt
;
627 add_pci_prom_devices(hd_data
, hd
, dt
);
631 add_legacy_prom_devices(hd_data
, dt
);
636 void dump_devtree_data(hd_data_t
*hd_data
)
641 devtree
= hd_data
->devtree
;
644 ADD2LOG("----- /proc device tree -----\n");
646 for(; devtree
; devtree
= devtree
->next
) {
647 u
= devtree
->parent
? devtree
->parent
->idx
: 0;
648 ADD2LOG(" %02u @%02u %s", devtree
->idx
, u
, devtree
->path
);
649 if(devtree
->pci
) ADD2LOG(" [pci]");
653 " name \"%s\", model \"%s\", dtype \"%s\", compat \"%s\"\n",
654 devtree
->name
? devtree
->name
: "",
655 devtree
->model
? devtree
->model
: "",
656 devtree
->device_type
? devtree
->device_type
: "",
657 devtree
->compatible
? devtree
->compatible
: ""
661 devtree
->class_code
!= -1 || devtree
->vendor_id
!= -1 ||
662 devtree
->device_id
!= -1 || devtree
->revision_id
!= -1 ||
663 devtree
->subdevice_id
!= -1 || devtree
->subvendor_id
!= -1 ||
664 devtree
->interrupt
!= -1
667 if(devtree
->class_code
!= -1) ADD2LOG(" class 0x%06x", devtree
->class_code
);
668 if(devtree
->vendor_id
!= -1) ADD2LOG(" vend 0x%04x", devtree
->vendor_id
);
669 if(devtree
->device_id
!= -1) ADD2LOG(" dev 0x%04x", devtree
->device_id
);
670 if(devtree
->subvendor_id
!= -1) ADD2LOG(" svend 0x%04x", devtree
->subvendor_id
);
671 if(devtree
->subdevice_id
!= -1) ADD2LOG(" sdev 0x%04x", devtree
->subdevice_id
);
672 if(devtree
->revision_id
!= -1) ADD2LOG(" rev 0x%02x", devtree
->revision_id
);
673 if(devtree
->interrupt
!= -1) ADD2LOG(" irq %d", devtree
->interrupt
);
678 ADD2LOG(" EDID record:\n");
679 for(u
= 0; u
< 0x80; u
+= 0x10) {
680 ADD2LOG(" %02x ", u
);
681 hexdump(&hd_data
->log
, 1, 0x10, devtree
->edid
+ u
);
686 if(devtree
->next
) ADD2LOG("\n");
689 ADD2LOG("----- /proc device tree end -----\n");
693 #endif /* defined(__PPC__) */