1 /* lspci.c - List PCI devices. */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2008, 2009 Free Software Foundation, Inc.
6 * GRUB is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * GRUB is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
22 #include <grub/misc.h>
23 #include <grub/extcmd.h>
26 #include <grub/i18n.h>
28 GRUB_MOD_LICENSE ("GPLv3+");
37 static struct pci_register pci_registers
[] =
39 {"VENDOR_ID", GRUB_PCI_REG_VENDOR
, 2},
40 {"DEVICE_ID", GRUB_PCI_REG_DEVICE
, 2},
41 {"COMMAND", GRUB_PCI_REG_COMMAND
, 2},
42 {"STATUS", GRUB_PCI_REG_STATUS
, 2},
43 {"REVISION", GRUB_PCI_REG_REVISION
, 1},
44 {"CLASS_PROG", GRUB_PCI_REG_CLASS
+ 1 , 1},
45 {"CLASS_DEVICE", GRUB_PCI_REG_CLASS
+ 2 , 2},
46 {"CACHE_LINE_SIZE", GRUB_PCI_REG_CACHELINE
, 1},
47 {"LATENCY_TIMER", GRUB_PCI_REG_LAT_TIMER
, 1},
48 {"HEADER_TYPE", GRUB_PCI_REG_HEADER_TYPE
, 1},
49 {"BIST", GRUB_PCI_REG_BIST
, 1},
50 {"BASE_ADDRESS_0", GRUB_PCI_REG_ADDRESS_REG0
, 4},
51 {"BASE_ADDRESS_1", GRUB_PCI_REG_ADDRESS_REG1
, 4},
52 {"BASE_ADDRESS_2", GRUB_PCI_REG_ADDRESS_REG2
, 4},
53 {"BASE_ADDRESS_3", GRUB_PCI_REG_ADDRESS_REG3
, 4},
54 {"BASE_ADDRESS_4", GRUB_PCI_REG_ADDRESS_REG4
, 4},
55 {"BASE_ADDRESS_5", GRUB_PCI_REG_ADDRESS_REG5
, 4},
56 {"CARDBUS_CIS", GRUB_PCI_REG_CIS_POINTER
, 4},
57 {"SUBVENDOR_ID", GRUB_PCI_REG_SUBVENDOR
, 2},
58 {"SUBSYSTEM_ID", GRUB_PCI_REG_SUBSYSTEM
, 2},
59 {"ROM_ADDRESS", GRUB_PCI_REG_ROM_ADDRESS
, 4},
60 {"CAP_POINTER", GRUB_PCI_REG_CAP_POINTER
, 1},
61 {"INTERRUPT_LINE", GRUB_PCI_REG_IRQ_LINE
, 1},
62 {"INTERRUPT_PIN", GRUB_PCI_REG_IRQ_PIN
, 1},
63 {"MIN_GNT", GRUB_PCI_REG_MIN_GNT
, 1},
64 {"MAX_LAT", GRUB_PCI_REG_MIN_GNT
, 1},
67 static const struct grub_arg_option options
[] =
69 {0, 'd', 0, N_("Select device by vendor and device IDs."),
70 N_("[vendor]:[device]"), ARG_TYPE_STRING
},
71 {0, 's', 0, N_("Select device by its position on the bus."),
72 N_("[bus]:[slot][.func]"), ARG_TYPE_STRING
},
73 {0, 'v', 0, N_("Save read value into variable VARNAME."),
74 N_("VARNAME"), ARG_TYPE_STRING
},
78 static grub_uint32_t pciid_check_mask
, pciid_check_value
;
79 static int bus
, device
, function
;
80 static int check_bus
, check_device
, check_function
;
81 static grub_uint32_t write_mask
, regwrite
;
83 static grub_uint16_t regaddr
;
84 static const char *varname
;
87 grub_setpci_iter (grub_pci_device_t dev
, grub_pci_id_t pciid
,
88 void *data
__attribute__ ((unused
)))
90 grub_uint32_t regval
= 0;
91 grub_pci_address_t addr
;
93 if ((pciid
& pciid_check_mask
) != pciid_check_value
)
96 if (check_bus
&& grub_pci_get_bus (dev
) != bus
)
99 if (check_device
&& grub_pci_get_device (dev
) != device
)
102 if (check_function
&& grub_pci_get_function (dev
) != function
)
105 addr
= grub_pci_make_address (dev
, regaddr
);
110 regval
= grub_pci_read_byte (addr
);
114 regval
= grub_pci_read_word (addr
);
118 regval
= grub_pci_read (addr
);
124 char buf
[sizeof ("XXXXXXXX")];
125 grub_snprintf (buf
, sizeof (buf
), "%x", regval
);
126 grub_env_set (varname
, buf
);
132 grub_printf (_("Register %x of %x:%02x.%x is %x\n"), regaddr
,
133 grub_pci_get_bus (dev
),
134 grub_pci_get_device (dev
),
135 grub_pci_get_function (dev
),
140 regval
= (regval
& ~write_mask
) | regwrite
;
145 grub_pci_write_byte (addr
, regval
);
149 grub_pci_write_word (addr
, regval
);
153 grub_pci_write (addr
, regval
);
161 grub_cmd_setpci (grub_extcmd_context_t ctxt
, int argc
, char **argv
)
166 pciid_check_value
= 0;
167 pciid_check_mask
= 0;
169 if (ctxt
->state
[0].set
)
171 ptr
= ctxt
->state
[0].arg
;
172 pciid_check_value
|= (grub_strtoul (ptr
, (char **) &ptr
, 16) & 0xffff);
173 if (grub_errno
== GRUB_ERR_BAD_NUMBER
)
175 grub_errno
= GRUB_ERR_NONE
;
176 ptr
= ctxt
->state
[0].arg
;
179 pciid_check_mask
|= 0xffff;
183 return grub_error (GRUB_ERR_BAD_ARGUMENT
, N_("missing `%c' symbol"), ':');
185 pciid_check_value
|= (grub_strtoul (ptr
, (char **) &ptr
, 16) & 0xffff)
187 if (grub_errno
== GRUB_ERR_BAD_NUMBER
)
188 grub_errno
= GRUB_ERR_NONE
;
190 pciid_check_mask
|= 0xffff0000;
193 pciid_check_value
&= pciid_check_mask
;
195 check_bus
= check_device
= check_function
= 0;
197 if (ctxt
->state
[1].set
)
201 ptr
= ctxt
->state
[1].arg
;
203 bus
= grub_strtoul (ptr
, (char **) &ptr
, 16);
204 if (grub_errno
== GRUB_ERR_BAD_NUMBER
)
206 grub_errno
= GRUB_ERR_NONE
;
214 return grub_error (GRUB_ERR_BAD_ARGUMENT
, N_("missing `%c' symbol"), ':');
217 device
= grub_strtoul (ptr
, (char **) &ptr
, 16);
218 if (grub_errno
== GRUB_ERR_BAD_NUMBER
)
220 grub_errno
= GRUB_ERR_NONE
;
228 function
= grub_strtoul (ptr
, (char **) &ptr
, 16);
235 if (ctxt
->state
[2].set
)
236 varname
= ctxt
->state
[2].arg
;
243 return grub_error (GRUB_ERR_BAD_ARGUMENT
, N_("one argument expected"));
247 for (i
= 0; i
< ARRAY_SIZE (pci_registers
); i
++)
249 if (grub_strncmp (ptr
, pci_registers
[i
].name
,
250 grub_strlen (pci_registers
[i
].name
)) == 0)
253 if (i
== ARRAY_SIZE (pci_registers
))
256 regaddr
= grub_strtoul (ptr
, (char **) &ptr
, 16);
258 return grub_error (GRUB_ERR_BAD_ARGUMENT
, "unknown register");
262 regaddr
= pci_registers
[i
].addr
;
263 regsize
= pci_registers
[i
].size
;
264 ptr
+= grub_strlen (pci_registers
[i
].name
);
273 regaddr
+= grub_strtoul (ptr
, (char **) &ptr
, 16);
278 if (grub_memcmp (ptr
, ".L", sizeof (".L") - 1) == 0
279 || grub_memcmp (ptr
, ".l", sizeof (".l") - 1) == 0)
282 ptr
+= sizeof (".l") - 1;
284 else if (grub_memcmp (ptr
, ".W", sizeof (".W") - 1) == 0
285 || grub_memcmp (ptr
, ".w", sizeof (".w") - 1) == 0)
288 ptr
+= sizeof (".w") - 1;
290 else if (grub_memcmp (ptr
, ".B", sizeof (".B") - 1) == 0
291 || grub_memcmp (ptr
, ".b", sizeof (".b") - 1) == 0)
294 ptr
+= sizeof (".b") - 1;
298 return grub_error (GRUB_ERR_BAD_ARGUMENT
,
299 "unknown register size");
305 regwrite
= grub_strtoul (ptr
, (char **) &ptr
, 16);
308 write_mask
= 0xffffffff;
312 write_mask
= grub_strtoul (ptr
, (char **) &ptr
, 16);
315 write_mask
= 0xffffffff;
317 regwrite
&= write_mask
;
320 if (write_mask
&& varname
)
321 return grub_error (GRUB_ERR_BAD_ARGUMENT
,
322 "option -v isn't valid for writes");
324 grub_pci_iterate (grub_setpci_iter
, NULL
);
325 return GRUB_ERR_NONE
;
328 static grub_extcmd_t cmd
;
330 GRUB_MOD_INIT(setpci
)
332 cmd
= grub_register_extcmd ("setpci", grub_cmd_setpci
, 0,
333 N_("[-s POSITION] [-d DEVICE] [-v VAR] "
334 "REGISTER[=VALUE[:MASK]]"),
335 N_("Manipulate PCI devices."), options
);
338 GRUB_MOD_FINI(setpci
)
340 grub_unregister_extcmd (cmd
);