Changes in uspace/drv/char/ns8250/ns8250.c [c7235d40:4510e06] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/char/ns8250/ns8250.c
rc7235d40 r4510e06 40 40 #include <stdio.h> 41 41 #include <errno.h> 42 #include < bool.h>42 #include <stdbool.h> 43 43 #include <fibril_synch.h> 44 44 #include <stdlib.h> … … 51 51 #include <sys/stat.h> 52 52 #include <ddi.h> 53 #include <libarch/ddi.h>54 53 55 54 #include <ddf/driver.h> … … 58 57 #include <ops/char_dev.h> 59 58 60 #include <devman.h>61 59 #include <ns.h> 62 #include <ipc/devman.h>63 60 #include <ipc/services.h> 64 61 #include <ipc/irc.h> … … 82 79 /** Interrupt ID Register definition. */ 83 80 #define NS8250_IID_ACTIVE (1 << 0) 81 #define NS8250_IID_CAUSE_MASK 0x0e 82 #define NS8250_IID_CAUSE_RXSTATUS 0x06 84 83 85 84 /** FIFO Control Register definition. */ … … 126 125 | NS8250_MSR_RI | NS8250_MSR_DCD) 127 126 128 /** Obtain soft-state structure from function node */129 #define NS8250(fnode) ((ns8250_t *) ((fnode)->dev->driver_data))130 131 /** Obtain soft-state structure from device node */132 #define NS8250_FROM_DEV(dnode) ((ns8250_t *) ((dnode)->driver_data))133 134 127 /** The number of bits of one data unit send by the serial port. */ 135 128 typedef enum { … … 167 160 /** I/O registers **/ 168 161 ns8250_regs_t *regs; 169 /** Is there any client conntected to the device? */170 bool client_connected;162 /** Are there any clients connected to the device? */ 163 unsigned client_connections; 171 164 /** The irq assigned to this device. */ 172 165 int irq; … … 175 168 /** The i/o port used to access the serial ports registers. */ 176 169 ioport8_t *port; 177 /** The buffer for incom ming data. */170 /** The buffer for incoming data. */ 178 171 cyclic_buffer_t input_buffer; 179 172 /** The fibril mutex for synchronizing the access to the device. */ 180 173 fibril_mutex_t mutex; 174 /** Indicates that some data has become available */ 175 fibril_condvar_t input_buffer_available; 181 176 /** True if device is removed. */ 182 177 bool removed; 183 178 } ns8250_t; 184 179 185 /** Find out if there is some incomming data available on the serial port. 180 /** Obtain soft-state structure from device node */ 181 static ns8250_t *dev_ns8250(ddf_dev_t *dev) 182 { 183 return ddf_dev_data_get(dev); 184 } 185 186 /** Obtain soft-state structure from function node */ 187 static ns8250_t *fun_ns8250(ddf_fun_t *fun) 188 { 189 return dev_ns8250(ddf_fun_get_dev(fun)); 190 } 191 192 /** Find out if there is some incoming data available on the serial port. 186 193 * 187 194 * @param port The base address of the serial port device's ports. … … 237 244 static int ns8250_read(ddf_fun_t *fun, char *buf, size_t count) 238 245 { 239 ns8250_t *ns = NS8250(fun); 240 int ret = EOK; 246 ns8250_t *ns = fun_ns8250(fun); 247 int ret = 0; 248 249 if (count == 0) return 0; 241 250 242 251 fibril_mutex_lock(&ns->mutex); 252 while (buf_is_empty(&ns->input_buffer)) 253 fibril_condvar_wait(&ns->input_buffer_available, &ns->mutex); 243 254 while (!buf_is_empty(&ns->input_buffer) && (size_t)ret < count) { 244 255 buf[ret] = (char)buf_pop_front(&ns->input_buffer); … … 271 282 static int ns8250_write(ddf_fun_t *fun, char *buf, size_t count) 272 283 { 273 ns8250_t *ns = NS8250(fun);284 ns8250_t *ns = fun_ns8250(fun); 274 285 size_t idx; 275 286 … … 309 320 static void ns8250_dev_cleanup(ns8250_t *ns) 310 321 { 311 if (ns->dev->parent_sess) {312 async_hangup(ns->dev->parent_sess);313 ns->dev->parent_sess = NULL;314 }315 322 } 316 323 … … 322 329 static bool ns8250_pio_enable(ns8250_t *ns) 323 330 { 324 ddf_msg(LVL_DEBUG, "ns8250_pio_enable %s", ns->dev->name);331 ddf_msg(LVL_DEBUG, "ns8250_pio_enable %s", ddf_dev_get_name(ns->dev)); 325 332 326 333 /* Gain control over port's registers. */ … … 328 335 (void **) &ns->port)) { 329 336 ddf_msg(LVL_ERROR, "Cannot map the port %#" PRIx32 330 " for device %s.", ns->io_addr, ns->dev->name);337 " for device %s.", ns->io_addr, ddf_dev_get_name(ns->dev)); 331 338 return false; 332 339 } … … 344 351 static bool ns8250_dev_probe(ns8250_t *ns) 345 352 { 346 ddf_msg(LVL_DEBUG, "ns8250_dev_probe %s", ns->dev->name);353 ddf_msg(LVL_DEBUG, "ns8250_dev_probe %s", ddf_dev_get_name(ns->dev)); 347 354 348 355 bool res = true; … … 364 371 if (!res) { 365 372 ddf_msg(LVL_DEBUG, "Device %s is not present.", 366 ns->dev->name);373 ddf_dev_get_name(ns->dev)); 367 374 } 368 375 … … 377 384 static int ns8250_dev_initialize(ns8250_t *ns) 378 385 { 379 ddf_msg(LVL_DEBUG, "ns8250_dev_initialize %s", ns->dev->name); 380 386 async_sess_t *parent_sess; 381 387 int ret = EOK; 388 389 ddf_msg(LVL_DEBUG, "ns8250_dev_initialize %s", ddf_dev_get_name(ns->dev)); 382 390 383 391 hw_resource_list_t hw_resources; … … 385 393 386 394 /* Connect to the parent's driver. */ 387 ns->dev->parent_sess = devman_parent_device_connect(EXCHANGE_SERIALIZE, 388 ns->dev->handle, IPC_FLAG_BLOCKING); 389 if (!ns->dev->parent_sess) { 395 parent_sess = ddf_dev_parent_sess_create(ns->dev, EXCHANGE_SERIALIZE); 396 if (parent_sess == NULL) { 390 397 ddf_msg(LVL_ERROR, "Failed to connect to parent driver of " 391 "device %s.", ns->dev->name);398 "device %s.", ddf_dev_get_name(ns->dev)); 392 399 ret = ENOENT; 393 400 goto failed; … … 395 402 396 403 /* Get hw resources. */ 397 ret = hw_res_get_resource_list( ns->dev->parent_sess, &hw_resources);404 ret = hw_res_get_resource_list(parent_sess, &hw_resources); 398 405 if (ret != EOK) { 399 406 ddf_msg(LVL_ERROR, "Failed to get HW resources for device " 400 "%s.", ns->dev->name);407 "%s.", ddf_dev_get_name(ns->dev)); 401 408 goto failed; 402 409 } … … 414 421 irq = true; 415 422 ddf_msg(LVL_NOTE, "Device %s was asigned irq = 0x%x.", 416 ns->dev->name, ns->irq);423 ddf_dev_get_name(ns->dev), ns->irq); 417 424 break; 418 425 … … 421 428 if (res->res.io_range.size < REG_COUNT) { 422 429 ddf_msg(LVL_ERROR, "I/O range assigned to " 423 "device %s is too small.", ns->dev->name);430 "device %s is too small.", ddf_dev_get_name(ns->dev)); 424 431 ret = ELIMIT; 425 432 goto failed; … … 427 434 ioport = true; 428 435 ddf_msg(LVL_NOTE, "Device %s was asigned I/O address = " 429 "0x%x.", ns->dev->name, ns->io_addr);436 "0x%x.", ddf_dev_get_name(ns->dev), ns->io_addr); 430 437 break; 431 438 … … 437 444 if (!irq || !ioport) { 438 445 ddf_msg(LVL_ERROR, "Missing HW resource(s) for device %s.", 439 ns->dev->name);446 ddf_dev_get_name(ns->dev)); 440 447 ret = ENOENT; 441 448 goto failed; … … 460 467 { 461 468 /* Interrupt when data received. */ 462 pio_write_8(®s->ier, NS8250_IER_RXREADY );469 pio_write_8(®s->ier, NS8250_IER_RXREADY | NS8250_IER_RXSTATUS); 463 470 pio_write_8(®s->mcr, NS8250_MCR_DTR | NS8250_MCR_RTS 464 471 | NS8250_MCR_OUT2); … … 499 506 async_exchange_end(exch); 500 507 508 /* Read LSR to clear possible previous LSR interrupt */ 509 pio_read_8(&ns->regs->lsr); 510 501 511 /* Enable interrupt on the serial port. */ 502 512 ns8250_port_interrupts_enable(ns->regs); … … 602 612 *parity = ((val >> NS8250_LCR_PARITY) & 7); 603 613 614 /* Silence warnings */ 615 *word_length = 0; 616 604 617 switch (val & 3) { 605 618 case WORD_LENGTH_5: … … 695 708 /* 8 bits, no parity, two stop bits. */ 696 709 ns8250_port_set_com_props(ns->regs, SERIAL_NO_PARITY, 8, 2); 697 /* Enable FIFO, clear them, with 14-byte threshold. */ 710 /* 711 * Enable FIFO, clear them, with 4-byte threshold for greater 712 * reliability. 713 */ 698 714 pio_write_8(&ns->regs->iid, NS8250_FCR_FIFOENABLE 699 | NS8250_FCR_RXFIFORESET | NS8250_FCR_TXFIFORESET 700 | NS8250_FCR_RXTRIGGERLOW | NS8250_FCR_RXTRIGGERHI);715 | NS8250_FCR_RXFIFORESET | NS8250_FCR_TXFIFORESET 716 | NS8250_FCR_RXTRIGGERLOW); 701 717 /* 702 718 * RTS/DSR set (Request to Send and Data Terminal Ready lines enabled), … … 731 747 bool cont = true; 732 748 749 fibril_mutex_lock(&ns->mutex); 733 750 while (cont) { 734 fibril_mutex_lock(&ns->mutex);735 736 751 cont = ns8250_received(regs); 737 752 if (cont) { 738 753 uint8_t val = ns8250_read_8(regs); 739 754 740 if (ns->client_connected) { 755 if (ns->client_connections > 0) { 756 bool buf_was_empty = buf_is_empty(&ns->input_buffer); 741 757 if (!buf_push_back(&ns->input_buffer, val)) { 742 758 ddf_msg(LVL_WARN, "Buffer overflow on " 743 "%s.", ns->dev->name); 759 "%s.", ddf_dev_get_name(ns->dev)); 760 break; 744 761 } else { 745 762 ddf_msg(LVL_DEBUG2, "Character %c saved " 746 763 "to the buffer of %s.", 747 val, ns->dev->name); 764 val, ddf_dev_get_name(ns->dev)); 765 if (buf_was_empty) 766 fibril_condvar_broadcast(&ns->input_buffer_available); 748 767 } 749 768 } 750 769 } 751 752 fibril_mutex_unlock(&ns->mutex); 753 fibril_yield(); 754 } 770 } 771 fibril_mutex_unlock(&ns->mutex); 772 fibril_yield(); 755 773 } 756 774 757 775 /** The interrupt handler. 758 776 * 759 * The serial port is initialized to interrupt when some data come, so the 760 * interrupt is handled by reading the incomming data. 777 * The serial port is initialized to interrupt when some data come or line 778 * status register changes, so the interrupt is handled by reading the incoming 779 * data and reading the line status register. 761 780 * 762 781 * @param dev The serial port device. … … 765 784 ipc_call_t *icall) 766 785 { 767 ns8250_read_from_device(NS8250_FROM_DEV(dev)); 786 ns8250_t *ns = dev_ns8250(dev); 787 788 uint8_t iir = pio_read_8(&ns->regs->iid); 789 if ((iir & NS8250_IID_CAUSE_MASK) == NS8250_IID_CAUSE_RXSTATUS) { 790 uint8_t lsr = pio_read_8(&ns->regs->lsr); 791 if (lsr & NS8250_LSR_OE) { 792 ddf_msg(LVL_WARN, "Overrun error on %s", ddf_dev_get_name(ns->dev)); 793 } 794 } 795 796 ns8250_read_from_device(ns); 768 797 } 769 798 … … 801 830 802 831 ddf_msg(LVL_DEBUG, "ns8250_dev_add %s (handle = %d)", 803 d ev->name, (int) dev->handle);832 ddf_dev_get_name(dev), (int) ddf_dev_get_handle(dev)); 804 833 805 834 /* Allocate soft-state for the device */ … … 811 840 812 841 fibril_mutex_initialize(&ns->mutex); 842 fibril_condvar_initialize(&ns->input_buffer_available); 813 843 ns->dev = dev; 814 844 … … 855 885 856 886 /* Set device operations. */ 857 fun->ops = &ns8250_dev_ops;887 ddf_fun_set_ops(fun, &ns8250_dev_ops); 858 888 rc = ddf_fun_bind(fun); 859 889 if (rc != EOK) { … … 867 897 868 898 ddf_msg(LVL_NOTE, "Device %s successfully initialized.", 869 d ev->name);899 ddf_dev_get_name(dev)); 870 900 871 901 return EOK; … … 880 910 static int ns8250_dev_remove(ddf_dev_t *dev) 881 911 { 882 ns8250_t *ns = NS8250_FROM_DEV(dev);912 ns8250_t *ns = dev_ns8250(dev); 883 913 int rc; 884 914 885 915 fibril_mutex_lock(&ns->mutex); 886 if (ns->client_connected) {916 if (ns->client_connections > 0) { 887 917 fibril_mutex_unlock(&ns->mutex); 888 918 return EBUSY; … … 914 944 static int ns8250_open(ddf_fun_t *fun) 915 945 { 916 ns8250_t *ns = NS8250(fun);946 ns8250_t *ns = fun_ns8250(fun); 917 947 int res; 918 948 919 949 fibril_mutex_lock(&ns->mutex); 920 if (ns->client_connected) { 921 res = ELIMIT; 922 } else if (ns->removed) { 950 if (ns->removed) { 923 951 res = ENXIO; 924 952 } else { 925 953 res = EOK; 926 ns->client_connect ed = true;954 ns->client_connections++; 927 955 } 928 956 fibril_mutex_unlock(&ns->mutex); … … 940 968 static void ns8250_close(ddf_fun_t *fun) 941 969 { 942 ns8250_t *data = (ns8250_t *) fun->dev->driver_data;970 ns8250_t *data = fun_ns8250(fun); 943 971 944 972 fibril_mutex_lock(&data->mutex); 945 973 946 assert(data->client_connect ed);947 948 data->client_connected = false;949 buf_clear(&data->input_buffer);974 assert(data->client_connections > 0); 975 976 if (!(--data->client_connections)) 977 buf_clear(&data->input_buffer); 950 978 951 979 fibril_mutex_unlock(&data->mutex); … … 965 993 unsigned int *word_length, unsigned int* stop_bits) 966 994 { 967 ns8250_t *data = (ns8250_t *) dev->driver_data;995 ns8250_t *data = dev_ns8250(dev); 968 996 ns8250_regs_t *regs = data->regs; 969 997 … … 996 1024 stop_bits); 997 1025 998 ns8250_t *data = (ns8250_t *) dev->driver_data;1026 ns8250_t *data = dev_ns8250(dev); 999 1027 ns8250_regs_t *regs = data->regs; 1000 1028 int ret; … … 1025 1053 switch (method) { 1026 1054 case SERIAL_GET_COM_PROPS: 1027 ns8250_get_props( fun->dev, &baud_rate, &parity, &word_length,1055 ns8250_get_props(ddf_fun_get_dev(fun), &baud_rate, &parity, &word_length, 1028 1056 &stop_bits); 1029 1057 async_answer_4(callid, EOK, baud_rate, parity, word_length, … … 1036 1064 word_length = IPC_GET_ARG3(*call); 1037 1065 stop_bits = IPC_GET_ARG4(*call); 1038 ret = ns8250_set_props( fun->dev, baud_rate, parity, word_length,1066 ret = ns8250_set_props(ddf_fun_get_dev(fun), baud_rate, parity, word_length, 1039 1067 stop_bits); 1040 1068 async_answer_0(callid, ret); … … 1053 1081 static void ns8250_init(void) 1054 1082 { 1055 ddf_log_init(NAME , LVL_ERROR);1083 ddf_log_init(NAME); 1056 1084 1057 1085 ns8250_dev_ops.open = &ns8250_open;
Note:
See TracChangeset
for help on using the changeset viewer.