1/* 2 * Copyright (c) 1996, Sujal M. Patel 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright --- 9 unchanged lines hidden (view full) --- 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * |
26 * $FreeBSD: head/sys/isa/pnp.c 52059 1999-10-09 13:11:46Z dfr $ |
27 * from: pnp.c,v 1.11 1999/05/06 22:11:19 peter Exp 28 */ 29 30#include <sys/param.h> 31#include <sys/systm.h> 32#include <sys/kernel.h> 33#include <sys/module.h> 34#include <sys/bus.h> 35#include <sys/malloc.h> 36#include <isa/isavar.h> 37#include <isa/pnpreg.h> 38#include <isa/pnpvar.h> |
39#include <machine/clock.h> 40 41typedef struct _pnp_id { 42 u_int32_t vendor_id; 43 u_int32_t serial; 44 u_char checksum; 45} pnp_id; 46 --- 114 unchanged lines hidden (view full) --- 161 162 valid = valid && (data[8] == sum); 163 164 return valid; 165} 166 167/* 168 * Fill's the buffer with resource info from the device. |
169 * Returns the number of characters read. |
170 */ 171static int 172pnp_get_resource_info(u_char *buffer, int len) 173{ |
174 int i, j, count; |
175 u_char temp; 176 |
177 count = 0; |
178 for (i = 0; i < len; i++) { 179 outb(_PNP_ADDRESS, PNP_STATUS); 180 for (j = 0; j < 100; j++) { 181 if ((inb((pnp_rd_port << 2) | 0x3)) & 0x1) 182 break; 183 DELAY(1); 184 } 185 if (j == 100) { 186 printf("PnP device failed to report resource data\n"); |
187 return count; |
188 } 189 outb(_PNP_ADDRESS, PNP_RESOURCE_DATA); 190 temp = inb((pnp_rd_port << 2) | 0x3); 191 if (buffer != NULL) 192 buffer[i] = temp; |
193 count++; |
194 } |
195 return count; |
196} 197 198#if 0 199/* 200 * write_pnp_parms initializes a logical device with the parms 201 * in d, and then activates the board if the last parameter is 1. 202 */ 203 --- 159 unchanged lines hidden (view full) --- 363 } 364 } 365} 366 367/* 368 * Scan Resource Data for Logical Devices. 369 * 370 * This function exits as soon as it gets an error reading *ANY* |
371 * Resource Data or it reaches the end of Resource Data. In the first |
372 * case the return value will be TRUE, FALSE otherwise. 373 */ 374static int |
375pnp_create_devices(device_t parent, pnp_id *p, int csn, 376 u_char *resources, int len) |
377{ |
378 u_char tag, *resp, *resinfo, *startres = 0; 379 int large_len, scanning = len, retval = FALSE; |
380 u_int32_t logical_id; 381 u_int32_t compat_id; 382 device_t dev = 0; 383 int ldn = 0; |
384 struct pnp_set_config_arg *csnldn; |
385 char buf[100]; |
386 char *desc = 0; 387 |
388 resp = resources; 389 while (scanning > 0) { 390 tag = *resp++; 391 scanning--; 392 if (PNP_RES_TYPE(tag) != 0) { 393 /* Large resource */ 394 if (scanning < 2) { |
395 scanning = 0; 396 continue; 397 } |
398 large_len = resp[0] + (resp[1] << 8); 399 resp += 2; |
400 |
401 if (scanning < large_len) { |
402 scanning = 0; |
403 continue; 404 } |
405 resinfo = resp; 406 resp += large_len; 407 scanning -= large_len; |
408 409 if (PNP_LRES_NUM(tag) == PNP_TAG_ID_ANSI) { |
410 if (large_len > sizeof(buf) - 1) 411 large_len = sizeof(buf) - 1; 412 bcopy(resinfo, buf, large_len); 413 |
414 /* |
415 * Trim trailing spaces. |
416 */ |
417 while (buf[large_len-1] == ' ') 418 large_len--; 419 buf[large_len] = '\0'; 420 desc = buf; 421 if (dev) 422 device_set_desc_copy(dev, desc); |
423 continue; 424 } 425 |
426 continue; 427 } 428 429 /* Small resource */ 430 if (scanning < PNP_SRES_LEN(tag)) { 431 scanning = 0; 432 continue; 433 } 434 resinfo = resp; 435 resp += PNP_SRES_LEN(tag); 436 scanning -= PNP_SRES_LEN(tag);; 437 438 switch (PNP_SRES_NUM(tag)) { 439 case PNP_TAG_LOGICAL_DEVICE: 440 /* 441 * Parse the resources for the previous 442 * logical device (if any). 443 */ 444 if (startres) { 445 pnp_parse_resources(dev, startres, 446 resinfo - startres - 1); 447 dev = 0; 448 startres = 0; |
449 } 450 |
451 /* 452 * A new logical device. Scan for end of 453 * resources. 454 */ 455 bcopy(resinfo, &logical_id, 4); 456 pnp_check_quirks(p->vendor_id, logical_id, ldn); 457 compat_id = 0; 458 dev = BUS_ADD_CHILD(parent, ISA_ORDER_PNP, NULL, -1); 459 if (desc) 460 device_set_desc_copy(dev, desc); 461 isa_set_vendorid(dev, p->vendor_id); 462 isa_set_serial(dev, p->serial); 463 isa_set_logicalid(dev, logical_id); 464 csnldn = malloc(sizeof *csnldn, M_DEVBUF, M_NOWAIT); 465 if (!csnldn) { 466 device_printf(parent, 467 "out of memory\n"); |
468 scanning = 0; |
469 break; |
470 } |
471 csnldn->csn = csn; 472 csnldn->ldn = ldn; 473 ISA_SET_CONFIG_CALLBACK(parent, dev, 474 pnp_set_config, csnldn); 475 ldn++; 476 startres = resp; 477 break; 478 479 case PNP_TAG_END: 480 if (!startres) { |
481 device_printf(parent, |
482 "malformed resources\n"); |
483 scanning = 0; 484 break; 485 } |
486 pnp_parse_resources(dev, startres, 487 resinfo - startres - 1); 488 dev = 0; 489 startres = 0; 490 scanning = 0; 491 break; |
492 |
493 default: 494 /* Skip this resource */ 495 break; |
496 } 497 } 498 |
499 return retval; 500} 501 502/* |
503 * Read 'amount' bytes of resources from the card, allocating memory 504 * as needed. If a buffer is already available, it should be passed in 505 * '*resourcesp' and its length in '*spacep'. The number of resource 506 * bytes already in the buffer should be passed in '*lenp'. The memory 507 * allocated will be returned in '*resourcesp' with its size and the 508 * number of bytes of resources in '*spacep' and '*lenp' respectively. 509 */ 510static int 511pnp_read_bytes(int amount, u_char **resourcesp, int *spacep, int *lenp) 512{ 513 u_char *resources = *resourcesp; 514 u_char *newres; 515 int space = *spacep; 516 int len = *lenp; 517 518 if (space == 0) { 519 space = 1024; 520 resources = malloc(space, M_TEMP, M_NOWAIT); 521 if (!resources) 522 return ENOMEM; 523 } 524 525 if (len + amount > space) { 526 int extra = 1024; 527 while (len + amount > space + extra) 528 extra += 1024; 529 newres = malloc(space + extra, M_TEMP, M_NOWAIT); 530 if (!newres) 531 return ENOMEM; 532 bcopy(resources, newres, len); 533 free(resources, M_TEMP); 534 resources = newres; 535 space += extra; 536 } 537 538 if (pnp_get_resource_info(resources + len, amount) != amount) 539 return EINVAL; 540 len += amount; 541 542 *resourcesp = resources; 543 *spacep = space; 544 *lenp = len; 545 546 return 0; 547} 548 549/* 550 * Read all resources from the card, allocating memory as needed. If a 551 * buffer is already available, it should be passed in '*resourcesp' 552 * and its length in '*spacep'. The memory allocated will be returned 553 * in '*resourcesp' with its size and the number of bytes of resources 554 * in '*spacep' and '*lenp' respectively. 555 */ 556static int 557pnp_read_resources(u_char **resourcesp, int *spacep, int *lenp) 558{ 559 u_char *resources = *resourcesp; 560 int space = *spacep; 561 int len = 0; 562 int error, done; 563 u_char tag; 564 565 error = 0; 566 done = 0; 567 while (!done) { 568 error = pnp_read_bytes(1, &resources, &space, &len); 569 if (error) 570 goto out; 571 tag = resources[len-1]; 572 if (PNP_RES_TYPE(tag) == 0) { 573 /* 574 * Small resource, read contents. 575 */ 576 error = pnp_read_bytes(PNP_SRES_LEN(tag), 577 &resources, &space, &len); 578 if (error) 579 goto out; 580 if (PNP_SRES_NUM(tag) == PNP_TAG_END) 581 done = 1; 582 } else { 583 /* 584 * Large resource, read length and contents. 585 */ 586 error = pnp_read_bytes(2, &resources, &space, &len); 587 if (error) 588 goto out; 589 error = pnp_read_bytes(resources[len-2] 590 + (resources[len-1] << 8), 591 &resources, &space, &len); 592 if (error) 593 goto out; 594 } 595 } 596 597 out: 598 *resourcesp = resources; 599 *spacep = space; 600 *lenp = len; 601 return error; 602} 603 604/* |
605 * Run the isolation protocol. Use pnp_rd_port as the READ_DATA port 606 * value (caller should try multiple READ_DATA locations before giving 607 * up). Upon exiting, all cards are aware that they should use 608 * pnp_rd_port as the READ_DATA port. 609 * 610 * In the first pass, a csn is assigned to each board and pnp_id's 611 * are saved to an array, pnp_devices. In the second pass, each 612 * card is woken up and the device configuration is called. 613 */ 614static int 615pnp_isolation_protocol(device_t parent) 616{ 617 int csn; 618 pnp_id id; |
619 int found = 0, len; 620 u_char *resources = 0; 621 int space = 0; 622 int error; |
623 624 /* 625 * Put all cards into the Sleep state so that we can clear 626 * their CSNs. 627 */ 628 pnp_send_initiation_key(); 629 630 /* --- 18 unchanged lines hidden (view full) --- 649 outb(_PNP_ADDRESS, PNP_SERIAL_ISOLATION); 650 DELAY(1000); /* Delay 1 msec */ 651 652 if (pnp_get_serial(&id)) { 653 /* 654 * We have read the id from a card 655 * successfully. The card which won the 656 * isolation protocol will be in Isolation |
657 * mode and all others will be in Sleep. |
658 * Program the CSN of the isolated card 659 * (taking it to Config state) and read its 660 * resources, creating devices as we find 661 * logical devices on the card. 662 */ 663 pnp_write(PNP_SET_CSN, csn); |
664 error = pnp_read_resources(&resources, 665 &space, 666 &len); 667 if (error) 668 break; 669 pnp_create_devices(parent, &id, csn, 670 resources, len); |
671 found++; 672 } else 673 break; 674 675 /* 676 * Put this card back to the Sleep state and 677 * simultaneously move all cards which don't have a 678 * CSN yet to Isolation state. 679 */ 680 pnp_write(PNP_WAKE, 0); 681 } 682 683 /* 684 * Unless we have chosen the wrong read port, all cards will 685 * be in Sleep state. Put them back into WaitForKey for 686 * now. Their resources will be programmed later. 687 */ 688 pnp_write(PNP_CONFIG_CONTROL, PNP_CONFIG_CONTROL_WAIT_FOR_KEY); 689 |
690 /* 691 * Cleanup. 692 */ 693 if (resources) 694 free(resources, M_TEMP); 695 |
696 return found; 697} 698 699 700/* 701 * pnp_identify() 702 * 703 * autoconfiguration of pnp devices. This routine just runs the --- 47 unchanged lines hidden --- |