1 /*======================================================================
3 A utility for reconfiguring PnP BIOS devices
5 setpnp.c 1.11 2006/07/06 15:27:55 MDT
7 The initial developer of the original code is David A. Hinds
8 <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
9 are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
11 (c) Copyright 2006 Hewlett-Packard Development Company, L.P.
12 Bjorn Helgaas <bjorn.helgaas@hp.com>
14 This program is free software; you can redistribute it and/or modify
15 it under the terms of the GNU General Public License version 2 as
16 published by the Free Software Foundation.
20 setpnp [-b] [device #] [resource list]
21 setpnp [-b] [device #] {on|off}
23 The device number is a two-digit hex string. The resource list
24 consists of a series of resource names and values. Four resource
25 names are available: "io", "mem", "irq", and "dma". Values can
26 either be single numbers or dash-delimited ranges. More than one
27 value can be listed in a single argument, separated by commas.
31 setpnp 0d irq 3 io 0x02f8-0x02ff
33 ======================================================================*/
42 #include <asm/types.h>
44 #include "pnp_resource.h"
46 static int verbose = 0, boot = 0;
48 #define swap16(n) ((((n)&0x00ff)<<8) | (((n)&0xff00)>>8))
50 ((((n)&0xff000000)>>24) | (((n)&0x00ff0000)>>8) | \
51 (((n)&0x0000ff00)<<8) | (((n)&0x000000ff)<<24))
53 #if (__BYTE_ORDER == _BIG_ENDIAN)
54 #define flip16(n) swap16(n)
55 #define flip32(n) swap32(n)
70 u_long base[NRSRC][NBASE];
71 u_long len[NRSRC][NBASE];
74 static const char *rsrc_type[] = { "io", "mem", "irq", "dma" };
76 /*====================================================================*/
78 static u_char *update_chain(u_char *buf, int nr, struct rsrc_list *res)
80 union pnp_resource *p = (union pnp_resource *)buf;
81 int tag = 0, sz, nu[4];
84 nu[0] = nu[1] = nu[2] = nu[3] = 0;
85 while (((u_char *)p < buf+nr) && (tag != PNP_RES_SMTAG_END)) {
86 if (p->lg.tag & PNP_RES_LARGE_ITEM) {
87 union pnp_large_resource *r = &p->lg.d;
88 tag = p->lg.tag & ~PNP_RES_LARGE_ITEM;
89 sz = flip16(p->lg.sz) + 2;
91 case PNP_RES_LGTAG_MEM:
92 if (res->nr[R_MEM] > nu[R_MEM]) {
93 base = res->base[R_MEM][nu[R_MEM]++];
94 len = res->len[R_MEM][nu[R_MEM]++];
95 r->mem.min = r->mem.max = flip16(base >> 8);
96 r->mem.len = flip16(len);
99 case PNP_RES_LGTAG_MEM32:
100 if (res->nr[R_MEM] > nu[R_MEM]) {
101 base = res->base[R_MEM][nu[R_MEM]++];
102 len = res->len[R_MEM][nu[R_MEM]++];
103 r->mem32.min = r->mem32.max = flip32(base);
104 r->mem32.len = flip32(len);
107 case PNP_RES_LGTAG_MEM32_FIXED:
108 if (res->nr[R_MEM] > nu[R_MEM]) {
109 base = res->base[R_MEM][nu[R_MEM]];
110 len = res->len[R_MEM][nu[R_MEM]++];
111 r->mem32_fixed.base = flip32(base);
112 r->mem32_fixed.len = flip32(len);
117 union pnp_small_resource *r = &p->sm.d;
118 tag = (p->sm.tag >> 3); sz = (p->sm.tag & 7);
120 case PNP_RES_SMTAG_IRQ:
121 if (res->nr[R_IRQ] > nu[R_IRQ]) {
122 base = res->base[R_IRQ][nu[R_IRQ]];
123 len = res->len[R_IRQ][nu[R_IRQ]++];
124 r->irq.mask = len ? flip16(1<<base) : 0;
127 case PNP_RES_SMTAG_DMA:
128 if (res->nr[R_DMA] > nu[R_DMA]) {
129 base = res->base[R_DMA][nu[R_DMA]];
130 len = res->len[R_DMA][nu[R_DMA]++];
131 r->dma.mask = len ? flip16(1<<base) : 0;
134 case PNP_RES_SMTAG_IO:
135 if (res->nr[R_IO] > nu[R_IO]) {
136 base = res->base[R_IO][nu[R_IO]];
137 len = res->len[R_IO][nu[R_IO]++];
138 r->io.min = r->io.max = flip16(base);
142 case PNP_RES_SMTAG_IO_FIXED:
143 if (res->nr[R_IO] > nu[R_IO]) {
144 base = res->base[R_IO][nu[R_IO]++];
145 len = res->len[R_IO][nu[R_IO]++];
146 r->io_fixed.base = flip16(base);
147 r->io_fixed.len = len;
152 p = (union pnp_resource *) ((u_char *)p + sz + 1);
157 static int update_resources(int num, struct rsrc_list *res)
163 if (access("/proc/bus/pnp", F_OK) != 0) {
164 fprintf(stderr, "lspnp: /proc/bus/pnp not available\n");
168 sprintf(fn, "/proc/bus/pnp/%s%02x", (boot ? "boot/" : ""), num);
169 fd = open(fn, O_RDWR);
170 nr = read(fd, buf, sizeof(buf));
172 perror("read failed");
176 update_chain(buf, nr, res);
177 nw = write(fd, buf, nr);
180 perror("write failed");
186 static int reset_resources(int num)
192 if (access("/proc/bus/pnp", F_OK) != 0) {
193 fprintf(stderr, "lspnp: /proc/bus/pnp not available\n");
196 sprintf(fn, "/proc/bus/pnp/boot/%02x", num);
197 fd = open(fn, O_RDONLY);
198 nr = read(fd, buf, sizeof(buf));
201 perror("read failed");
204 sprintf(fn, "/proc/bus/pnp/%02x", num);
205 fd = open(fn, O_WRONLY);
206 nw = write(fd, buf, nr);
209 perror("write failed");
215 /*====================================================================*/
217 static int parse_resources(char *argv[], int argc,
218 struct rsrc_list *res)
224 for (i = 0; i < argc; i += 2) {
225 for (j = 0; j < NRSRC; j++)
226 if (strcmp(rsrc_type[j], argv[i]) == 0) break;
228 fprintf(stderr, "bad resource type: '%s'\n", argv[i]);
231 s = strtok(argv[i+1], ", \t");
233 if (strcmp(s, "off") == 0) {
237 base = strtoul(s, &t, 0);
238 len = ((*t == '-') ? strtoul(t+1, &t, 0)-base+1 : 1);
240 if ((*s == '\0') || (*t != '\0')) {
241 fprintf(stderr, "bad resource argument: '%s'\n", t);
244 res->base[j][res->nr[j]] = base;
245 res->len[j][res->nr[j]++] = len;
246 s = strtok(NULL, ", \t");
252 /*====================================================================*/
254 void usage(char *name)
256 fprintf(stderr, "usage: %s [-b] [device #] [resources ...]\n"
257 " or %s [-b] [device #] {on|off}\n", name, name);
261 int main(int argc, char *argv[])
263 int i, optch, errflg = 0;
264 static struct rsrc_list res;
267 while ((optch = getopt(argc, argv, "bv")) != -1) {
277 if (errflg || (optind == argc))
280 i = strtoul(argv[optind], &s, 16);
281 if ((argv[optind] == '\0') || (*s != '\0'))
285 /* Special commands */
286 if (argc == optind+1) {
287 if (strcmp(argv[optind], "off") == 0) {
288 res.nr[0] = res.nr[1] = res.nr[2] = res.nr[3] = 7;
290 } else if (strcmp(argv[optind], "on") == 0) {
291 return reset_resources(i);
295 } else if (argc == optind)
298 if ((argc - optind) % 2)
300 if (parse_resources(argv+optind, argc-optind, &res) == 0)
301 return update_resources(i, &res);