Changeset 68414f4a in mainline for uspace/drv/ns8250/ns8250.c
- Timestamp:
- 2011-02-13T20:03:45Z (14 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- bab6388
- Parents:
- 8b1e15ac
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/ns8250/ns8250.c
r8b1e15ac r68414f4a 1 /* 1 /* 2 2 * Copyright (c) 2010 Lenka Trochtova 3 * Copyright (c) 2011 Jiri Svoboda 3 4 * All rights reserved. 4 5 * … … 68 69 #define DLAB_MASK (1 << 7) 69 70 71 /** Obtain soft-state structure from function node */ 72 #define NS8250(fnode) ((ns8250_t *) ((fnode)->dev->driver_data)) 73 74 /** Obtain soft-state structure from device node */ 75 #define NS8250_FROM_DEV(dnode) ((ns8250_t *) ((dnode)->driver_data)) 76 70 77 /** The number of bits of one data unit send by the serial port. */ 71 78 typedef enum { … … 85 92 86 93 /** The driver data for the serial port devices. */ 87 typedef struct ns8250_dev_data { 94 typedef struct ns8250 { 95 /** DDF device node */ 96 device_t *dev; 97 /** DDF function node */ 98 function_t *fun; 88 99 /** Is there any client conntected to the device? */ 89 100 bool client_connected; … … 98 109 /** The fibril mutex for synchronizing the access to the device. */ 99 110 fibril_mutex_t mutex; 100 } ns8250_dev_data_t; 101 102 /** Create driver data for a device. 103 * 104 * @return The driver data. 105 */ 106 static ns8250_dev_data_t *create_ns8250_dev_data(void) 107 { 108 ns8250_dev_data_t *data; 109 110 data = (ns8250_dev_data_t *) malloc(sizeof(ns8250_dev_data_t)); 111 if (NULL != data) { 112 memset(data, 0, sizeof(ns8250_dev_data_t)); 113 fibril_mutex_initialize(&data->mutex); 114 } 115 return data; 116 } 117 118 /** Delete driver data. 119 * 120 * @param data The driver data structure. 121 */ 122 static void delete_ns8250_dev_data(ns8250_dev_data_t *data) 123 { 124 if (data != NULL) 125 free(data); 111 } ns8250_t; 112 113 /** Create per-device soft-state structure. 114 * 115 * @return Pointer to soft-state structure. 116 */ 117 static ns8250_t *ns8250_new(void) 118 { 119 ns8250_t *ns; 120 121 ns = (ns8250_t *) calloc(1, sizeof(ns8250_t)); 122 if (ns == NULL) 123 return NULL; 124 125 fibril_mutex_initialize(&ns->mutex); 126 return ns; 127 } 128 129 /** Delete soft-state structure. 130 * 131 * @param ns The driver data structure. 132 */ 133 static void ns8250_delete(ns8250_t *ns) 134 { 135 free(ns); 126 136 } 127 137 … … 171 181 /** Read data from the serial port device. 172 182 * 173 * @param dev The serial port device.183 * @param fun The serial port function 174 184 * @param buf The ouput buffer for read data. 175 185 * @param count The number of bytes to be read. … … 180 190 static int ns8250_read(function_t *fun, char *buf, size_t count) 181 191 { 192 ns8250_t *ns = NS8250(fun); 182 193 int ret = EOK; 183 ns8250_dev_data_t *data = (ns8250_dev_data_t *) fun->dev->driver_data; 184 185 fibril_mutex_lock(&data->mutex); 186 while (!buf_is_empty(&data->input_buffer) && (size_t)ret < count) { 187 buf[ret] = (char)buf_pop_front(&data->input_buffer); 194 195 fibril_mutex_lock(&ns->mutex); 196 while (!buf_is_empty(&ns->input_buffer) && (size_t)ret < count) { 197 buf[ret] = (char)buf_pop_front(&ns->input_buffer); 188 198 ret++; 189 199 } 190 fibril_mutex_unlock(& data->mutex);200 fibril_mutex_unlock(&ns->mutex); 191 201 192 202 return ret; … … 195 205 /** Write a character to the serial port. 196 206 * 197 * @param data The serial port device's driver data.198 * @param c The character to be written .199 */ 200 static inline void ns8250_putchar(ns8250_ dev_data_t *data, uint8_t c)201 { 202 fibril_mutex_lock(& data->mutex);203 ns8250_write_8( data->port, c);204 fibril_mutex_unlock(& data->mutex);207 * @param ns Serial port device 208 * @param c The character to be written 209 */ 210 static inline void ns8250_putchar(ns8250_t *ns, uint8_t c) 211 { 212 fibril_mutex_lock(&ns->mutex); 213 ns8250_write_8(ns->port, c); 214 fibril_mutex_unlock(&ns->mutex); 205 215 } 206 216 207 217 /** Write data to the serial port. 208 218 * 209 * @param dev The serial port device.210 * @param buf The data to be written .211 * @param count The number of bytes to be written .212 * @return Zero on success .219 * @param fun The serial port function 220 * @param buf The data to be written 221 * @param count The number of bytes to be written 222 * @return Zero on success 213 223 */ 214 224 static int ns8250_write(function_t *fun, char *buf, size_t count) 215 225 { 216 ns8250_ dev_data_t *data = (ns8250_dev_data_t *) fun->dev->driver_data;226 ns8250_t *ns = NS8250(fun); 217 227 size_t idx; 218 228 219 229 for (idx = 0; idx < count; idx++) 220 ns8250_putchar( data, (uint8_t) buf[idx]);230 ns8250_putchar(ns, (uint8_t) buf[idx]); 221 231 222 232 return 0; … … 244 254 }; 245 255 246 /** Clean up the serial port device structure. 247 * 248 * @param dev The device structure. 249 */ 250 static void ns8250_dev_cleanup(device_t *dev) 251 { 252 if (dev->driver_data != NULL) { 253 delete_ns8250_dev_data((ns8250_dev_data_t*) dev->driver_data); 254 dev->driver_data = NULL; 255 } 256 257 if (dev->parent_phone > 0) { 258 async_hangup(dev->parent_phone); 259 dev->parent_phone = 0; 256 /** Clean up the serial port soft-state 257 * 258 * @param ns Serial port device 259 */ 260 static void ns8250_dev_cleanup(ns8250_t *ns) 261 { 262 if (ns->dev->parent_phone > 0) { 263 async_hangup(ns->dev->parent_phone); 264 ns->dev->parent_phone = 0; 260 265 } 261 266 } … … 263 268 /** Enable the i/o ports of the device. 264 269 * 265 * @param dev The serial port device. 266 * @return True on success, false otherwise. 267 */ 268 static bool ns8250_pio_enable(device_t *dev) 269 { 270 printf(NAME ": ns8250_pio_enable %s\n", dev->name); 271 272 ns8250_dev_data_t *data = (ns8250_dev_data_t *)dev->driver_data; 270 * @param ns Serial port device 271 * @return True on success, false otherwise 272 */ 273 static bool ns8250_pio_enable(ns8250_t *ns) 274 { 275 printf(NAME ": ns8250_pio_enable %s\n", ns->dev->name); 273 276 274 277 /* Gain control over port's registers. */ 275 if (pio_enable((void *)(uintptr_t) data->io_addr, REG_COUNT,276 (void **) & data->port)) {278 if (pio_enable((void *)(uintptr_t) ns->io_addr, REG_COUNT, 279 (void **) &ns->port)) { 277 280 printf(NAME ": error - cannot gain the port %#" PRIx32 " for device " 278 "%s.\n", data->io_addr,dev->name);281 "%s.\n", ns->io_addr, ns->dev->name); 279 282 return false; 280 283 } … … 285 288 /** Probe the serial port device for its presence. 286 289 * 287 * @param dev The serial port device. 288 * @return True if the device is present, false otherwise. 289 */ 290 static bool ns8250_dev_probe(device_t *dev) 291 { 292 printf(NAME ": ns8250_dev_probe %s\n", dev->name); 293 294 ns8250_dev_data_t *data = (ns8250_dev_data_t *) dev->driver_data; 295 ioport8_t *port_addr = data->port; 290 * @param ns Serial port device 291 * @return True if the device is present, false otherwise 292 */ 293 static bool ns8250_dev_probe(ns8250_t *ns) 294 { 295 printf(NAME ": ns8250_dev_probe %s\n", ns->dev->name); 296 297 ioport8_t *port_addr = ns->port; 296 298 bool res = true; 297 299 uint8_t olddata; … … 310 312 311 313 if (!res) 312 printf(NAME ": device %s is not present.\n", dev->name);314 printf(NAME ": device %s is not present.\n", ns->dev->name); 313 315 314 316 return res; … … 317 319 /** Initialize serial port device. 318 320 * 319 * @param dev The serial port device.320 * @return Zero on success, negative error number otherwise .321 */ 322 static int ns8250_dev_initialize( device_t *dev)323 { 324 printf(NAME ": ns8250_dev_initialize %s\n", dev->name);321 * @param ns Serial port device 322 * @return Zero on success, negative error number otherwise 323 */ 324 static int ns8250_dev_initialize(ns8250_t *ns) 325 { 326 printf(NAME ": ns8250_dev_initialize %s\n", ns->dev->name); 325 327 326 328 int ret = EOK; … … 329 331 memset(&hw_resources, 0, sizeof(hw_resource_list_t)); 330 332 331 /* Allocate driver data for the device. */332 ns8250_dev_data_t *data = create_ns8250_dev_data();333 if (data == NULL)334 return ENOMEM;335 dev->driver_data = data;336 337 333 /* Connect to the parent's driver. */ 338 dev->parent_phone = devman_parent_device_connect(dev->handle,334 ns->dev->parent_phone = devman_parent_device_connect(ns->dev->handle, 339 335 IPC_FLAG_BLOCKING); 340 if ( dev->parent_phone < 0) {336 if (ns->dev->parent_phone < 0) { 341 337 printf(NAME ": failed to connect to the parent driver of the " 342 "device %s.\n", dev->name);343 ret = dev->parent_phone;338 "device %s.\n", ns->dev->name); 339 ret = ns->dev->parent_phone; 344 340 goto failed; 345 341 } 346 342 347 343 /* Get hw resources. */ 348 ret = hw_res_get_resource_list( dev->parent_phone, &hw_resources);344 ret = hw_res_get_resource_list(ns->dev->parent_phone, &hw_resources); 349 345 if (ret != EOK) { 350 346 printf(NAME ": failed to get hw resources for the device " 351 "%s.\n", dev->name);347 "%s.\n", ns->dev->name); 352 348 goto failed; 353 349 } … … 362 358 switch (res->type) { 363 359 case INTERRUPT: 364 data->irq = res->res.interrupt.irq;360 ns->irq = res->res.interrupt.irq; 365 361 irq = true; 366 362 printf(NAME ": the %s device was asigned irq = 0x%x.\n", 367 dev->name, data->irq);363 ns->dev->name, ns->irq); 368 364 break; 369 365 370 366 case IO_RANGE: 371 data->io_addr = res->res.io_range.address;367 ns->io_addr = res->res.io_range.address; 372 368 if (res->res.io_range.size < REG_COUNT) { 373 369 printf(NAME ": i/o range assigned to the device " 374 "%s is too small.\n", dev->name);370 "%s is too small.\n", ns->dev->name); 375 371 ret = ELIMIT; 376 372 goto failed; … … 378 374 ioport = true; 379 375 printf(NAME ": the %s device was asigned i/o address = " 380 "0x%x.\n", dev->name, data->io_addr);376 "0x%x.\n", ns->dev->name, ns->io_addr); 381 377 break; 382 378 … … 388 384 if (!irq || !ioport) { 389 385 printf(NAME ": missing hw resource(s) for the device %s.\n", 390 dev->name);386 ns->dev->name); 391 387 ret = ENOENT; 392 388 goto failed; … … 397 393 398 394 failed: 399 ns8250_dev_cleanup( dev);395 ns8250_dev_cleanup(ns); 400 396 hw_res_clean_resource_list(&hw_resources); 401 397 return ret; … … 404 400 /** Enable interrupts on the serial port device. 405 401 * 406 * Interrupt when data is received .402 * Interrupt when data is received 407 403 * 408 404 * @param port The base address of the serial port device's ports. … … 416 412 /** Disable interrupts on the serial port device. 417 413 * 418 * @param port The base address of the serial port device's ports .414 * @param port The base address of the serial port device's ports 419 415 */ 420 416 static inline void ns8250_port_interrupts_disable(ioport8_t *port) … … 425 421 /** Enable interrupts for the serial port device. 426 422 * 427 * @param dev The device. 428 * @return Zero on success, negative error number otherwise. 429 */ 430 static int ns8250_interrupt_enable(device_t *dev) 431 { 432 ns8250_dev_data_t *data = (ns8250_dev_data_t *) dev->driver_data; 433 423 * @param ns Serial port device 424 * @return Zero on success, negative error number otherwise 425 */ 426 static int ns8250_interrupt_enable(ns8250_t *ns) 427 { 434 428 /* Enable interrupt on the serial port. */ 435 ns8250_port_interrupts_enable( data->port);429 ns8250_port_interrupts_enable(ns->port); 436 430 437 431 return EOK; … … 618 612 * Set the default parameters of the serial communication. 619 613 * 620 * @param dev The serial port device. 621 */ 622 static void ns8250_initialize_port(device_t *dev) 623 { 624 ns8250_dev_data_t *data = (ns8250_dev_data_t *)dev->driver_data; 625 ioport8_t *port = data->port; 614 * @param ns Serial port device 615 */ 616 static void ns8250_initialize_port(ns8250_t *ns) 617 { 618 ioport8_t *port = ns->port; 626 619 627 620 /* Disable interrupts. */ … … 643 636 * buffer. 644 637 * 645 * @param dev The serial port device. 646 */ 647 static void ns8250_read_from_device(device_t *dev) 648 { 649 ns8250_dev_data_t *data = (ns8250_dev_data_t *) dev->driver_data; 650 ioport8_t *port = data->port; 638 * @param ns Serial port device 639 */ 640 static void ns8250_read_from_device(ns8250_t *ns) 641 { 642 ioport8_t *port = ns->port; 651 643 bool cont = true; 652 644 653 645 while (cont) { 654 fibril_mutex_lock(& data->mutex);646 fibril_mutex_lock(&ns->mutex); 655 647 656 648 cont = ns8250_received(port); … … 658 650 uint8_t val = ns8250_read_8(port); 659 651 660 if ( data->client_connected) {661 if (!buf_push_back(& data->input_buffer, val)) {652 if (ns->client_connected) { 653 if (!buf_push_back(&ns->input_buffer, val)) { 662 654 printf(NAME ": buffer overflow on " 663 "%s.\n", dev->name);655 "%s.\n", ns->dev->name); 664 656 } else { 665 657 printf(NAME ": the character %c saved " 666 658 "to the buffer of %s.\n", 667 val, dev->name);659 val, ns->dev->name); 668 660 } 669 661 } 670 662 } 671 663 672 fibril_mutex_unlock(& data->mutex);664 fibril_mutex_unlock(&ns->mutex); 673 665 fibril_yield(); 674 666 } … … 685 677 ipc_call_t *icall) 686 678 { 687 ns8250_read_from_device( dev);679 ns8250_read_from_device(NS8250_FROM_DEV(dev)); 688 680 } 689 681 690 682 /** Register the interrupt handler for the device. 691 683 * 684 * @param ns Serial port device 685 */ 686 static inline int ns8250_register_interrupt_handler(ns8250_t *ns) 687 { 688 return register_interrupt_handler(ns->dev, ns->irq, 689 ns8250_interrupt_handler, NULL); 690 } 691 692 /** Unregister the interrupt handler for the device. 693 * 694 * @param ns Serial port device 695 */ 696 static inline int ns8250_unregister_interrupt_handler(ns8250_t *ns) 697 { 698 return unregister_interrupt_handler(ns->dev, ns->irq); 699 } 700 701 /** The add_device callback method of the serial port driver. 702 * 703 * Probe and initialize the newly added device. 704 * 692 705 * @param dev The serial port device. 693 706 */ 694 static inline int ns8250_register_interrupt_handler(device_t *dev)695 {696 ns8250_dev_data_t *data = (ns8250_dev_data_t *) dev->driver_data;697 698 return register_interrupt_handler(dev, data->irq,699 ns8250_interrupt_handler, NULL);700 }701 702 /** Unregister the interrupt handler for the device.703 *704 * @param dev The serial port device.705 */706 static inline int ns8250_unregister_interrupt_handler(device_t *dev)707 {708 ns8250_dev_data_t *data = (ns8250_dev_data_t *) dev->driver_data;709 710 return unregister_interrupt_handler(dev, data->irq);711 }712 713 /** The add_device callback method of the serial port driver.714 *715 * Probe and initialize the newly added device.716 *717 * @param dev The serial port device.718 */719 707 static int ns8250_add_device(device_t *dev) 720 708 { 721 function_t *fun; 722 709 ns8250_t *ns = NULL; 710 function_t *fun = NULL; 711 bool need_cleanup = false; 712 int rc; 713 723 714 printf(NAME ": ns8250_add_device %s (handle = %d)\n", 724 715 dev->name, (int) dev->handle); 725 716 726 int res = ns8250_dev_initialize(dev); 727 if (res != EOK) 728 return res; 729 730 if (!ns8250_pio_enable(dev)) { 731 ns8250_dev_cleanup(dev); 732 return EADDRNOTAVAIL; 717 /* Allocate soft-state for the device */ 718 ns = ns8250_new(); 719 if (ns == NULL) { 720 rc = ENOMEM; 721 goto fail; 722 } 723 724 ns->dev = dev; 725 dev->driver_data = ns; 726 727 rc = ns8250_dev_initialize(ns); 728 if (rc != EOK) 729 goto fail; 730 731 need_cleanup = true; 732 733 if (!ns8250_pio_enable(ns)) { 734 rc = EADDRNOTAVAIL; 735 goto fail; 733 736 } 734 737 735 738 /* Find out whether the device is present. */ 736 if (!ns8250_dev_probe( dev)) {737 ns8250_dev_cleanup(dev);738 return ENOENT;739 if (!ns8250_dev_probe(ns)) { 740 rc = ENOENT; 741 goto fail; 739 742 } 740 743 741 744 /* Serial port initialization (baud rate etc.). */ 742 ns8250_initialize_port( dev);745 ns8250_initialize_port(ns); 743 746 744 747 /* Register interrupt handler. */ 745 if (ns8250_register_interrupt_handler( dev) != EOK) {748 if (ns8250_register_interrupt_handler(ns) != EOK) { 746 749 printf(NAME ": failed to register interrupt handler.\n"); 747 ns8250_dev_cleanup(dev);748 return res;750 rc = EADDRNOTAVAIL; 751 goto fail; 749 752 } 750 753 751 754 /* Enable interrupt. */ 752 r es = ns8250_interrupt_enable(dev);753 if (r es!= EOK) {755 rc = ns8250_interrupt_enable(ns); 756 if (rc != EOK) { 754 757 printf(NAME ": failed to enable the interrupt. Error code = " 755 "%d.\n", res); 756 ns8250_dev_cleanup(dev); 757 ns8250_unregister_interrupt_handler(dev); 758 return res; 759 } 760 758 "%d.\n", rc); 759 goto fail; 760 } 761 761 762 fun = create_function(); 762 763 fun->ftype = fun_exposed; … … 766 767 fun->ops = &ns8250_dev_ops; 767 768 register_function(fun, dev); 769 ns->fun = fun; 768 770 769 771 add_function_to_class(fun, "serial"); … … 773 775 774 776 return EOK; 777 fail: 778 if (need_cleanup) 779 ns8250_dev_cleanup(ns); 780 if (ns != NULL) 781 ns8250_delete(ns); 782 return rc; 775 783 } 776 784 … … 784 792 static int ns8250_open(function_t *fun) 785 793 { 786 ns8250_ dev_data_t *data = (ns8250_dev_data_t *) fun->dev->driver_data;794 ns8250_t *data = (ns8250_t *) fun->dev->driver_data; 787 795 int res; 788 796 … … 808 816 static void ns8250_close(function_t *fun) 809 817 { 810 ns8250_ dev_data_t *data = (ns8250_dev_data_t *) fun->dev->driver_data;818 ns8250_t *data = (ns8250_t *) fun->dev->driver_data; 811 819 812 820 fibril_mutex_lock(&data->mutex); … … 833 841 unsigned int *word_length, unsigned int* stop_bits) 834 842 { 835 ns8250_ dev_data_t *data = (ns8250_dev_data_t *) dev->driver_data;843 ns8250_t *data = (ns8250_t *) dev->driver_data; 836 844 ioport8_t *port = data->port; 837 845 … … 864 872 stop_bits); 865 873 866 ns8250_ dev_data_t *data = (ns8250_dev_data_t *) dev->driver_data;874 ns8250_t *data = (ns8250_t *) dev->driver_data; 867 875 ioport8_t *port = data->port; 868 876 int ret;
Note:
See TracChangeset
for help on using the changeset viewer.