1/*
2 * Copyright (c) 2013 ETH Zurich.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 * THE SOFTWARE.
21 */
22
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26#include <octopus/octopus.h>
27#include <barrelfish/barrelfish.h>
28#include <barrelfish/nameservice_client.h>
29
30#define OPT_HELP             0
31#define OPT_LIST_PCI         1
32#define OPT_LIST_HW          2
33#define OPT_LIST_ALL         3
34#define OPT_LIST_PATTERN     4
35
36
37struct opt_t {
38    const char *option;
39    const char *pattern;
40    const char *help;
41    int option_number;
42};
43
44/*
45 * Program options and help text.
46 */
47static struct opt_t option[] = {
48   { "-pci",  "r'hw\\.pci.'", "List all available PCI devices.", OPT_LIST_PCI },
49   { "-hw",   "r'hw\\.'",      "List all found hardware.",   OPT_LIST_HW },
50   { "-all",  "r'.*'",        "List all registered types.", OPT_LIST_ALL },
51   { "-free", 0,              "Use free search pattern.",   OPT_LIST_PATTERN },
52   { "-help", 0,              "Print this help.",             OPT_HELP },
53   { 0, 0, 0, 0 }
54};
55
56/**
57 *
58 */
59static int exit_help(const char *name)
60{
61    fprintf(stderr, "Usage: %s <[option] | [pattern]>\n", name);
62    fprintf(stderr, "options: \n");
63
64    for (int i = 0; option[i].option != 0; i++)
65        fprintf(stderr, "  %s    %s\n", option[i].option, option[i].help);
66
67    exit(1);
68}
69
70/**
71 *
72 */
73static void print_pci(const char *data)
74{
75    int pci, bus, class, device, device_id, function, prog_if, subclass, vendor;
76    int i = 0, retval = 0;
77
78    const char *supported_fmt[][2] = {
79        { /* PCI */
80          "hw.pci.device.%u { "
81          "bus: %u, class: %u, device: %u, "
82          "device_id: %u, function: %u, prog_if: %u, "
83          "subclass: %u, vendor: %u }", "pci"
84        },{ /* PCIe */
85          "hw.pcie.device.%u { "
86          "bus: %u, class: %u, device: %u, "
87          "device_id: %u, function: %u, prog_if: %u, "
88          "subclass: %u, vendor: %u }", "pcie"
89        },{ /* terminator */
90           0, 0
91        }
92    };
93
94    /* parse octopus device listing */
95    while (supported_fmt[i][0] != 0 && retval < 9) {
96        retval = sscanf(data, supported_fmt[i][0],
97                        &pci, &bus, &class, &device, &device_id,
98                        &function, &prog_if, &subclass, &vendor);
99        if (retval < 9)
100            i++;
101    }
102
103    if (retval >= 9) {
104        printf("hw.%s.device.%u { "
105               "bus: %u, class: 0x%x, device: 0x%x, "
106               "device_id: 0x%x, function: 0x%x, prog_if: %u, "
107               "subclass: 0x%x, vendor: 0x%x }\n",
108               supported_fmt[i][1], pci, bus, class, device, device_id,
109               function, prog_if, subclass, vendor);
110    } else {
111        printf("%s\n", data);
112    }
113}
114
115/**
116 *
117 */
118int main(int argc, char **argv)
119{
120    const char *pattern;
121    char **names;
122    errval_t err;
123    size_t size;
124    iref_t iref;
125    int opt = 0;
126
127    if (argc > 1) {
128        /* Get selected option */
129        for (opt = 0; option[opt].option != 0; opt++) {
130            if (strcmp(option[opt].option, argv[1]) == 0)
131                break;
132        }
133    }
134
135    if (option[opt].option_number == OPT_HELP)
136        exit_help(argv[0]);
137
138    pattern = option[opt].pattern;
139
140    if (option[opt].option_number == OPT_LIST_PATTERN) {
141        if (argc < 3)
142            exit_help(argv[0]);
143
144        pattern = argv[2];
145    }
146
147    err = nameservice_blocking_lookup("pci_discovery_done", &iref);
148    if (err_is_fail(err)) {
149        fprintf(stderr,
150                "Error: nameservice_blocking_lookup failed for pci_discovery_done.\n");
151        exit(err);
152    }
153
154    err = oct_init();
155    if (err_is_fail(err)) {
156        fprintf(stderr, "Error: oct_init failed.\n");
157        exit(err);
158    }
159
160    err = oct_get_names(&names, &size, pattern);
161    if (err) {
162        fprintf(stderr, "Error: oct_get_names failed.\n");
163        exit(err);
164    }
165
166    for (int i = 0; i < size; i++) {
167        char *data;
168
169        err = oct_get(&data, names[i]);
170        if (err) {
171            fprintf(stderr, "Error: oct_get failed.\n");
172            exit(err);
173        }
174
175        if (option[opt].option_number == OPT_LIST_PCI)
176            print_pci(data);
177        else
178            printf("%s\n", data);
179
180        free(data);
181    }
182
183    if (size)
184        oct_free_names(names, size);
185
186    return 0;
187}
188