Changeset cf8cc36 in mainline for uspace/srv/drivers/ns8250/ns8250.c
- Timestamp:
- 2010-05-14T13:45:28Z (15 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- c47e1a8
- Parents:
- 04c7003f
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/srv/drivers/ns8250/ns8250.c
r04c7003f rcf8cc36 67 67 #define REG_COUNT 7 68 68 #define MAX_BAUD_RATE 115200 69 69 #define DLAB_MASK (1 << 7) 70 71 /** The number of bits of one data unit send by the serial port.*/ 72 typedef enum { 73 WORD_LENGTH_5, 74 WORD_LENGTH_6, 75 WORD_LENGTH_7, 76 WORD_LENGTH_8 77 } word_length_t; 78 79 /** The number of stop bits used by the serial port. */ 80 typedef enum { 81 /** Use one stop bit. */ 82 ONE_STOP_BIT, 83 /** 1.5 stop bits for word length 5, 2 stop bits otherwise. */ 84 TWO_STOP_BITS 85 } stop_bit_t; 86 87 /** The driver data for the serial port devices. 88 */ 70 89 typedef struct ns8250_dev_data { 90 /** Is there any client conntected to the device? */ 71 91 bool client_connected; 92 /** The irq assigned to this device. */ 72 93 int irq; 94 /** The base i/o address of the devices registers. */ 73 95 uint32_t io_addr; 96 /** The i/o port used to access the serial ports registers. */ 74 97 ioport8_t *port; 98 /** The buffer for incomming data.*/ 75 99 cyclic_buffer_t input_buffer; 100 /** The fibril mutex for synchronizing the access to the device.*/ 76 101 fibril_mutex_t mutex; 77 102 } ns8250_dev_data_t; 78 103 104 /** Create driver data for a device. 105 * 106 * @return the driver data. 107 */ 79 108 static ns8250_dev_data_t * create_ns8250_dev_data() 80 109 { … … 87 116 } 88 117 118 /** Delete driver data. 119 * 120 * @param data the driver data structure. 121 */ 89 122 static void delete_ns8250_dev_data(ns8250_dev_data_t *data) 90 123 { … … 94 127 } 95 128 129 /** Find out if there is some incomming data available on the serial port. 130 * 131 * @param port the base address of the serial port device's ports. 132 * @return true if there are data waiting to be read, false otherwise. 133 */ 96 134 static bool ns8250_received(ioport8_t *port) 97 135 { … … 99 137 } 100 138 139 /** Read one byte from the serial port. 140 * 141 * @param port the base address of the serial port device's ports. 142 * @return the data read. 143 */ 101 144 static uint8_t ns8250_read_8(ioport8_t *port) 102 145 { … … 104 147 } 105 148 149 /** Find out wheter it is possible to send data. 150 * 151 * @param port the base address of the serial port device's ports. 152 */ 106 153 static bool is_transmit_empty(ioport8_t *port) 107 154 { … … 109 156 } 110 157 158 /** Write one character on the serial port. 159 * 160 * @param port the base address of the serial port device's ports. 161 * @param c the character to be written to the serial port device. 162 */ 111 163 static void ns8250_write_8(ioport8_t *port, uint8_t c) 112 164 { … … 117 169 } 118 170 171 /** Read data from the serial port device. 172 * 173 * @param dev the serial port device. 174 * @param buf the ouput buffer for read data. 175 * @param count the number of bytes to be read. 176 * 177 * @return the number of bytes actually read on success, negative error number otherwise. 178 */ 119 179 static int ns8250_read(device_t *dev, char *buf, size_t count) 120 180 { 121 181 // printf(NAME ": ns8250_read %s\n", dev->name); 122 182 123 int ret = 0;183 int ret = EOK; 124 184 125 185 ns8250_dev_data_t *data = (ns8250_dev_data_t *)dev->driver_data; 126 186 fibril_mutex_lock(&data->mutex); 127 187 128 while (!buf_is_empty(&data->input_buffer) && ret < count) {188 while (!buf_is_empty(&data->input_buffer) && (size_t)ret < count) { 129 189 buf[ret] = (char)buf_pop_front(&data->input_buffer); 130 190 ret++; … … 136 196 } 137 197 198 /** Write a character to the serial port. 199 * 200 * @param data the serial port device's driver data. 201 * @param c the character to be written. 202 */ 138 203 static inline void ns8250_putchar(ns8250_dev_data_t *data, uint8_t c) 139 204 { … … 143 208 } 144 209 210 /** Write data to the serial port. 211 * 212 * @param dev the serial port device. 213 * @param buf the data to be written. 214 * @param count the number of bytes to be written. 215 * 216 * @return 0 on success. 217 */ 145 218 static int ns8250_write(device_t *dev, char *buf, size_t count) 146 219 { … … 157 230 static device_class_t ns8250_dev_class; 158 231 232 /** The character interface's callbacks. 233 */ 159 234 static char_iface_t ns8250_char_iface = { 160 235 .read = &ns8250_read, … … 177 252 }; 178 253 254 /** Clean up the serial port device structure. 255 * 256 * @param dev the device structure. 257 */ 179 258 static void ns8250_dev_cleanup(device_t *dev) 180 259 { … … 190 269 } 191 270 271 /** Enable the i/o ports of the device. 272 * 273 * @param the serial port device. 274 * @return true on success, false otherwise. 275 */ 192 276 static bool ns8250_pio_enable(device_t *dev) 193 277 { … … 205 289 } 206 290 291 /** Probe the serial port device for its presence. 292 * 293 * @param dev the serial port device. 294 * @return true if the device is present, false otherwise. 295 */ 207 296 static bool ns8250_dev_probe(device_t *dev) 208 297 { … … 235 324 } 236 325 326 /** Initialize serial port device. 327 * 328 * @param dev the serial port device. 329 * @return 0 on success, negative error number otherwise. 330 */ 237 331 static int ns8250_dev_initialize(device_t *dev) 238 332 { … … 309 403 } 310 404 405 /** Enable interrupts on the serial port device. 406 * 407 * Interrupt when data is received. 408 * 409 * @param port the base address of the serial port device's ports. 410 */ 311 411 static inline void ns8250_port_interrupts_enable(ioport8_t *port) 312 412 { … … 315 415 } 316 416 417 /** Disable interrupts on the serial port device. 418 * 419 * @param port the base address of the serial port device's ports. 420 */ 317 421 static inline void ns8250_port_interrupts_disable(ioport8_t *port) 318 422 { … … 320 424 } 321 425 426 /** Enable interrupts for the serial port device. 427 * 428 * @param dev the device. 429 * @return 0 on success, negative error number otherwise. 430 */ 322 431 static int ns8250_interrupt_enable(device_t *dev) 323 432 { … … 336 445 } 337 446 447 /** Set Divisor Latch Access Bit. 448 * 449 * When the Divisor Latch Access Bit is set, 450 * it is possible to set baud rate of the serial port device. 451 * 452 * @param port the base address of the serial port device's ports. 453 */ 454 static inline void enable_dlab(ioport8_t *port) 455 { 456 uint8_t val = pio_read_8(port + 3); 457 pio_write_8(port + 3, val | DLAB_MASK); 458 } 459 460 /** Clear Divisor Latch Access Bit. 461 * 462 * @param port the base address of the serial port device's ports. 463 */ 464 static inline void clear_dlab(ioport8_t *port) 465 { 466 uint8_t val = pio_read_8(port + 3); 467 pio_write_8(port + 3, val & (~DLAB_MASK)); 468 } 469 470 /** Set baud rate of the serial communication on the serial device. 471 * 472 * @param port the base address of the serial port device's ports. 473 * @param baud_rate the baud rate to be used by the device. 474 * 475 * @return 0 on success, negative error number otherwise (EINVAL if the specified baud_rate is not valid). 476 */ 338 477 static int ns8250_port_set_baud_rate(ioport8_t *port, unsigned int baud_rate) 339 478 { … … 350 489 div_high = (uint8_t)(divisor >> 8); 351 490 352 pio_write_8(port + 3, 0x80); // Enable DLAB (set baud rate divisor) 353 354 pio_write_8(port + 0, div_low); // Set divisor low byte 355 pio_write_8(port + 1, div_high); // Set divisor high byte 356 357 pio_write_8(port + 3, pio_read_8(port + 3) & (~0x80)); // Clear DLAB 491 // enable DLAB to be able to access baud rate divisor 492 enable_dlab(port); 493 494 // set divisor low byte 495 pio_write_8(port + 0, div_low); 496 // set divisor high byte 497 pio_write_8(port + 1, div_high); 498 499 clear_dlab(port); 358 500 359 501 return EOK; 360 502 } 361 503 362 static int ns8250_set_baud_rate(device_t *dev, unsigned int baud_rate) 504 /** Get baud rate used by the serial port device. 505 * 506 * @param port the base address of the serial port device's ports. 507 * @param baud_rate the ouput parameter to which the baud rate is stored. 508 */ 509 static unsigned int ns8250_port_get_baud_rate(ioport8_t *port) 510 { 511 uint16_t divisor; 512 uint8_t div_low, div_high; 513 514 // enable DLAB to be able to access baud rate divisor 515 enable_dlab(port); 516 517 // get divisor low byte 518 div_low = pio_read_8(port + 0); 519 // get divisor high byte 520 div_high = pio_read_8(port + 1); 521 522 clear_dlab(port); 523 524 divisor = (div_high << 8) | div_low; 525 return MAX_BAUD_RATE / divisor; 526 } 527 528 /** Get the parameters of the serial communication set on the serial port device. 529 * 530 * @param parity the parity used. 531 * @param word_length the length of one data unit in bits. 532 * @param stop_bits the number of stop bits used (one or two). 533 */ 534 static void ns8250_port_get_com_props( 535 ioport8_t *port, unsigned int *parity, unsigned int *word_length, unsigned int *stop_bits) 536 { 537 uint8_t val; 538 539 val = pio_read_8(port + 3); 540 541 *parity = ((val >> 3) & 7); 542 543 switch (val & 3) { 544 case WORD_LENGTH_5: 545 *word_length = 5; 546 break; 547 case WORD_LENGTH_6: 548 *word_length = 6; 549 break; 550 case WORD_LENGTH_7: 551 *word_length = 7; 552 break; 553 case WORD_LENGTH_8: 554 *word_length = 8; 555 break; 556 } 557 558 if ((val >> 2) & 1) { 559 *stop_bits = 2; 560 } else { 561 *stop_bits = 1; 562 } 563 } 564 565 /** Set the parameters of the serial communication on the serial port device. 566 * 567 * @param parity the parity to be used. 568 * @param word_length the length of one data unit in bits. 569 * @param stop_bits the number of stop bits used (one or two). 570 * 571 * @return 0 on success, EINVAL if some of the specified values is invalid. 572 */ 573 static int ns8250_port_set_com_props( 574 ioport8_t *port, unsigned int parity, unsigned int word_length, unsigned int stop_bits) 575 { 576 uint8_t val; 577 578 switch (word_length) { 579 case 5: 580 val = WORD_LENGTH_5; 581 break; 582 case 6: 583 val = WORD_LENGTH_6; 584 break; 585 case 7: 586 val = WORD_LENGTH_7; 587 break; 588 case 8: 589 val = WORD_LENGTH_8; 590 break; 591 default: 592 return EINVAL; 593 } 594 595 switch (stop_bits) { 596 case 1: 597 val |= ONE_STOP_BIT << 2; 598 break; 599 case 2: 600 val |= TWO_STOP_BITS << 2; 601 break; 602 default: 603 return EINVAL; 604 } 605 606 switch (parity) { 607 case SERIAL_NO_PARITY: 608 case SERIAL_ODD_PARITY: 609 case SERIAL_EVEN_PARITY: 610 case SERIAL_MARK_PARITY: 611 case SERIAL_SPACE_PARITY: 612 val |= parity << 3; 613 break; 614 default: 615 return EINVAL; 616 } 617 618 pio_write_8(port + 3, val); 619 620 return EOK; 621 } 622 623 /** Initialize the serial port device. 624 * 625 * Set the default parameters of the serial communication. 626 * 627 * @param dev the serial port device. 628 */ 629 static void ns8250_initialize_port(device_t *dev) 363 630 { 364 631 ns8250_dev_data_t *data = (ns8250_dev_data_t *)dev->driver_data; 365 632 ioport8_t *port = data->port; 366 int ret; 367 368 printf(NAME ": set baud rate %d for the device %s.\n", baud_rate, dev->name); 369 370 fibril_mutex_lock(&data->mutex); 371 ns8250_port_interrupts_disable(port); // Disable all interrupts 372 ret = ns8250_port_set_baud_rate(port, baud_rate); 373 ns8250_port_interrupts_enable(port); 374 fibril_mutex_unlock(&data->mutex); 375 376 return ret; 377 } 378 379 static void ns8250_initialize_port(device_t *dev) 380 { 381 ns8250_dev_data_t *data = (ns8250_dev_data_t *)dev->driver_data; 382 ioport8_t *port = data->port; 383 384 ns8250_port_interrupts_disable(port); // Disable all interrupts 633 634 // disable interrupts 635 ns8250_port_interrupts_disable(port); 636 // set baud rate 385 637 ns8250_port_set_baud_rate(port, 38400); 386 pio_write_8(port + 3, 0x07); // 8 bits, no parity, two stop bits 387 pio_write_8(port + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold 388 pio_write_8(port + 4, 0x0B); // RTS/DSR set (Request to Send and Data Terminal Ready lines enabled), 389 // Aux Output2 set - needed for interrupts 390 } 391 638 // 8 bits, no parity, two stop bits 639 ns8250_port_set_com_props(port, SERIAL_NO_PARITY, 8, 2); 640 // Enable FIFO, clear them, with 14-byte threshold 641 pio_write_8(port + 2, 0xC7); 642 // RTS/DSR set (Request to Send and Data Terminal Ready lines enabled), 643 // Aux Output2 set - needed for interrupts 644 pio_write_8(port + 4, 0x0B); 645 } 646 647 /** Read the data from the serial port device and store them to the input buffer. 648 * 649 * @param dev the serial port device. 650 */ 392 651 static void ns8250_read_from_device(device_t *dev) 393 652 { … … 399 658 fibril_mutex_lock(&data->mutex); 400 659 401 if (cont = ns8250_received(port)) { 660 cont = ns8250_received(port); 661 if (cont) { 402 662 uint8_t val = ns8250_read_8(port); 403 663 // printf(NAME ": character %c read from %s.\n", val, dev->name); … … 420 680 } 421 681 682 /** The interrupt handler. 683 * 684 * The serial port is initialized to interrupt when some data come, 685 * so the interrupt is handled by reading the incomming data. 686 * 687 * @param dev the serial port device. 688 */ 422 689 static inline void ns8250_interrupt_handler(device_t *dev, ipc_callid_t iid, ipc_call_t *icall) 423 690 { … … 425 692 } 426 693 694 /** Register the interrupt handler for the device. 695 * 696 * @param dev the serial port device. 697 */ 427 698 static inline int ns8250_register_interrupt_handler(device_t *dev) 428 699 { … … 432 703 } 433 704 705 /** Unregister the interrupt handler for the device. 706 * 707 * @param dev the serial port device. 708 */ 434 709 static inline int ns8250_unregister_interrupt_handler(device_t *dev) 435 710 { … … 439 714 } 440 715 716 /** The add_device callback method of the serial port driver. 717 * 718 * Probe and initialize the newly added device. 719 * 720 * @param dev the serial port device. 721 */ 441 722 static int ns8250_add_device(device_t *dev) 442 723 { … … 529 810 } 530 811 812 /** Get parameters of the serial communication which are set to the specified device. 813 * 814 * @param the serial port device. 815 * @param baud_rate the baud rate used by the device. 816 * @param the type of parity used by the device. 817 * @param word_length the size of one data unit in bits. 818 * @param stop_bits the number of stop bits used. 819 */ 820 static void ns8250_get_props(device_t *dev, unsigned int *baud_rate, 821 unsigned int *parity, unsigned int *word_length, unsigned int* stop_bits) 822 { 823 ns8250_dev_data_t *data = (ns8250_dev_data_t *)dev->driver_data; 824 ioport8_t *port = data->port; 825 826 fibril_mutex_lock(&data->mutex); 827 ns8250_port_interrupts_disable(port); // Disable all interrupts 828 *baud_rate = ns8250_port_get_baud_rate(port); 829 ns8250_port_get_com_props(port, parity, word_length, stop_bits); 830 ns8250_port_interrupts_enable(port); 831 fibril_mutex_unlock(&data->mutex); 832 833 printf(NAME ": ns8250_get_props: baud rate %d, parity 0x%x, word length %d, stop bits %d\n", 834 *baud_rate, *parity, *word_length, * stop_bits); 835 } 836 837 /** Set parameters of the serial communication to the specified serial port device. 838 * 839 * @param the serial port device. 840 * @param baud_rate the baud rate to be used by the device. 841 * @param the type of parity to be used by the device. 842 * @param word_length the size of one data unit in bits. 843 * @param stop_bits the number of stop bits to be used. 844 */ 845 static int ns8250_set_props(device_t *dev, unsigned int baud_rate, 846 unsigned int parity, unsigned int word_length, unsigned int stop_bits) 847 { 848 printf(NAME ": ns8250_set_props: baud rate %d, parity 0x%x, word length %d, stop bits %d\n", 849 baud_rate, parity, word_length, stop_bits); 850 851 ns8250_dev_data_t *data = (ns8250_dev_data_t *)dev->driver_data; 852 ioport8_t *port = data->port; 853 int ret; 854 855 fibril_mutex_lock(&data->mutex); 856 ns8250_port_interrupts_disable(port); // Disable all interrupts 857 ret = ns8250_port_set_baud_rate(port, baud_rate); 858 if (EOK == ret) { 859 ret = ns8250_port_set_com_props(port, parity, word_length, stop_bits); 860 } 861 ns8250_port_interrupts_enable(port); 862 fibril_mutex_unlock(&data->mutex); 863 864 return ret; 865 } 866 867 531 868 /** Default handler for client requests which are not handled by the standard interfaces. 532 869 * … … 537 874 ipcarg_t method = IPC_GET_METHOD(*call); 538 875 int ret; 876 unsigned int baud_rate, parity, word_length, stop_bits; 539 877 540 878 switch(method) { 541 case SERIAL_SET_BAUD_RATE: 542 ret = ns8250_set_baud_rate(dev, IPC_GET_ARG1(*call)); 879 case SERIAL_GET_COM_PROPS: 880 ns8250_get_props(dev, &baud_rate, &parity, &word_length, &stop_bits); 881 ipc_answer_4(callid, EOK, baud_rate, parity, word_length, stop_bits); 882 break; 883 884 case SERIAL_SET_COM_PROPS: 885 baud_rate = IPC_GET_ARG1(*call); 886 parity = IPC_GET_ARG2(*call); 887 word_length = IPC_GET_ARG3(*call); 888 stop_bits = IPC_GET_ARG4(*call); 889 ret = ns8250_set_props(dev, baud_rate, parity, word_length, stop_bits); 543 890 ipc_answer_0(callid, ret); 544 891 break; 545 case SERIAL_SET_PARITY: 546 // TODO 547 break; 548 case SERIAL_SET_STOP_BITS: 549 // TODO 550 break; 892 551 893 default: 552 894 ipc_answer_0(callid, ENOTSUP); 553 } 895 } 554 896 } 555 897
Note:
See TracChangeset
for help on using the changeset viewer.