|
|
1.1 ! root 1: // VGA io port access ! 2: // ! 3: // Copyright (C) 2009 Kevin O'Connor <[email protected]> ! 4: // Copyright (C) 2001-2008 the LGPL VGABios developers Team ! 5: // ! 6: // This file may be distributed under the terms of the GNU LGPLv3 license. ! 7: ! 8: #include "ioport.h" // outb ! 9: #include "farptr.h" // SET_FARVAR ! 10: #include "biosvar.h" // GET_BDA ! 11: #include "vgatables.h" // VGAREG_* ! 12: ! 13: // TODO ! 14: // * replace direct in/out calls with wrapper functions ! 15: ! 16: ! 17: /**************************************************************** ! 18: * Attribute control ! 19: ****************************************************************/ ! 20: ! 21: void ! 22: vgahw_screen_disable() ! 23: { ! 24: inb(VGAREG_ACTL_RESET); ! 25: outb(0x00, VGAREG_ACTL_ADDRESS); ! 26: } ! 27: ! 28: void ! 29: vgahw_screen_enable() ! 30: { ! 31: inb(VGAREG_ACTL_RESET); ! 32: outb(0x20, VGAREG_ACTL_ADDRESS); ! 33: } ! 34: ! 35: void ! 36: vgahw_set_border_color(u8 color) ! 37: { ! 38: inb(VGAREG_ACTL_RESET); ! 39: outb(0x00, VGAREG_ACTL_ADDRESS); ! 40: u8 v1 = color & 0x0f; ! 41: if (v1 & 0x08) ! 42: v1 += 0x08; ! 43: outb(v1, VGAREG_ACTL_WRITE_DATA); ! 44: ! 45: u8 v2 = color & 0x10; ! 46: int i; ! 47: for (i = 1; i < 4; i++) { ! 48: outb(i, VGAREG_ACTL_ADDRESS); ! 49: ! 50: u8 cur = inb(VGAREG_ACTL_READ_DATA); ! 51: cur &= 0xef; ! 52: cur |= v2; ! 53: outb(cur, VGAREG_ACTL_WRITE_DATA); ! 54: } ! 55: outb(0x20, VGAREG_ACTL_ADDRESS); ! 56: } ! 57: ! 58: void ! 59: vgahw_set_overscan_border_color(u8 color) ! 60: { ! 61: inb(VGAREG_ACTL_RESET); ! 62: outb(0x11, VGAREG_ACTL_ADDRESS); ! 63: outb(color, VGAREG_ACTL_WRITE_DATA); ! 64: outb(0x20, VGAREG_ACTL_ADDRESS); ! 65: } ! 66: ! 67: u8 ! 68: vgahw_get_overscan_border_color() ! 69: { ! 70: inb(VGAREG_ACTL_RESET); ! 71: outb(0x11, VGAREG_ACTL_ADDRESS); ! 72: u8 v = inb(VGAREG_ACTL_READ_DATA); ! 73: inb(VGAREG_ACTL_RESET); ! 74: outb(0x20, VGAREG_ACTL_ADDRESS); ! 75: return v; ! 76: } ! 77: ! 78: void ! 79: vgahw_set_palette(u8 palid) ! 80: { ! 81: inb(VGAREG_ACTL_RESET); ! 82: palid &= 0x01; ! 83: int i; ! 84: for (i = 1; i < 4; i++) { ! 85: outb(i, VGAREG_ACTL_ADDRESS); ! 86: ! 87: u8 v = inb(VGAREG_ACTL_READ_DATA); ! 88: v &= 0xfe; ! 89: v |= palid; ! 90: outb(v, VGAREG_ACTL_WRITE_DATA); ! 91: } ! 92: outb(0x20, VGAREG_ACTL_ADDRESS); ! 93: } ! 94: ! 95: void ! 96: vgahw_set_single_palette_reg(u8 reg, u8 val) ! 97: { ! 98: inb(VGAREG_ACTL_RESET); ! 99: outb(reg, VGAREG_ACTL_ADDRESS); ! 100: outb(val, VGAREG_ACTL_WRITE_DATA); ! 101: outb(0x20, VGAREG_ACTL_ADDRESS); ! 102: } ! 103: ! 104: u8 ! 105: vgahw_get_single_palette_reg(u8 reg) ! 106: { ! 107: inb(VGAREG_ACTL_RESET); ! 108: outb(reg, VGAREG_ACTL_ADDRESS); ! 109: u8 v = inb(VGAREG_ACTL_READ_DATA); ! 110: inb(VGAREG_ACTL_RESET); ! 111: outb(0x20, VGAREG_ACTL_ADDRESS); ! 112: return v; ! 113: } ! 114: ! 115: void ! 116: vgahw_set_all_palette_reg(u16 seg, u8 *data_far) ! 117: { ! 118: inb(VGAREG_ACTL_RESET); ! 119: int i; ! 120: for (i = 0; i < 0x10; i++) { ! 121: outb(i, VGAREG_ACTL_ADDRESS); ! 122: u8 val = GET_FARVAR(seg, *data_far); ! 123: outb(val, VGAREG_ACTL_WRITE_DATA); ! 124: data_far++; ! 125: } ! 126: outb(0x11, VGAREG_ACTL_ADDRESS); ! 127: outb(GET_FARVAR(seg, *data_far), VGAREG_ACTL_WRITE_DATA); ! 128: outb(0x20, VGAREG_ACTL_ADDRESS); ! 129: } ! 130: ! 131: void ! 132: vgahw_get_all_palette_reg(u16 seg, u8 *data_far) ! 133: { ! 134: int i; ! 135: for (i = 0; i < 0x10; i++) { ! 136: inb(VGAREG_ACTL_RESET); ! 137: outb(i, VGAREG_ACTL_ADDRESS); ! 138: SET_FARVAR(seg, *data_far, inb(VGAREG_ACTL_READ_DATA)); ! 139: data_far++; ! 140: } ! 141: inb(VGAREG_ACTL_RESET); ! 142: outb(0x11, VGAREG_ACTL_ADDRESS); ! 143: SET_FARVAR(seg, *data_far, inb(VGAREG_ACTL_READ_DATA)); ! 144: inb(VGAREG_ACTL_RESET); ! 145: outb(0x20, VGAREG_ACTL_ADDRESS); ! 146: } ! 147: ! 148: void ! 149: vgahw_toggle_intensity(u8 flag) ! 150: { ! 151: inb(VGAREG_ACTL_RESET); ! 152: outb(0x10, VGAREG_ACTL_ADDRESS); ! 153: u8 val = (inb(VGAREG_ACTL_READ_DATA) & 0xf7) | ((flag & 0x01) << 3); ! 154: outb(val, VGAREG_ACTL_WRITE_DATA); ! 155: outb(0x20, VGAREG_ACTL_ADDRESS); ! 156: } ! 157: ! 158: void ! 159: vgahw_select_video_dac_color_page(u8 flag, u8 data) ! 160: { ! 161: inb(VGAREG_ACTL_RESET); ! 162: outb(0x10, VGAREG_ACTL_ADDRESS); ! 163: u8 val = inb(VGAREG_ACTL_READ_DATA); ! 164: if (!(flag & 0x01)) { ! 165: // select paging mode ! 166: val = (val & 0x7f) | (data << 7); ! 167: outb(val, VGAREG_ACTL_WRITE_DATA); ! 168: outb(0x20, VGAREG_ACTL_ADDRESS); ! 169: return; ! 170: } ! 171: // select page ! 172: inb(VGAREG_ACTL_RESET); ! 173: outb(0x14, VGAREG_ACTL_ADDRESS); ! 174: if (!(val & 0x80)) ! 175: data <<= 2; ! 176: data &= 0x0f; ! 177: outb(data, VGAREG_ACTL_WRITE_DATA); ! 178: outb(0x20, VGAREG_ACTL_ADDRESS); ! 179: } ! 180: ! 181: void ! 182: vgahw_read_video_dac_state(u8 *pmode, u8 *curpage) ! 183: { ! 184: inb(VGAREG_ACTL_RESET); ! 185: outb(0x10, VGAREG_ACTL_ADDRESS); ! 186: u8 val1 = inb(VGAREG_ACTL_READ_DATA) >> 7; ! 187: ! 188: inb(VGAREG_ACTL_RESET); ! 189: outb(0x14, VGAREG_ACTL_ADDRESS); ! 190: u8 val2 = inb(VGAREG_ACTL_READ_DATA) & 0x0f; ! 191: if (!(val1 & 0x01)) ! 192: val2 >>= 2; ! 193: ! 194: inb(VGAREG_ACTL_RESET); ! 195: outb(0x20, VGAREG_ACTL_ADDRESS); ! 196: ! 197: *pmode = val1; ! 198: *curpage = val2; ! 199: } ! 200: ! 201: ! 202: /**************************************************************** ! 203: * DAC control ! 204: ****************************************************************/ ! 205: ! 206: void ! 207: vgahw_set_dac_regs(u16 seg, u8 *data_far, u8 start, int count) ! 208: { ! 209: outb(start, VGAREG_DAC_WRITE_ADDRESS); ! 210: while (count) { ! 211: outb(GET_FARVAR(seg, *data_far), VGAREG_DAC_DATA); ! 212: data_far++; ! 213: outb(GET_FARVAR(seg, *data_far), VGAREG_DAC_DATA); ! 214: data_far++; ! 215: outb(GET_FARVAR(seg, *data_far), VGAREG_DAC_DATA); ! 216: data_far++; ! 217: count--; ! 218: } ! 219: } ! 220: ! 221: void ! 222: vgahw_get_dac_regs(u16 seg, u8 *data_far, u8 start, int count) ! 223: { ! 224: outb(start, VGAREG_DAC_READ_ADDRESS); ! 225: while (count) { ! 226: SET_FARVAR(seg, *data_far, inb(VGAREG_DAC_DATA)); ! 227: data_far++; ! 228: SET_FARVAR(seg, *data_far, inb(VGAREG_DAC_DATA)); ! 229: data_far++; ! 230: SET_FARVAR(seg, *data_far, inb(VGAREG_DAC_DATA)); ! 231: data_far++; ! 232: count--; ! 233: } ! 234: } ! 235: ! 236: void ! 237: vgahw_set_pel_mask(u8 val) ! 238: { ! 239: outb(val, VGAREG_PEL_MASK); ! 240: } ! 241: ! 242: u8 ! 243: vgahw_get_pel_mask() ! 244: { ! 245: return inb(VGAREG_PEL_MASK); ! 246: } ! 247: ! 248: void ! 249: vgahw_save_dac_state(u16 seg, struct saveDACcolors *info) ! 250: { ! 251: /* XXX: check this */ ! 252: SET_FARVAR(seg, info->rwmode, inb(VGAREG_DAC_STATE)); ! 253: SET_FARVAR(seg, info->peladdr, inb(VGAREG_DAC_WRITE_ADDRESS)); ! 254: SET_FARVAR(seg, info->pelmask, inb(VGAREG_PEL_MASK)); ! 255: vgahw_get_dac_regs(seg, info->dac, 0, 256); ! 256: SET_FARVAR(seg, info->color_select, 0); ! 257: } ! 258: ! 259: void ! 260: vgahw_restore_dac_state(u16 seg, struct saveDACcolors *info) ! 261: { ! 262: outb(GET_FARVAR(seg, info->pelmask), VGAREG_PEL_MASK); ! 263: vgahw_set_dac_regs(seg, info->dac, 0, 256); ! 264: outb(GET_FARVAR(seg, info->peladdr), VGAREG_DAC_WRITE_ADDRESS); ! 265: } ! 266: ! 267: ! 268: /**************************************************************** ! 269: * Memory control ! 270: ****************************************************************/ ! 271: ! 272: void ! 273: vgahw_sequ_write(u8 index, u8 value) ! 274: { ! 275: outw((value<<8) | index, VGAREG_SEQU_ADDRESS); ! 276: } ! 277: ! 278: void ! 279: vgahw_grdc_write(u8 index, u8 value) ! 280: { ! 281: outw((value<<8) | index, VGAREG_GRDC_ADDRESS); ! 282: } ! 283: ! 284: void ! 285: vgahw_set_text_block_specifier(u8 spec) ! 286: { ! 287: outw((spec << 8) | 0x03, VGAREG_SEQU_ADDRESS); ! 288: } ! 289: ! 290: void ! 291: get_font_access() ! 292: { ! 293: outw(0x0100, VGAREG_SEQU_ADDRESS); ! 294: outw(0x0402, VGAREG_SEQU_ADDRESS); ! 295: outw(0x0704, VGAREG_SEQU_ADDRESS); ! 296: outw(0x0300, VGAREG_SEQU_ADDRESS); ! 297: outw(0x0204, VGAREG_GRDC_ADDRESS); ! 298: outw(0x0005, VGAREG_GRDC_ADDRESS); ! 299: outw(0x0406, VGAREG_GRDC_ADDRESS); ! 300: } ! 301: ! 302: void ! 303: release_font_access() ! 304: { ! 305: outw(0x0100, VGAREG_SEQU_ADDRESS); ! 306: outw(0x0302, VGAREG_SEQU_ADDRESS); ! 307: outw(0x0304, VGAREG_SEQU_ADDRESS); ! 308: outw(0x0300, VGAREG_SEQU_ADDRESS); ! 309: u16 v = (inw(VGAREG_READ_MISC_OUTPUT) & 0x01) ? 0x0e : 0x0a; ! 310: outw((v << 8) | 0x06, VGAREG_GRDC_ADDRESS); ! 311: outw(0x0004, VGAREG_GRDC_ADDRESS); ! 312: outw(0x1005, VGAREG_GRDC_ADDRESS); ! 313: } ! 314: ! 315: ! 316: /**************************************************************** ! 317: * CRTC registers ! 318: ****************************************************************/ ! 319: ! 320: static u16 ! 321: get_crtc() ! 322: { ! 323: return GET_BDA(crtc_address); ! 324: } ! 325: ! 326: void ! 327: vgahw_set_cursor_shape(u8 start, u8 end) ! 328: { ! 329: u16 crtc_addr = get_crtc(); ! 330: outb(0x0a, crtc_addr); ! 331: outb(start, crtc_addr + 1); ! 332: outb(0x0b, crtc_addr); ! 333: outb(end, crtc_addr + 1); ! 334: } ! 335: ! 336: void ! 337: vgahw_set_active_page(u16 address) ! 338: { ! 339: u16 crtc_addr = get_crtc(); ! 340: outb(0x0c, crtc_addr); ! 341: outb((address & 0xff00) >> 8, crtc_addr + 1); ! 342: outb(0x0d, crtc_addr); ! 343: outb(address & 0x00ff, crtc_addr + 1); ! 344: } ! 345: ! 346: void ! 347: vgahw_set_cursor_pos(u16 address) ! 348: { ! 349: u16 crtc_addr = get_crtc(); ! 350: outb(0x0e, crtc_addr); ! 351: outb((address & 0xff00) >> 8, crtc_addr + 1); ! 352: outb(0x0f, crtc_addr); ! 353: outb(address & 0x00ff, crtc_addr + 1); ! 354: } ! 355: ! 356: void ! 357: vgahw_set_scan_lines(u8 lines) ! 358: { ! 359: u16 crtc_addr = get_crtc(); ! 360: outb(0x09, crtc_addr); ! 361: u8 crtc_r9 = inb(crtc_addr + 1); ! 362: crtc_r9 = (crtc_r9 & 0xe0) | (lines - 1); ! 363: outb(crtc_r9, crtc_addr + 1); ! 364: } ! 365: ! 366: // Get vertical display end ! 367: u16 ! 368: vgahw_get_vde() ! 369: { ! 370: u16 crtc_addr = get_crtc(); ! 371: outb(0x12, crtc_addr); ! 372: u16 vde = inb(crtc_addr + 1); ! 373: outb(0x07, crtc_addr); ! 374: u8 ovl = inb(crtc_addr + 1); ! 375: vde += (((ovl & 0x02) << 7) + ((ovl & 0x40) << 3) + 1); ! 376: return vde; ! 377: } ! 378: ! 379: ! 380: /**************************************************************** ! 381: * Save/Restore/Set state ! 382: ****************************************************************/ ! 383: ! 384: void ! 385: vgahw_save_state(u16 seg, struct saveVideoHardware *info) ! 386: { ! 387: u16 crtc_addr = get_crtc(); ! 388: SET_FARVAR(seg, info->sequ_index, inb(VGAREG_SEQU_ADDRESS)); ! 389: SET_FARVAR(seg, info->crtc_index, inb(crtc_addr)); ! 390: SET_FARVAR(seg, info->grdc_index, inb(VGAREG_GRDC_ADDRESS)); ! 391: inb(VGAREG_ACTL_RESET); ! 392: u16 ar_index = inb(VGAREG_ACTL_ADDRESS); ! 393: SET_FARVAR(seg, info->actl_index, ar_index); ! 394: SET_FARVAR(seg, info->feature, inb(VGAREG_READ_FEATURE_CTL)); ! 395: ! 396: u16 i; ! 397: for (i=0; i<4; i++) { ! 398: outb(i+1, VGAREG_SEQU_ADDRESS); ! 399: SET_FARVAR(seg, info->sequ_regs[i], inb(VGAREG_SEQU_DATA)); ! 400: } ! 401: outb(0, VGAREG_SEQU_ADDRESS); ! 402: SET_FARVAR(seg, info->sequ0, inb(VGAREG_SEQU_DATA)); ! 403: ! 404: for (i=0; i<25; i++) { ! 405: outb(i, crtc_addr); ! 406: SET_FARVAR(seg, info->crtc_regs[i], inb(crtc_addr + 1)); ! 407: } ! 408: ! 409: for (i=0; i<20; i++) { ! 410: inb(VGAREG_ACTL_RESET); ! 411: outb(i | (ar_index & 0x20), VGAREG_ACTL_ADDRESS); ! 412: SET_FARVAR(seg, info->actl_regs[i], inb(VGAREG_ACTL_READ_DATA)); ! 413: } ! 414: inb(VGAREG_ACTL_RESET); ! 415: ! 416: for (i=0; i<9; i++) { ! 417: outb(i, VGAREG_GRDC_ADDRESS); ! 418: SET_FARVAR(seg, info->grdc_regs[i], inb(VGAREG_GRDC_DATA)); ! 419: } ! 420: ! 421: SET_FARVAR(seg, info->crtc_addr, crtc_addr); ! 422: ! 423: /* XXX: read plane latches */ ! 424: for (i=0; i<4; i++) ! 425: SET_FARVAR(seg, info->plane_latch[i], 0); ! 426: } ! 427: ! 428: void ! 429: vgahw_restore_state(u16 seg, struct saveVideoHardware *info) ! 430: { ! 431: // Reset Attribute Ctl flip-flop ! 432: inb(VGAREG_ACTL_RESET); ! 433: ! 434: u16 crtc_addr = GET_FARVAR(seg, info->crtc_addr); ! 435: ! 436: u16 i; ! 437: for (i=0; i<4; i++) { ! 438: outb(i+1, VGAREG_SEQU_ADDRESS); ! 439: outb(GET_FARVAR(seg, info->sequ_regs[i]), VGAREG_SEQU_DATA); ! 440: } ! 441: outb(0, VGAREG_SEQU_ADDRESS); ! 442: outb(GET_FARVAR(seg, info->sequ0), VGAREG_SEQU_DATA); ! 443: ! 444: // Disable CRTC write protection ! 445: outw(0x0011, crtc_addr); ! 446: // Set CRTC regs ! 447: for (i=0; i<25; i++) ! 448: if (i != 0x11) { ! 449: outb(i, crtc_addr); ! 450: outb(GET_FARVAR(seg, info->crtc_regs[i]), crtc_addr + 1); ! 451: } ! 452: // select crtc base address ! 453: u16 v = inb(VGAREG_READ_MISC_OUTPUT) & ~0x01; ! 454: if (crtc_addr == VGAREG_VGA_CRTC_ADDRESS) ! 455: v |= 0x01; ! 456: outb(v, VGAREG_WRITE_MISC_OUTPUT); ! 457: ! 458: // enable write protection if needed ! 459: outb(0x11, crtc_addr); ! 460: outb(GET_FARVAR(seg, info->crtc_regs[0x11]), crtc_addr + 1); ! 461: ! 462: // Set Attribute Ctl ! 463: u16 ar_index = GET_FARVAR(seg, info->actl_index); ! 464: inb(VGAREG_ACTL_RESET); ! 465: for (i=0; i<20; i++) { ! 466: outb(i | (ar_index & 0x20), VGAREG_ACTL_ADDRESS); ! 467: outb(GET_FARVAR(seg, info->actl_regs[i]), VGAREG_ACTL_WRITE_DATA); ! 468: } ! 469: outb(ar_index, VGAREG_ACTL_ADDRESS); ! 470: inb(VGAREG_ACTL_RESET); ! 471: ! 472: for (i=0; i<9; i++) { ! 473: outb(i, VGAREG_GRDC_ADDRESS); ! 474: outb(GET_FARVAR(seg, info->grdc_regs[i]), VGAREG_GRDC_DATA); ! 475: } ! 476: ! 477: outb(GET_FARVAR(seg, info->sequ_index), VGAREG_SEQU_ADDRESS); ! 478: outb(GET_FARVAR(seg, info->crtc_index), crtc_addr); ! 479: outb(GET_FARVAR(seg, info->grdc_index), VGAREG_GRDC_ADDRESS); ! 480: outb(GET_FARVAR(seg, info->feature), crtc_addr - 0x4 + 0xa); ! 481: } ! 482: ! 483: void ! 484: vgahw_set_mode(struct VideoParam_s *vparam_g) ! 485: { ! 486: // Reset Attribute Ctl flip-flop ! 487: inb(VGAREG_ACTL_RESET); ! 488: ! 489: // Set Attribute Ctl ! 490: u16 i; ! 491: for (i = 0; i <= 0x13; i++) { ! 492: outb(i, VGAREG_ACTL_ADDRESS); ! 493: outb(GET_GLOBAL(vparam_g->actl_regs[i]), VGAREG_ACTL_WRITE_DATA); ! 494: } ! 495: outb(0x14, VGAREG_ACTL_ADDRESS); ! 496: outb(0x00, VGAREG_ACTL_WRITE_DATA); ! 497: ! 498: // Set Sequencer Ctl ! 499: outb(0, VGAREG_SEQU_ADDRESS); ! 500: outb(0x03, VGAREG_SEQU_DATA); ! 501: for (i = 1; i <= 4; i++) { ! 502: outb(i, VGAREG_SEQU_ADDRESS); ! 503: outb(GET_GLOBAL(vparam_g->sequ_regs[i - 1]), VGAREG_SEQU_DATA); ! 504: } ! 505: ! 506: // Set Grafx Ctl ! 507: for (i = 0; i <= 8; i++) { ! 508: outb(i, VGAREG_GRDC_ADDRESS); ! 509: outb(GET_GLOBAL(vparam_g->grdc_regs[i]), VGAREG_GRDC_DATA); ! 510: } ! 511: ! 512: // Set CRTC address VGA or MDA ! 513: u8 miscreg = GET_GLOBAL(vparam_g->miscreg); ! 514: u16 crtc_addr = VGAREG_VGA_CRTC_ADDRESS; ! 515: if (!(miscreg & 1)) ! 516: crtc_addr = VGAREG_MDA_CRTC_ADDRESS; ! 517: ! 518: // Disable CRTC write protection ! 519: outw(0x0011, crtc_addr); ! 520: // Set CRTC regs ! 521: for (i = 0; i <= 0x18; i++) { ! 522: outb(i, crtc_addr); ! 523: outb(GET_GLOBAL(vparam_g->crtc_regs[i]), crtc_addr + 1); ! 524: } ! 525: ! 526: // Set the misc register ! 527: outb(miscreg, VGAREG_WRITE_MISC_OUTPUT); ! 528: ! 529: // Enable video ! 530: outb(0x20, VGAREG_ACTL_ADDRESS); ! 531: inb(VGAREG_ACTL_RESET); ! 532: } ! 533: ! 534: ! 535: /**************************************************************** ! 536: * Misc ! 537: ****************************************************************/ ! 538: ! 539: void ! 540: vgahw_enable_video_addressing(u8 disable) ! 541: { ! 542: u8 v = (disable & 1) ? 0x00 : 0x02; ! 543: u8 v2 = inb(VGAREG_READ_MISC_OUTPUT) & ~0x02; ! 544: outb(v | v2, VGAREG_WRITE_MISC_OUTPUT); ! 545: } ! 546: ! 547: void ! 548: vgahw_init() ! 549: { ! 550: // switch to color mode and enable CPU access 480 lines ! 551: outb(0xc3, VGAREG_WRITE_MISC_OUTPUT); ! 552: // more than 64k 3C4/04 ! 553: outb(0x04, VGAREG_SEQU_ADDRESS); ! 554: outb(0x02, VGAREG_SEQU_DATA); ! 555: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.