Blame view
drivers/pnp/pnpbios/rsparser.c
16.7 KB
1da177e4c
|
1 2 |
/* * rsparser.c - parses and encodes pnpbios resource data streams |
1da177e4c
|
3 |
*/ |
1da177e4c
|
4 5 |
#include <linux/ctype.h> #include <linux/pnp.h> |
4e57b6817
|
6 7 |
#include <linux/string.h> #include <linux/slab.h> |
1da177e4c
|
8 9 10 11 |
#ifdef CONFIG_PCI #include <linux/pci.h> #else |
9dd78466c
|
12 13 14 |
inline void pcibios_penalize_isa_irq(int irq, int active) { } |
07d4e9af1
|
15 |
#endif /* CONFIG_PCI */ |
1da177e4c
|
16 |
|
772defc62
|
17 |
#include "../base.h" |
1da177e4c
|
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
#include "pnpbios.h" /* standard resource tags */ #define SMALL_TAG_PNPVERNO 0x01 #define SMALL_TAG_LOGDEVID 0x02 #define SMALL_TAG_COMPATDEVID 0x03 #define SMALL_TAG_IRQ 0x04 #define SMALL_TAG_DMA 0x05 #define SMALL_TAG_STARTDEP 0x06 #define SMALL_TAG_ENDDEP 0x07 #define SMALL_TAG_PORT 0x08 #define SMALL_TAG_FIXEDPORT 0x09 #define SMALL_TAG_VENDOR 0x0e #define SMALL_TAG_END 0x0f #define LARGE_TAG 0x80 #define LARGE_TAG_MEM 0x81 #define LARGE_TAG_ANSISTR 0x82 #define LARGE_TAG_UNICODESTR 0x83 #define LARGE_TAG_VENDOR 0x84 #define LARGE_TAG_MEM32 0x85 #define LARGE_TAG_FIXEDMEM32 0x86 /* * Resource Data Stream Format: * * Allocated Resources (required) * end tag -> * Resource Configuration Options (optional) * end tag -> * Compitable Device IDs (optional) * final end tag -> */ /* * Allocated Resources */ |
4ab55d8d4
|
54 |
static void pnpbios_parse_allocated_ioresource(struct pnp_dev *dev, |
cc8c2e308
|
55 |
int start, int len) |
1da177e4c
|
56 |
{ |
cc8c2e308
|
57 58 |
int flags = 0; int end = start + len - 1; |
06cb58a6e
|
59 |
|
cc8c2e308
|
60 61 |
if (len <= 0 || end >= 0x10003) flags |= IORESOURCE_DISABLED; |
07d4e9af1
|
62 |
|
cc8c2e308
|
63 |
pnp_add_io_resource(dev, start, end, flags); |
1da177e4c
|
64 |
} |
4ab55d8d4
|
65 |
static void pnpbios_parse_allocated_memresource(struct pnp_dev *dev, |
d6180f366
|
66 |
int start, int len) |
1da177e4c
|
67 |
{ |
d6180f366
|
68 69 70 71 72 73 74 |
int flags = 0; int end = start + len - 1; if (len <= 0) flags |= IORESOURCE_DISABLED; pnp_add_mem_resource(dev, start, end, flags); |
1da177e4c
|
75 |
} |
4ab55d8d4
|
76 77 78 |
static unsigned char *pnpbios_parse_allocated_resource_data(struct pnp_dev *dev, unsigned char *p, unsigned char *end) |
1da177e4c
|
79 80 |
{ unsigned int len, tag; |
dbddd0383
|
81 |
int io, size, mask, i, flags; |
1da177e4c
|
82 83 84 |
if (!p) return NULL; |
2f53432c2
|
85 86 |
pnp_dbg(&dev->dev, "parse allocated resources "); |
72dcc883d
|
87 |
|
f44900020
|
88 |
pnp_init_resources(dev); |
1da177e4c
|
89 90 91 92 |
while ((char *)p < (char *)end) { /* determine the type of tag */ |
9dd78466c
|
93 |
if (p[0] & LARGE_TAG) { /* large tag */ |
1da177e4c
|
94 95 |
len = (p[2] << 8) | p[1]; tag = p[0]; |
9dd78466c
|
96 |
} else { /* small tag */ |
1da177e4c
|
97 |
len = p[0] & 0x07; |
9dd78466c
|
98 |
tag = ((p[0] >> 3) & 0x0f); |
1da177e4c
|
99 100 101 102 103 104 105 |
} switch (tag) { case LARGE_TAG_MEM: if (len != 9) goto len_err; |
9dd78466c
|
106 107 |
io = *(short *)&p[4]; size = *(short *)&p[10]; |
4ab55d8d4
|
108 |
pnpbios_parse_allocated_memresource(dev, io, size); |
1da177e4c
|
109 110 111 112 113 114 115 116 117 118 119 120 121 |
break; case LARGE_TAG_ANSISTR: /* ignore this for now */ break; case LARGE_TAG_VENDOR: /* do nothing */ break; case LARGE_TAG_MEM32: if (len != 17) goto len_err; |
9dd78466c
|
122 123 |
io = *(int *)&p[4]; size = *(int *)&p[16]; |
4ab55d8d4
|
124 |
pnpbios_parse_allocated_memresource(dev, io, size); |
1da177e4c
|
125 126 127 128 129 |
break; case LARGE_TAG_FIXEDMEM32: if (len != 9) goto len_err; |
9dd78466c
|
130 131 |
io = *(int *)&p[4]; size = *(int *)&p[8]; |
4ab55d8d4
|
132 |
pnpbios_parse_allocated_memresource(dev, io, size); |
1da177e4c
|
133 134 135 136 137 |
break; case SMALL_TAG_IRQ: if (len < 2 || len > 3) goto len_err; |
dbddd0383
|
138 |
flags = 0; |
1da177e4c
|
139 |
io = -1; |
9dd78466c
|
140 141 142 143 |
mask = p[1] + p[2] * 256; for (i = 0; i < 16; i++, mask = mask >> 1) if (mask & 0x01) io = i; |
dbddd0383
|
144 145 146 147 148 |
if (io != -1) pcibios_penalize_isa_irq(io, 1); else flags = IORESOURCE_DISABLED; pnp_add_irq_resource(dev, io, flags); |
1da177e4c
|
149 150 151 152 153 |
break; case SMALL_TAG_DMA: if (len != 2) goto len_err; |
dc16f5f2e
|
154 |
flags = 0; |
1da177e4c
|
155 156 |
io = -1; mask = p[1]; |
9dd78466c
|
157 158 159 |
for (i = 0; i < 8; i++, mask = mask >> 1) if (mask & 0x01) io = i; |
dc16f5f2e
|
160 161 162 |
if (io == -1) flags = IORESOURCE_DISABLED; pnp_add_dma_resource(dev, io, flags); |
1da177e4c
|
163 164 165 166 167 |
break; case SMALL_TAG_PORT: if (len != 7) goto len_err; |
9dd78466c
|
168 |
io = p[2] + p[3] * 256; |
1da177e4c
|
169 |
size = p[7]; |
4ab55d8d4
|
170 |
pnpbios_parse_allocated_ioresource(dev, io, size); |
1da177e4c
|
171 172 173 174 175 176 177 178 179 180 181 |
break; case SMALL_TAG_VENDOR: /* do nothing */ break; case SMALL_TAG_FIXEDPORT: if (len != 3) goto len_err; io = p[1] + p[2] * 256; size = p[3]; |
4ab55d8d4
|
182 |
pnpbios_parse_allocated_ioresource(dev, io, size); |
1da177e4c
|
183 184 185 186 |
break; case SMALL_TAG_END: p = p + 2; |
9dd78466c
|
187 |
return (unsigned char *)p; |
1da177e4c
|
188 |
break; |
af901ca18
|
189 |
default: /* an unknown tag */ |
1e0aa9ad7
|
190 |
len_err: |
af11cb2d5
|
191 192 193 |
dev_err(&dev->dev, "unknown tag %#x length %d ", tag, len); |
1da177e4c
|
194 195 196 197 198 199 200 201 202 |
break; } /* continue to the next tag */ if (p[0] & LARGE_TAG) p += len + 3; else p += len + 1; } |
af11cb2d5
|
203 204 |
dev_err(&dev->dev, "no end tag in resource structure "); |
1da177e4c
|
205 206 207 |
return NULL; } |
1da177e4c
|
208 209 210 |
/* * Resource Configuration Options */ |
c1caf06cc
|
211 212 |
static __init void pnpbios_parse_mem_option(struct pnp_dev *dev, unsigned char *p, int size, |
1f32ca31e
|
213 |
unsigned int option_flags) |
1da177e4c
|
214 |
{ |
c227536b4
|
215 216 217 218 219 220 221 222 |
resource_size_t min, max, align, len; unsigned char flags; min = ((p[5] << 8) | p[4]) << 8; max = ((p[7] << 8) | p[6]) << 8; align = (p[9] << 8) | p[8]; len = ((p[11] << 8) | p[10]) << 8; flags = p[3]; |
1f32ca31e
|
223 224 |
pnp_register_mem_resource(dev, option_flags, min, max, align, len, flags); |
1da177e4c
|
225 |
} |
c1caf06cc
|
226 227 |
static __init void pnpbios_parse_mem32_option(struct pnp_dev *dev, unsigned char *p, int size, |
1f32ca31e
|
228 |
unsigned int option_flags) |
1da177e4c
|
229 |
{ |
c227536b4
|
230 231 232 233 234 235 236 237 |
resource_size_t min, max, align, len; unsigned char flags; min = (p[7] << 24) | (p[6] << 16) | (p[5] << 8) | p[4]; max = (p[11] << 24) | (p[10] << 16) | (p[9] << 8) | p[8]; align = (p[15] << 24) | (p[14] << 16) | (p[13] << 8) | p[12]; len = (p[19] << 24) | (p[18] << 16) | (p[17] << 8) | p[16]; flags = p[3]; |
1f32ca31e
|
238 239 |
pnp_register_mem_resource(dev, option_flags, min, max, align, len, flags); |
1da177e4c
|
240 |
} |
c1caf06cc
|
241 242 |
static __init void pnpbios_parse_fixed_mem32_option(struct pnp_dev *dev, unsigned char *p, int size, |
1f32ca31e
|
243 |
unsigned int option_flags) |
1da177e4c
|
244 |
{ |
c227536b4
|
245 246 247 248 249 250 |
resource_size_t base, len; unsigned char flags; base = (p[7] << 24) | (p[6] << 16) | (p[5] << 8) | p[4]; len = (p[11] << 24) | (p[10] << 16) | (p[9] << 8) | p[8]; flags = p[3]; |
1f32ca31e
|
251 |
pnp_register_mem_resource(dev, option_flags, base, base, 0, len, flags); |
1da177e4c
|
252 |
} |
c1caf06cc
|
253 254 |
static __init void pnpbios_parse_irq_option(struct pnp_dev *dev, unsigned char *p, int size, |
1f32ca31e
|
255 |
unsigned int option_flags) |
1da177e4c
|
256 |
{ |
1da177e4c
|
257 |
unsigned long bits; |
c227536b4
|
258 259 |
pnp_irq_mask_t map; unsigned char flags = IORESOURCE_IRQ_HIGHEDGE; |
1da177e4c
|
260 |
|
1da177e4c
|
261 |
bits = (p[2] << 8) | p[1]; |
c227536b4
|
262 263 264 |
bitmap_zero(map.bits, PNP_IRQ_NR); bitmap_copy(map.bits, &bits, 16); |
1da177e4c
|
265 |
if (size > 2) |
c227536b4
|
266 |
flags = p[3]; |
1f32ca31e
|
267 |
pnp_register_irq_resource(dev, option_flags, &map, flags); |
1da177e4c
|
268 |
} |
c1caf06cc
|
269 270 |
static __init void pnpbios_parse_dma_option(struct pnp_dev *dev, unsigned char *p, int size, |
1f32ca31e
|
271 |
unsigned int option_flags) |
1da177e4c
|
272 |
{ |
1f32ca31e
|
273 |
pnp_register_dma_resource(dev, option_flags, p[1], p[2]); |
1da177e4c
|
274 |
} |
c1caf06cc
|
275 276 |
static __init void pnpbios_parse_port_option(struct pnp_dev *dev, unsigned char *p, int size, |
1f32ca31e
|
277 |
unsigned int option_flags) |
1da177e4c
|
278 |
{ |
c227536b4
|
279 280 281 282 283 284 285 286 |
resource_size_t min, max, align, len; unsigned char flags; min = (p[3] << 8) | p[2]; max = (p[5] << 8) | p[4]; align = p[6]; len = p[7]; flags = p[1] ? IORESOURCE_IO_16BIT_ADDR : 0; |
1f32ca31e
|
287 288 |
pnp_register_port_resource(dev, option_flags, min, max, align, len, flags); |
1da177e4c
|
289 |
} |
c1caf06cc
|
290 291 |
static __init void pnpbios_parse_fixed_port_option(struct pnp_dev *dev, unsigned char *p, int size, |
1f32ca31e
|
292 |
unsigned int option_flags) |
1da177e4c
|
293 |
{ |
c227536b4
|
294 295 296 297 |
resource_size_t base, len; base = (p[2] << 8) | p[1]; len = p[3]; |
1f32ca31e
|
298 |
pnp_register_port_resource(dev, option_flags, base, base, 0, len, |
c227536b4
|
299 |
IORESOURCE_IO_FIXED); |
1da177e4c
|
300 |
} |
2bb9a6b32
|
301 302 |
static __init unsigned char * pnpbios_parse_resource_option_data(unsigned char *p, unsigned char *end, |
1f32ca31e
|
303 |
struct pnp_dev *dev) |
1da177e4c
|
304 305 |
{ unsigned int len, tag; |
e2a1a6f1c
|
306 |
int priority; |
1f32ca31e
|
307 |
unsigned int option_flags; |
1da177e4c
|
308 309 310 |
if (!p) return NULL; |
2f53432c2
|
311 312 |
pnp_dbg(&dev->dev, "parse resource options "); |
1f32ca31e
|
313 |
option_flags = 0; |
1da177e4c
|
314 315 316 |
while ((char *)p < (char *)end) { /* determine the type of tag */ |
9dd78466c
|
317 |
if (p[0] & LARGE_TAG) { /* large tag */ |
1da177e4c
|
318 319 |
len = (p[2] << 8) | p[1]; tag = p[0]; |
9dd78466c
|
320 |
} else { /* small tag */ |
1da177e4c
|
321 |
len = p[0] & 0x07; |
9dd78466c
|
322 |
tag = ((p[0] >> 3) & 0x0f); |
1da177e4c
|
323 324 325 326 327 328 329 |
} switch (tag) { case LARGE_TAG_MEM: if (len != 9) goto len_err; |
1f32ca31e
|
330 |
pnpbios_parse_mem_option(dev, p, len, option_flags); |
1da177e4c
|
331 332 333 334 335 |
break; case LARGE_TAG_MEM32: if (len != 17) goto len_err; |
1f32ca31e
|
336 |
pnpbios_parse_mem32_option(dev, p, len, option_flags); |
1da177e4c
|
337 338 339 340 341 |
break; case LARGE_TAG_FIXEDMEM32: if (len != 9) goto len_err; |
1f32ca31e
|
342 343 |
pnpbios_parse_fixed_mem32_option(dev, p, len, option_flags); |
1da177e4c
|
344 345 346 347 348 |
break; case SMALL_TAG_IRQ: if (len < 2 || len > 3) goto len_err; |
1f32ca31e
|
349 |
pnpbios_parse_irq_option(dev, p, len, option_flags); |
1da177e4c
|
350 351 352 353 354 |
break; case SMALL_TAG_DMA: if (len != 2) goto len_err; |
1f32ca31e
|
355 |
pnpbios_parse_dma_option(dev, p, len, option_flags); |
1da177e4c
|
356 357 358 359 360 |
break; case SMALL_TAG_PORT: if (len != 7) goto len_err; |
1f32ca31e
|
361 |
pnpbios_parse_port_option(dev, p, len, option_flags); |
1da177e4c
|
362 363 364 365 366 367 368 369 370 |
break; case SMALL_TAG_VENDOR: /* do nothing */ break; case SMALL_TAG_FIXEDPORT: if (len != 3) goto len_err; |
1f32ca31e
|
371 372 |
pnpbios_parse_fixed_port_option(dev, p, len, option_flags); |
1da177e4c
|
373 374 375 376 377 |
break; case SMALL_TAG_STARTDEP: if (len > 1) goto len_err; |
e2a1a6f1c
|
378 |
priority = PNP_RES_PRIORITY_ACCEPTABLE; |
1da177e4c
|
379 |
if (len > 0) |
e2a1a6f1c
|
380 |
priority = p[1]; |
1f32ca31e
|
381 |
option_flags = pnp_new_dependent_set(dev, priority); |
1da177e4c
|
382 383 384 385 386 |
break; case SMALL_TAG_ENDDEP: if (len != 0) goto len_err; |
1f32ca31e
|
387 |
option_flags = 0; |
1da177e4c
|
388 389 390 |
break; case SMALL_TAG_END: |
9dd78466c
|
391 |
return p + 2; |
1da177e4c
|
392 |
|
af901ca18
|
393 |
default: /* an unknown tag */ |
1e0aa9ad7
|
394 |
len_err: |
af11cb2d5
|
395 396 397 |
dev_err(&dev->dev, "unknown tag %#x length %d ", tag, len); |
1da177e4c
|
398 399 400 401 402 403 404 405 406 |
break; } /* continue to the next tag */ if (p[0] & LARGE_TAG) p += len + 3; else p += len + 1; } |
af11cb2d5
|
407 408 |
dev_err(&dev->dev, "no end tag in resource structure "); |
1da177e4c
|
409 410 411 |
return NULL; } |
1da177e4c
|
412 413 414 |
/* * Compatible Device IDs */ |
9dd78466c
|
415 416 417 |
static unsigned char *pnpbios_parse_compatible_ids(unsigned char *p, unsigned char *end, struct pnp_dev *dev) |
1da177e4c
|
418 419 |
{ int len, tag; |
25eb84618
|
420 |
u32 eisa_id; |
1da177e4c
|
421 422 423 424 425 426 427 428 429 |
char id[8]; struct pnp_id *dev_id; if (!p) return NULL; while ((char *)p < (char *)end) { /* determine the type of tag */ |
9dd78466c
|
430 |
if (p[0] & LARGE_TAG) { /* large tag */ |
1da177e4c
|
431 432 |
len = (p[2] << 8) | p[1]; tag = p[0]; |
9dd78466c
|
433 |
} else { /* small tag */ |
1da177e4c
|
434 |
len = p[0] & 0x07; |
9dd78466c
|
435 |
tag = ((p[0] >> 3) & 0x0f); |
1da177e4c
|
436 437 438 439 440 |
} switch (tag) { case LARGE_TAG_ANSISTR: |
9dd78466c
|
441 442 443 444 |
strncpy(dev->name, p + 3, len >= PNP_NAME_LEN ? PNP_NAME_LEN - 2 : len); dev->name[len >= PNP_NAME_LEN ? PNP_NAME_LEN - 1 : len] = '\0'; |
1da177e4c
|
445 |
break; |
9dd78466c
|
446 |
case SMALL_TAG_COMPATDEVID: /* compatible ID */ |
1da177e4c
|
447 448 |
if (len != 4) goto len_err; |
25eb84618
|
449 450 |
eisa_id = p[1] | p[2] << 8 | p[3] << 16 | p[4] << 24; pnp_eisa_id_to_string(eisa_id & PNP_EISA_ID_MASK, id); |
772defc62
|
451 452 453 |
dev_id = pnp_add_id(dev, id); if (!dev_id) return NULL; |
1da177e4c
|
454 455 456 457 |
break; case SMALL_TAG_END: p = p + 2; |
9dd78466c
|
458 |
return (unsigned char *)p; |
1da177e4c
|
459 |
break; |
af901ca18
|
460 |
default: /* an unknown tag */ |
1e0aa9ad7
|
461 |
len_err: |
af11cb2d5
|
462 463 464 |
dev_err(&dev->dev, "unknown tag %#x length %d ", tag, len); |
1da177e4c
|
465 466 467 468 469 470 471 472 473 |
break; } /* continue to the next tag */ if (p[0] & LARGE_TAG) p += len + 3; else p += len + 1; } |
af11cb2d5
|
474 475 |
dev_err(&dev->dev, "no end tag in resource structure "); |
1da177e4c
|
476 477 478 |
return NULL; } |
1da177e4c
|
479 480 481 |
/* * Allocated Resource Encoding */ |
72dcc883d
|
482 483 |
static void pnpbios_encode_mem(struct pnp_dev *dev, unsigned char *p, struct resource *res) |
1da177e4c
|
484 |
{ |
aee3ad815
|
485 486 487 488 489 490 491 492 493 494 |
unsigned long base; unsigned long len; if (pnp_resource_enabled(res)) { base = res->start; len = res->end - res->start + 1; } else { base = 0; len = 0; } |
07d4e9af1
|
495 |
|
1da177e4c
|
496 497 498 499 500 501 |
p[4] = (base >> 8) & 0xff; p[5] = ((base >> 8) >> 8) & 0xff; p[6] = (base >> 8) & 0xff; p[7] = ((base >> 8) >> 8) & 0xff; p[10] = (len >> 8) & 0xff; p[11] = ((len >> 8) >> 8) & 0xff; |
72dcc883d
|
502 |
|
2f53432c2
|
503 504 |
pnp_dbg(&dev->dev, " encode mem %#lx-%#lx ", base, base + len - 1); |
1da177e4c
|
505 |
} |
72dcc883d
|
506 507 |
static void pnpbios_encode_mem32(struct pnp_dev *dev, unsigned char *p, struct resource *res) |
1da177e4c
|
508 |
{ |
aee3ad815
|
509 510 511 512 513 514 515 516 517 518 |
unsigned long base; unsigned long len; if (pnp_resource_enabled(res)) { base = res->start; len = res->end - res->start + 1; } else { base = 0; len = 0; } |
07d4e9af1
|
519 |
|
1da177e4c
|
520 521 522 523 524 525 526 527 528 529 530 531 |
p[4] = base & 0xff; p[5] = (base >> 8) & 0xff; p[6] = (base >> 16) & 0xff; p[7] = (base >> 24) & 0xff; p[8] = base & 0xff; p[9] = (base >> 8) & 0xff; p[10] = (base >> 16) & 0xff; p[11] = (base >> 24) & 0xff; p[16] = len & 0xff; p[17] = (len >> 8) & 0xff; p[18] = (len >> 16) & 0xff; p[19] = (len >> 24) & 0xff; |
72dcc883d
|
532 |
|
2f53432c2
|
533 534 |
pnp_dbg(&dev->dev, " encode mem32 %#lx-%#lx ", base, base + len - 1); |
1da177e4c
|
535 |
} |
72dcc883d
|
536 537 |
static void pnpbios_encode_fixed_mem32(struct pnp_dev *dev, unsigned char *p, struct resource *res) |
9dd78466c
|
538 |
{ |
aee3ad815
|
539 540 541 542 543 544 545 546 547 548 |
unsigned long base; unsigned long len; if (pnp_resource_enabled(res)) { base = res->start; len = res->end - res->start + 1; } else { base = 0; len = 0; } |
07d4e9af1
|
549 |
|
1da177e4c
|
550 551 552 553 554 555 556 557 |
p[4] = base & 0xff; p[5] = (base >> 8) & 0xff; p[6] = (base >> 16) & 0xff; p[7] = (base >> 24) & 0xff; p[8] = len & 0xff; p[9] = (len >> 8) & 0xff; p[10] = (len >> 16) & 0xff; p[11] = (len >> 24) & 0xff; |
72dcc883d
|
558 |
|
2f53432c2
|
559 560 |
pnp_dbg(&dev->dev, " encode fixed_mem32 %#lx-%#lx ", base, |
aee3ad815
|
561 |
base + len - 1); |
1da177e4c
|
562 |
} |
72dcc883d
|
563 564 |
static void pnpbios_encode_irq(struct pnp_dev *dev, unsigned char *p, struct resource *res) |
1da177e4c
|
565 |
{ |
aee3ad815
|
566 567 568 569 570 571 |
unsigned long map; if (pnp_resource_enabled(res)) map = 1 << res->start; else map = 0; |
07d4e9af1
|
572 |
|
1da177e4c
|
573 574 |
p[1] = map & 0xff; p[2] = (map >> 8) & 0xff; |
72dcc883d
|
575 |
|
2f53432c2
|
576 577 |
pnp_dbg(&dev->dev, " encode irq mask %#lx ", map); |
1da177e4c
|
578 |
} |
72dcc883d
|
579 580 |
static void pnpbios_encode_dma(struct pnp_dev *dev, unsigned char *p, struct resource *res) |
1da177e4c
|
581 |
{ |
aee3ad815
|
582 583 584 585 586 587 |
unsigned long map; if (pnp_resource_enabled(res)) map = 1 << res->start; else map = 0; |
07d4e9af1
|
588 |
|
1da177e4c
|
589 |
p[1] = map & 0xff; |
72dcc883d
|
590 |
|
2f53432c2
|
591 592 |
pnp_dbg(&dev->dev, " encode dma mask %#lx ", map); |
1da177e4c
|
593 |
} |
72dcc883d
|
594 595 |
static void pnpbios_encode_port(struct pnp_dev *dev, unsigned char *p, struct resource *res) |
1da177e4c
|
596 |
{ |
aee3ad815
|
597 598 599 600 601 602 603 604 605 606 |
unsigned long base; unsigned long len; if (pnp_resource_enabled(res)) { base = res->start; len = res->end - res->start + 1; } else { base = 0; len = 0; } |
07d4e9af1
|
607 |
|
1da177e4c
|
608 609 610 611 612 |
p[2] = base & 0xff; p[3] = (base >> 8) & 0xff; p[4] = base & 0xff; p[5] = (base >> 8) & 0xff; p[7] = len & 0xff; |
72dcc883d
|
613 |
|
2f53432c2
|
614 615 |
pnp_dbg(&dev->dev, " encode io %#lx-%#lx ", base, base + len - 1); |
1da177e4c
|
616 |
} |
72dcc883d
|
617 618 |
static void pnpbios_encode_fixed_port(struct pnp_dev *dev, unsigned char *p, struct resource *res) |
1da177e4c
|
619 620 621 |
{ unsigned long base = res->start; unsigned long len = res->end - res->start + 1; |
07d4e9af1
|
622 |
|
aee3ad815
|
623 624 625 626 627 628 629 |
if (pnp_resource_enabled(res)) { base = res->start; len = res->end - res->start + 1; } else { base = 0; len = 0; } |
1da177e4c
|
630 631 632 |
p[1] = base & 0xff; p[2] = (base >> 8) & 0xff; p[3] = len & 0xff; |
72dcc883d
|
633 |
|
2f53432c2
|
634 635 |
pnp_dbg(&dev->dev, " encode fixed_io %#lx-%#lx ", base, |
aee3ad815
|
636 |
base + len - 1); |
1da177e4c
|
637 |
} |
4ab55d8d4
|
638 639 640 641 |
static unsigned char *pnpbios_encode_allocated_resource_data(struct pnp_dev *dev, unsigned char *p, unsigned char *end) |
1da177e4c
|
642 643 644 645 646 647 648 649 650 651 |
{ unsigned int len, tag; int port = 0, irq = 0, dma = 0, mem = 0; if (!p) return NULL; while ((char *)p < (char *)end) { /* determine the type of tag */ |
9dd78466c
|
652 |
if (p[0] & LARGE_TAG) { /* large tag */ |
1da177e4c
|
653 654 |
len = (p[2] << 8) | p[1]; tag = p[0]; |
9dd78466c
|
655 |
} else { /* small tag */ |
1da177e4c
|
656 |
len = p[0] & 0x07; |
9dd78466c
|
657 |
tag = ((p[0] >> 3) & 0x0f); |
1da177e4c
|
658 659 660 661 662 663 664 |
} switch (tag) { case LARGE_TAG_MEM: if (len != 9) goto len_err; |
7e2cf31f1
|
665 666 |
pnpbios_encode_mem(dev, p, pnp_get_resource(dev, IORESOURCE_MEM, mem)); |
1da177e4c
|
667 668 669 670 671 672 |
mem++; break; case LARGE_TAG_MEM32: if (len != 17) goto len_err; |
7e2cf31f1
|
673 674 |
pnpbios_encode_mem32(dev, p, pnp_get_resource(dev, IORESOURCE_MEM, mem)); |
1da177e4c
|
675 676 677 678 679 680 |
mem++; break; case LARGE_TAG_FIXEDMEM32: if (len != 9) goto len_err; |
7e2cf31f1
|
681 682 |
pnpbios_encode_fixed_mem32(dev, p, pnp_get_resource(dev, IORESOURCE_MEM, mem)); |
1da177e4c
|
683 684 685 686 687 688 |
mem++; break; case SMALL_TAG_IRQ: if (len < 2 || len > 3) goto len_err; |
7e2cf31f1
|
689 690 |
pnpbios_encode_irq(dev, p, pnp_get_resource(dev, IORESOURCE_IRQ, irq)); |
1da177e4c
|
691 692 693 694 695 696 |
irq++; break; case SMALL_TAG_DMA: if (len != 2) goto len_err; |
7e2cf31f1
|
697 698 |
pnpbios_encode_dma(dev, p, pnp_get_resource(dev, IORESOURCE_DMA, dma)); |
1da177e4c
|
699 700 701 702 703 704 |
dma++; break; case SMALL_TAG_PORT: if (len != 7) goto len_err; |
7e2cf31f1
|
705 706 |
pnpbios_encode_port(dev, p, pnp_get_resource(dev, IORESOURCE_IO, port)); |
1da177e4c
|
707 708 709 710 711 712 713 714 715 716 |
port++; break; case SMALL_TAG_VENDOR: /* do nothing */ break; case SMALL_TAG_FIXEDPORT: if (len != 3) goto len_err; |
7e2cf31f1
|
717 718 |
pnpbios_encode_fixed_port(dev, p, pnp_get_resource(dev, IORESOURCE_IO, port)); |
1da177e4c
|
719 720 721 722 723 |
port++; break; case SMALL_TAG_END: p = p + 2; |
9dd78466c
|
724 |
return (unsigned char *)p; |
1da177e4c
|
725 |
break; |
af901ca18
|
726 |
default: /* an unknown tag */ |
1e0aa9ad7
|
727 |
len_err: |
af11cb2d5
|
728 729 730 |
dev_err(&dev->dev, "unknown tag %#x length %d ", tag, len); |
1da177e4c
|
731 732 733 734 735 736 737 738 739 |
break; } /* continue to the next tag */ if (p[0] & LARGE_TAG) p += len + 3; else p += len + 1; } |
af11cb2d5
|
740 741 |
dev_err(&dev->dev, "no end tag in resource structure "); |
1da177e4c
|
742 743 744 |
return NULL; } |
1da177e4c
|
745 746 747 |
/* * Core Parsing Functions */ |
2bb9a6b32
|
748 749 |
int __init pnpbios_parse_data_stream(struct pnp_dev *dev, struct pnp_bios_node *node) |
1da177e4c
|
750 |
{ |
9dd78466c
|
751 752 |
unsigned char *p = (char *)node->data; unsigned char *end = (char *)(node->data + node->size); |
07d4e9af1
|
753 |
|
4ab55d8d4
|
754 |
p = pnpbios_parse_allocated_resource_data(dev, p, end); |
1da177e4c
|
755 756 |
if (!p) return -EIO; |
9dd78466c
|
757 |
p = pnpbios_parse_resource_option_data(p, end, dev); |
1da177e4c
|
758 759 |
if (!p) return -EIO; |
9dd78466c
|
760 |
p = pnpbios_parse_compatible_ids(p, end, dev); |
1da177e4c
|
761 762 763 764 |
if (!p) return -EIO; return 0; } |
4ab55d8d4
|
765 |
int pnpbios_read_resources_from_node(struct pnp_dev *dev, |
07d4e9af1
|
766 |
struct pnp_bios_node *node) |
1da177e4c
|
767 |
{ |
9dd78466c
|
768 769 |
unsigned char *p = (char *)node->data; unsigned char *end = (char *)(node->data + node->size); |
07d4e9af1
|
770 |
|
4ab55d8d4
|
771 |
p = pnpbios_parse_allocated_resource_data(dev, p, end); |
1da177e4c
|
772 773 774 775 |
if (!p) return -EIO; return 0; } |
4ab55d8d4
|
776 |
int pnpbios_write_resources_to_node(struct pnp_dev *dev, |
07d4e9af1
|
777 |
struct pnp_bios_node *node) |
1da177e4c
|
778 |
{ |
9dd78466c
|
779 780 |
unsigned char *p = (char *)node->data; unsigned char *end = (char *)(node->data + node->size); |
07d4e9af1
|
781 |
|
4ab55d8d4
|
782 |
p = pnpbios_encode_allocated_resource_data(dev, p, end); |
1da177e4c
|
783 784 785 786 |
if (!p) return -EIO; return 0; } |