Changeset 49698fa in mainline
- Timestamp:
- 2010-10-23T10:25:37Z (14 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 663f41c4
- Parents:
- 472020fc
- Location:
- uspace/drv/ns8250
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/ns8250/cyclic_buffer.h
r472020fc r49698fa 1 1 /* 2 * Copyright (c) 2010 Lenka Trochtova 2 * Copyright (c) 2010 Lenka Trochtova 3 3 * All rights reserved. 4 4 * … … 32 32 /** @file 33 33 */ 34 35 #ifndef CYCLIC_BUFFER_H36 #define CYCLIC_BUFFER_H37 34 38 #define BUF_LEN 256 // the length of the buffer 35 #ifndef CYCLIC_BUFFER_H_ 36 #define CYCLIC_BUFFER_H_ 37 38 #define BUF_LEN 256 39 39 40 40 typedef struct cyclic_buffer { 41 uint8_t buf[BUF_LEN]; // the buffer41 uint8_t buf[BUF_LEN]; 42 42 int start; 43 43 int cnt; 44 } cyclic_buffer_t; 44 } cyclic_buffer_t; 45 45 46 // returns false if the buffer is full 47 static inline bool buf_push_back(cyclic_buffer_t *buf, uint8_t item) 46 /* 47 * @returns False if the buffer is full. 48 */ 49 static inline bool buf_push_back(cyclic_buffer_t *buf, uint8_t item) 48 50 { 49 if (buf->cnt >= BUF_LEN) {51 if (buf->cnt >= BUF_LEN) 50 52 return false; 51 }52 53 53 int pos = (buf->start + buf->cnt) % BUF_LEN; 54 54 buf->buf[pos] = item; … … 57 57 } 58 58 59 static inline bool buf_is_empty(cyclic_buffer_t *buf) 59 static inline bool buf_is_empty(cyclic_buffer_t *buf) 60 60 { 61 61 return buf->cnt == 0; 62 62 } 63 63 64 // call it on non empty buffer! 65 static inline uint8_t buf_pop_front(cyclic_buffer_t *buf) 64 static inline uint8_t buf_pop_front(cyclic_buffer_t *buf) 66 65 { 67 66 assert(!buf_is_empty(buf)); 68 67 69 68 uint8_t res = buf->buf[buf->start]; 70 buf->start = (buf->start + 1) % BUF_LEN; 69 buf->start = (buf->start + 1) % BUF_LEN; 71 70 buf->cnt--; 72 71 return res; 73 72 } 74 73 75 static inline void buf_clear(cyclic_buffer_t *buf) 74 static inline void buf_clear(cyclic_buffer_t *buf) 76 75 { 77 76 buf->cnt = 0; -
uspace/drv/ns8250/ns8250.c
r472020fc r49698fa 69 69 #define DLAB_MASK (1 << 7) 70 70 71 /** The number of bits of one data unit send by the serial port. */71 /** The number of bits of one data unit send by the serial port. */ 72 72 typedef enum { 73 73 WORD_LENGTH_5, 74 74 WORD_LENGTH_6, 75 75 WORD_LENGTH_7, 76 WORD_LENGTH_8 76 WORD_LENGTH_8 77 77 } word_length_t; 78 78 … … 82 82 ONE_STOP_BIT, 83 83 /** 1.5 stop bits for word length 5, 2 stop bits otherwise. */ 84 TWO_STOP_BITS 84 TWO_STOP_BITS 85 85 } stop_bit_t; 86 86 87 /** The driver data for the serial port devices. 88 */ 87 /** The driver data for the serial port devices. */ 89 88 typedef struct ns8250_dev_data { 90 89 /** Is there any client conntected to the device? */ … … 96 95 /** The i/o port used to access the serial ports registers. */ 97 96 ioport8_t *port; 98 /** The buffer for incomming data. */97 /** The buffer for incomming data. */ 99 98 cyclic_buffer_t input_buffer; 100 /** The fibril mutex for synchronizing the access to the device. */101 fibril_mutex_t mutex; 99 /** The fibril mutex for synchronizing the access to the device. */ 100 fibril_mutex_t mutex; 102 101 } ns8250_dev_data_t; 103 102 104 103 /** Create driver data for a device. 105 * 106 * @return the driver data. 107 */ 108 static ns8250_dev_data_t * create_ns8250_dev_data() 109 { 110 ns8250_dev_data_t *data = (ns8250_dev_data_t *)malloc(sizeof(ns8250_dev_data_t)); 104 * 105 * @return The driver data. 106 */ 107 static ns8250_dev_data_t *create_ns8250_dev_data(void) 108 { 109 ns8250_dev_data_t *data; 110 111 data = (ns8250_dev_data_t *) malloc(sizeof(ns8250_dev_data_t)); 111 112 if (NULL != data) { 112 113 memset(data, 0, sizeof(ns8250_dev_data_t)); 113 114 fibril_mutex_initialize(&data->mutex); 114 115 } 115 return data; 116 return data; 116 117 } 117 118 118 119 /** 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 (NULL != data) {120 * 121 * @param data The driver data structure. 122 */ 123 static void delete_ns8250_dev_data(ns8250_dev_data_t *data) 124 { 125 if (NULL != data) 125 126 free(data); 126 }127 127 } 128 128 129 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 */ 134 static bool ns8250_received(ioport8_t *port) 135 { 136 return (pio_read_8(port + 5) & 1) != 0; 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 133 * otherwise. 134 */ 135 static bool ns8250_received(ioport8_t *port) 136 { 137 return (pio_read_8(port + 5) & 1) != 0; 137 138 } 138 139 139 140 /** 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 */ 144 static uint8_t ns8250_read_8(ioport8_t *port) 141 * 142 * @param port The base address of the serial port device's ports. 143 * @return The data read. 144 */ 145 static uint8_t ns8250_read_8(ioport8_t *port) 145 146 { 146 147 return pio_read_8(port); … … 148 149 149 150 /** Find out wheter it is possible to send data. 150 * 151 * @param port the base address of the serial port device's ports.152 */ 153 static bool is_transmit_empty(ioport8_t *port) 154 { 155 151 * 152 * @param port The base address of the serial port device's ports. 153 */ 154 static bool is_transmit_empty(ioport8_t *port) 155 { 156 return (pio_read_8(port + 5) & 0x20) != 0; 156 157 } 157 158 158 159 /** 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 */ 163 static void ns8250_write_8(ioport8_t *port, uint8_t c) 164 { 165 while (!is_transmit_empty(port)) 160 * 161 * @param port The base address of the serial port device's ports. 162 * @param c The character to be written to the serial port device. 163 */ 164 static void ns8250_write_8(ioport8_t *port, uint8_t c) 165 { 166 while (!is_transmit_empty(port)) 166 167 ; 167 168 … … 170 171 171 172 /** 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 */ 179 static int ns8250_read(device_t *dev, char *buf, size_t count) 180 { 181 // printf(NAME ": ns8250_read %s\n", dev->name); 182 173 * 174 * @param dev The serial port device. 175 * @param buf The ouput buffer for read data. 176 * @param count The number of bytes to be read. 177 * 178 * @return The number of bytes actually read on success, negative 179 * error number otherwise. 180 */ 181 static int ns8250_read(device_t *dev, char *buf, size_t count) 182 { 183 183 int ret = EOK; 184 185 ns8250_dev_data_t *data = (ns8250_dev_data_t *)dev->driver_data;184 ns8250_dev_data_t *data = (ns8250_dev_data_t *) dev->driver_data; 185 186 186 fibril_mutex_lock(&data->mutex); 187 188 187 while (!buf_is_empty(&data->input_buffer) && (size_t)ret < count) { 189 188 buf[ret] = (char)buf_pop_front(&data->input_buffer); 190 189 ret++; 191 190 } 192 193 191 fibril_mutex_unlock(&data->mutex); 194 192 … … 197 195 198 196 /** 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.197 * 198 * @param data The serial port device's driver data. 199 * @param c The character to be written. 202 200 */ 203 201 static inline void ns8250_putchar(ns8250_dev_data_t *data, uint8_t c) 204 { 202 { 205 203 fibril_mutex_lock(&data->mutex); 206 ns8250_write_8(data->port, c); 204 ns8250_write_8(data->port, c); 207 205 fibril_mutex_unlock(&data->mutex); 208 206 } 209 207 210 208 /** 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. 209 * 210 * @param dev The serial port device. 211 * @param buf The data to be written. 212 * @param count The number of bytes to be written. 213 * @return Zero on success. 217 214 */ 218 215 static int ns8250_write(device_t *dev, char *buf, size_t count) 219 216 { 220 ns8250_dev_data_t *data = (ns8250_dev_data_t *)dev->driver_data; 221 217 ns8250_dev_data_t *data = (ns8250_dev_data_t *) dev->driver_data; 222 218 size_t idx; 223 for (idx = 0; idx < count; idx++) {224 ns8250_putchar(data, (uint8_t)buf[idx]);225 }219 220 for (idx = 0; idx < count; idx++) 221 ns8250_putchar(data, (uint8_t) buf[idx]); 226 222 227 223 return 0; … … 230 226 static device_ops_t ns8250_dev_ops; 231 227 232 /** The character interface's callbacks. 233 */ 228 /** The character interface's callbacks. */ 234 229 static char_iface_t ns8250_char_iface = { 235 230 .read = &ns8250_read, … … 239 234 static int ns8250_add_device(device_t *dev); 240 235 241 /** The serial port device driver's standard operations. 242 */ 236 /** The serial port device driver's standard operations. */ 243 237 static driver_ops_t ns8250_ops = { 244 238 .add_device = &ns8250_add_device 245 239 }; 246 240 247 /** The serial port device driver structure. 248 */ 241 /** The serial port device driver structure. */ 249 242 static driver_t ns8250_driver = { 250 243 .name = NAME, … … 253 246 254 247 /** Clean up the serial port device structure. 255 * 256 * @param dev the device structure.248 * 249 * @param dev The device structure. 257 250 */ 258 251 static void ns8250_dev_cleanup(device_t *dev) 259 252 { 260 253 if (NULL != dev->driver_data) { 261 delete_ns8250_dev_data((ns8250_dev_data_t*) dev->driver_data);254 delete_ns8250_dev_data((ns8250_dev_data_t*) dev->driver_data); 262 255 dev->driver_data = NULL; 263 256 } … … 266 259 ipc_hangup(dev->parent_phone); 267 260 dev->parent_phone = 0; 268 } 261 } 269 262 } 270 263 271 264 /** Enable the i/o ports of the device. 272 * 273 * @param the serial port device.274 * @return true on success, false otherwise.265 * 266 * @param dev The serial port device. 267 * @return True on success, false otherwise. 275 268 */ 276 269 static bool ns8250_pio_enable(device_t *dev) … … 280 273 ns8250_dev_data_t *data = (ns8250_dev_data_t *)dev->driver_data; 281 274 282 // Gain control over port's registers. 283 if (pio_enable((void *)data->io_addr, REG_COUNT, (void **)(&data->port))) { 284 printf(NAME ": error - cannot gain the port %lx for device %s.\n", data->io_addr, dev->name); 275 /* Gain control over port's registers. */ 276 if (pio_enable((void *) data->io_addr, REG_COUNT, 277 (void **) &data->port)) { 278 printf(NAME ": error - cannot gain the port %lx for device " 279 "%s.\n", data->io_addr, dev->name); 285 280 return false; 286 281 } … … 290 285 291 286 /** 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.287 * 288 * @param dev The serial port device. 289 * @return True if the device is present, false otherwise. 295 290 */ 296 291 static bool ns8250_dev_probe(device_t *dev) … … 298 293 printf(NAME ": ns8250_dev_probe %s\n", dev->name); 299 294 300 ns8250_dev_data_t *data = (ns8250_dev_data_t *) dev->driver_data;301 ioport8_t *port_addr = data->port; 295 ns8250_dev_data_t *data = (ns8250_dev_data_t *) dev->driver_data; 296 ioport8_t *port_addr = data->port; 302 297 bool res = true; 303 298 uint8_t olddata; … … 306 301 307 302 pio_write_8(port_addr + 4, 0x10); 308 if (pio_read_8(port_addr + 6) & 0xf0) {303 if (pio_read_8(port_addr + 6) & 0xf0) 309 304 res = false; 310 }311 305 312 306 pio_write_8(port_addr + 4, 0x1f); 313 if ((pio_read_8(port_addr + 6) & 0xf0) != 0xf0) {307 if ((pio_read_8(port_addr + 6) & 0xf0) != 0xf0) 314 308 res = false; 315 }316 309 317 310 pio_write_8(port_addr + 4, olddata); 318 311 319 if (!res) {312 if (!res) 320 313 printf(NAME ": device %s is not present.\n", dev->name); 321 } 322 323 return res; 314 315 return res; 324 316 } 325 317 326 318 /** Initialize serial port device. 327 * 328 * @param dev the serial port device.329 * @return 0on success, negative error number otherwise.319 * 320 * @param dev The serial port device. 321 * @return Zero on success, negative error number otherwise. 330 322 */ 331 323 static int ns8250_dev_initialize(device_t *dev) … … 334 326 335 327 int ret = EOK; 328 336 329 hw_resource_list_t hw_resources; 337 330 memset(&hw_resources, 0, sizeof(hw_resource_list_t)); 338 331 339 / / allocate driver data for the device340 ns8250_dev_data_t *data = create_ns8250_dev_data(); 341 if (NULL == data) {332 /* Allocate driver data for the device. */ 333 ns8250_dev_data_t *data = create_ns8250_dev_data(); 334 if (NULL == data) 342 335 return ENOMEM; 343 }344 336 dev->driver_data = data; 345 337 346 // connect to the parent's driver 347 dev->parent_phone = devman_parent_device_connect(dev->handle, IPC_FLAG_BLOCKING); 348 if (dev->parent_phone <= 0) { 349 printf(NAME ": failed to connect to the parent driver of the device %s.\n", dev->name); 350 ret = EPARTY; 338 /* Connect to the parent's driver. */ 339 dev->parent_phone = devman_parent_device_connect(dev->handle, 340 IPC_FLAG_BLOCKING); 341 if (dev->parent_phone < 0) { 342 printf(NAME ": failed to connect to the parent driver of the " 343 "device %s.\n", dev->name); 344 ret = EPARTY; /* FIXME: use another EC */ 351 345 goto failed; 352 346 } 353 347 354 // get hw resources 355 348 /* Get hw resources. */ 356 349 if (!get_hw_resources(dev->parent_phone, &hw_resources)) { 357 printf(NAME ": failed to get hw resources for the device %s.\n", dev->name); 358 ret = EPARTY; 350 printf(NAME ": failed to get hw resources for the device " 351 "%s.\n", dev->name); 352 ret = EPARTY; /* FIXME: use another EC */ 359 353 goto failed; 360 } 354 } 361 355 362 356 size_t i; … … 371 365 data->irq = res->res.interrupt.irq; 372 366 irq = true; 373 printf(NAME ": the %s device was asigned irq = 0x%x.\n", dev->name, data->irq); 367 printf(NAME ": the %s device was asigned irq = 0x%x.\n", 368 dev->name, data->irq); 374 369 break; 370 375 371 case IO_RANGE: 376 372 data->io_addr = res->res.io_range.address; 377 373 if (res->res.io_range.size < REG_COUNT) { 378 printf(NAME ": i/o range assigned to the device %s is too small.\n", dev->name); 379 ret = EPARTY; 374 printf(NAME ": i/o range assigned to the device " 375 "%s is too small.\n", dev->name); 376 ret = EPARTY; /* FIXME: use another EC */ 380 377 goto failed; 381 378 } 382 379 ioport = true; 383 printf(NAME ": the %s device was asigned i/o address = 0x%x.\n", dev->name, data->io_addr); 384 break; 380 printf(NAME ": the %s device was asigned i/o address = " 381 "0x%x.\n", dev->name, data->io_addr); 382 break; 383 385 384 default: 386 385 break; … … 389 388 390 389 if (!irq || !ioport) { 391 printf(NAME ": missing hw resource(s) for the device %s.\n", dev->name); 392 ret = EPARTY; 390 printf(NAME ": missing hw resource(s) for the device %s.\n", 391 dev->name); 392 ret = EPARTY; /* FIXME: use another EC */ 393 393 goto failed; 394 } 394 } 395 395 396 396 clean_hw_resource_list(&hw_resources); … … 398 398 399 399 failed: 400 ns8250_dev_cleanup(dev); 401 clean_hw_resource_list(&hw_resources); 402 return ret; 400 ns8250_dev_cleanup(dev); 401 clean_hw_resource_list(&hw_resources); 402 return ret; 403 403 } 404 404 405 405 /** Enable interrupts on the serial port device. 406 * 406 * 407 407 * Interrupt when data is received. 408 * 409 * @param port the base address of the serial port device's ports.408 * 409 * @param port The base address of the serial port device's ports. 410 410 */ 411 411 static inline void ns8250_port_interrupts_enable(ioport8_t *port) 412 412 { 413 pio_write_8(port + 1 , 0x01); // Interrupt when data received414 pio_write_8(port + 4, 0x 0B);413 pio_write_8(port + 1, 0x1); /* Interrupt when data received. */ 414 pio_write_8(port + 4, 0xB); 415 415 } 416 416 417 417 /** Disable interrupts on the serial port device. 418 * 419 * @param port the base address of the serial port device's ports.418 * 419 * @param port The base address of the serial port device's ports. 420 420 */ 421 421 static inline void ns8250_port_interrupts_disable(ioport8_t *port) 422 422 { 423 pio_write_8(port + 1, 0x0 0); // Disable all interrupts423 pio_write_8(port + 1, 0x0); /* Disable all interrupts. */ 424 424 } 425 425 426 426 /** Enable interrupts for the serial port device. 427 * 428 * @param dev the device.429 * @return 0on success, negative error number otherwise.427 * 428 * @param dev The device. 429 * @return Zero on success, negative error number otherwise. 430 430 */ 431 431 static int ns8250_interrupt_enable(device_t *dev) 432 432 { 433 ns8250_dev_data_t *data = (ns8250_dev_data_t *)dev->driver_data; 434 433 ns8250_dev_data_t *data = (ns8250_dev_data_t *) dev->driver_data; 435 434 int res; 436 // enable interrupt globally 437 if (EOK != (res = interrupt_enable(data->irq))) { 435 436 /* Enable interrupt globally. */ 437 res = interrupt_enable(data->irq); 438 if (EOK != res) 438 439 return res; 439 } 440 441 // enable interrupt on the serial port 440 441 /* Enable interrupt on the serial port. */ 442 442 ns8250_port_interrupts_enable(data->port); 443 443 … … 446 446 447 447 /** Set Divisor Latch Access Bit. 448 * 449 * When the Divisor Latch Access Bit is set, 450 * it is possible to set baud rate ofthe serial port device.451 * 452 * @param port the base address of the serial port device's ports.448 * 449 * When the Divisor Latch Access Bit is set, it is possible to set baud rate of 450 * the serial port device. 451 * 452 * @param port The base address of the serial port device's ports. 453 453 */ 454 454 static inline void enable_dlab(ioport8_t *port) 455 455 { 456 456 uint8_t val = pio_read_8(port + 3); 457 pio_write_8(port + 3, val | DLAB_MASK); 457 pio_write_8(port + 3, val | DLAB_MASK); 458 458 } 459 459 460 460 /** Clear Divisor Latch Access Bit. 461 * 462 * @param port the base address of the serial port device's ports.461 * 462 * @param port The base address of the serial port device's ports. 463 463 */ 464 464 static inline void clear_dlab(ioport8_t *port) … … 469 469 470 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).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 * @return Zero on success, negative error number otherwise (EINVAL 475 * if the specified baud_rate is not valid). 476 476 */ 477 477 static int ns8250_port_set_baud_rate(ioport8_t *port, unsigned int baud_rate) … … 481 481 482 482 if (50 > baud_rate || 0 != MAX_BAUD_RATE % baud_rate) { 483 printf(NAME ": error - somebody tried to set invalid baud rate %d\n", baud_rate); 484 return EINVAL; 483 printf(NAME ": error - somebody tried to set invalid baud rate " 484 "%d\n", baud_rate); 485 return EINVAL; 485 486 } 486 487 487 488 divisor = MAX_BAUD_RATE / baud_rate; 488 489 div_low = (uint8_t)divisor; 489 div_high = (uint8_t)(divisor >> 8); 490 491 / / enable DLAB to be able to access baud rate divisor492 enable_dlab(port); 493 494 / / set divisor low byte495 pio_write_8(port + 0, div_low); 496 / / set divisor high byte497 pio_write_8(port + 1, div_high); 498 499 clear_dlab(port); 500 501 return EOK; 490 div_high = (uint8_t)(divisor >> 8); 491 492 /* Enable DLAB to be able to access baud rate divisor. */ 493 enable_dlab(port); 494 495 /* Set divisor low byte. */ 496 pio_write_8(port + 0, div_low); 497 /* Set divisor high byte. */ 498 pio_write_8(port + 1, div_high); 499 500 clear_dlab(port); 501 502 return EOK; 502 503 } 503 504 504 505 /** 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.506 * 507 * @param port The base address of the serial port device's ports. 508 * @param baud_rate The ouput parameter to which the baud rate is stored. 508 509 */ 509 510 static unsigned int ns8250_port_get_baud_rate(ioport8_t *port) … … 512 513 uint8_t div_low, div_high; 513 514 514 / / enable DLAB to be able to access baud rate divisor515 /* Enable DLAB to be able to access baud rate divisor. */ 515 516 enable_dlab(port); 516 517 517 / / get divisor low byte518 /* Get divisor low byte. */ 518 519 div_low = pio_read_8(port + 0); 519 / / get divisor high byte520 div_high = pio_read_8(port + 1); 520 /* Get divisor high byte. */ 521 div_high = pio_read_8(port + 1); 521 522 522 523 clear_dlab(port); … … 526 527 } 527 528 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) 529 /** Get the parameters of the serial communication set on the serial port 530 * device. 531 * 532 * @param parity The parity used. 533 * @param word_length The length of one data unit in bits. 534 * @param stop_bits The number of stop bits used (one or two). 535 */ 536 static void 537 ns8250_port_get_com_props(ioport8_t *port, unsigned int *parity, 538 unsigned int *word_length, unsigned int *stop_bits) 536 539 { 537 540 uint8_t val; 538 541 539 542 val = pio_read_8(port + 3); 540 541 543 *parity = ((val >> 3) & 7); 542 544 543 545 switch (val & 3) { 544 545 546 547 548 549 550 551 552 553 554 555 556 } 557 558 if ((val >> 2) & 1) {546 case WORD_LENGTH_5: 547 *word_length = 5; 548 break; 549 case WORD_LENGTH_6: 550 *word_length = 6; 551 break; 552 case WORD_LENGTH_7: 553 *word_length = 7; 554 break; 555 case WORD_LENGTH_8: 556 *word_length = 8; 557 break; 558 } 559 560 if ((val >> 2) & 1) 559 561 *stop_bits = 2; 560 } else {562 else 561 563 *stop_bits = 1; 562 }563 564 } 564 565 565 566 /** 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) 567 * 568 * @param parity The parity to be used. 569 * @param word_length The length of one data unit in bits. 570 * @param stop_bits The number of stop bits used (one or two). 571 * @return Zero on success, EINVAL if some of the specified values 572 * is invalid. 573 */ 574 static int 575 ns8250_port_set_com_props(ioport8_t *port, unsigned int parity, 576 unsigned int word_length, unsigned int stop_bits) 575 577 { 576 578 uint8_t val; 577 579 578 580 switch (word_length) { 579 580 581 582 583 584 585 586 587 588 589 590 591 592 581 case 5: 582 val = WORD_LENGTH_5; 583 break; 584 case 6: 585 val = WORD_LENGTH_6; 586 break; 587 case 7: 588 val = WORD_LENGTH_7; 589 break; 590 case 8: 591 val = WORD_LENGTH_8; 592 break; 593 default: 594 return EINVAL; 593 595 } 594 596 595 597 switch (stop_bits) { 596 597 598 599 600 601 602 603 598 case 1: 599 val |= ONE_STOP_BIT << 2; 600 break; 601 case 2: 602 val |= TWO_STOP_BITS << 2; 603 break; 604 default: 605 return EINVAL; 604 606 } 605 607 606 608 switch (parity) { 607 608 609 610 611 case SERIAL_SPACE_PARITY:612 613 614 615 616 } 617 618 pio_write_8(port + 3, val); 609 case SERIAL_NO_PARITY: 610 case SERIAL_ODD_PARITY: 611 case SERIAL_EVEN_PARITY: 612 case SERIAL_MARK_PARITY: 613 case SERIAL_SPACE_PARITY: 614 val |= parity << 3; 615 break; 616 default: 617 return EINVAL; 618 } 619 620 pio_write_8(port + 3, val); 619 621 620 622 return EOK; … … 622 624 623 625 /** Initialize the serial port device. 624 * 626 * 625 627 * Set the default parameters of the serial communication. 626 * 627 * @param dev the serial port device.628 * 629 * @param dev The serial port device. 628 630 */ 629 631 static void ns8250_initialize_port(device_t *dev) … … 632 634 ioport8_t *port = data->port; 633 635 634 / / disable interrupts635 ns8250_port_interrupts_disable(port); 636 // set baud rate 636 /* Disable interrupts. */ 637 ns8250_port_interrupts_disable(port); 638 /* Set baud rate. */ 637 639 ns8250_port_set_baud_rate(port, 38400); 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. 640 /* 8 bits, no parity, two stop bits. */ 641 ns8250_port_set_com_props(port, SERIAL_NO_PARITY, 8, 2); 642 /* Enable FIFO, clear them, with 14-byte threshold. */ 643 pio_write_8(port + 2, 0xC7); 644 /* 645 * RTS/DSR set (Request to Send and Data Terminal Ready lines enabled), 646 * Aux Output2 set - needed for interrupts. 647 */ 648 pio_write_8(port + 4, 0x0B); 649 } 650 651 /** Read the data from the serial port device and store them to the input 652 * buffer. 653 * 654 * @param dev The serial port device. 650 655 */ 651 656 static void ns8250_read_from_device(device_t *dev) 652 657 { 653 ns8250_dev_data_t *data = (ns8250_dev_data_t *) dev->driver_data;658 ns8250_dev_data_t *data = (ns8250_dev_data_t *) dev->driver_data; 654 659 ioport8_t *port = data->port; 655 660 bool cont = true; 656 661 657 while (cont) { 662 while (cont) { 658 663 fibril_mutex_lock(&data->mutex); 659 664 … … 661 666 if (cont) { 662 667 uint8_t val = ns8250_read_8(port); 663 // printf(NAME ": character %c read from %s.\n", val, dev->name);664 668 665 669 if (data->client_connected) { 666 if (!buf_push_back(&(data->input_buffer), val)) { 667 printf(NAME ": buffer overflow on %s.\n", dev->name); 670 if (!buf_push_back(&data->input_buffer, val)) { 671 printf(NAME ": buffer overflow on " 672 "%s.\n", dev->name); 668 673 } else { 669 printf(NAME ": the character %c saved to the buffer of %s.\n", val, dev->name); 674 printf(NAME ": the character %c saved " 675 "to the buffer of %s.\n", 676 val, dev->name); 670 677 } 671 } else { 672 // printf(NAME ": no client is connected to %s, discarding the character which was read.\n", dev->name); 673 } 678 } 674 679 } 675 680 676 fibril_mutex_unlock(&data->mutex); 677 678 fibril_yield(); 679 } 681 fibril_mutex_unlock(&data->mutex); 682 fibril_yield(); 683 } 680 684 } 681 685 682 686 /** 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 */ 689 static inline void ns8250_interrupt_handler(device_t *dev, ipc_callid_t iid, ipc_call_t *icall) 687 * 688 * The serial port is initialized to interrupt when some data come, so the 689 * interrupt is handled by reading the incomming data. 690 * 691 * @param dev The serial port device. 692 */ 693 static inline void 694 ns8250_interrupt_handler(device_t *dev, ipc_callid_t iid, ipc_call_t *icall) 690 695 { 691 696 ns8250_read_from_device(dev); … … 693 698 694 699 /** Register the interrupt handler for the device. 695 * 696 * @param dev the serial port device.700 * 701 * @param dev The serial port device. 697 702 */ 698 703 static inline int ns8250_register_interrupt_handler(device_t *dev) 699 704 { 700 ns8250_dev_data_t *data = (ns8250_dev_data_t *)dev->driver_data; 701 702 return register_interrupt_handler(dev, data->irq, ns8250_interrupt_handler, NULL); 705 ns8250_dev_data_t *data = (ns8250_dev_data_t *) dev->driver_data; 706 707 return register_interrupt_handler(dev, data->irq, 708 ns8250_interrupt_handler, NULL); 703 709 } 704 710 705 711 /** Unregister the interrupt handler for the device. 706 * 707 * @param dev the serial port device.712 * 713 * @param dev The serial port device. 708 714 */ 709 715 static inline int ns8250_unregister_interrupt_handler(device_t *dev) 710 716 { 711 ns8250_dev_data_t *data = (ns8250_dev_data_t *) dev->driver_data;712 713 return unregister_interrupt_handler(dev, data->irq); 717 ns8250_dev_data_t *data = (ns8250_dev_data_t *) dev->driver_data; 718 719 return unregister_interrupt_handler(dev, data->irq); 714 720 } 715 721 716 722 /** The add_device callback method of the serial port driver. 717 * 723 * 718 724 * Probe and initialize the newly added device. 719 * 720 * @param dev the serial port device.725 * 726 * @param dev The serial port device. 721 727 */ 722 728 static int ns8250_add_device(device_t *dev) 723 729 { 724 printf(NAME ": ns8250_add_device %s (handle = %d)\n", dev->name, dev->handle); 730 printf(NAME ": ns8250_add_device %s (handle = %d)\n", 731 dev->name, dev->handle); 725 732 726 733 int res = ns8250_dev_initialize(dev); 727 if (EOK != res) {734 if (EOK != res) 728 735 return res; 729 }730 736 731 737 if (!ns8250_pio_enable(dev)) { 732 738 ns8250_dev_cleanup(dev); 733 739 return EADDRNOTAVAIL; 734 } 735 736 / / find out whether the device is present740 } 741 742 /* Find out whether the device is present. */ 737 743 if (!ns8250_dev_probe(dev)) { 738 744 ns8250_dev_cleanup(dev); 739 745 return ENOENT; 740 } 741 742 / / serial port initialization (baud rate etc.)746 } 747 748 /* Serial port initialization (baud rate etc.). */ 743 749 ns8250_initialize_port(dev); 744 750 745 / / register interrupt handler751 /* Register interrupt handler. */ 746 752 if (EOK != ns8250_register_interrupt_handler(dev)) { 747 753 printf(NAME ": failed to register interrupt handler.\n"); … … 750 756 } 751 757 752 // enable interrupt 753 if (EOK != (res = ns8250_interrupt_enable(dev))) { 754 printf(NAME ": failed to enable the interrupt. Error code = %d.\n", res); 758 /* Enable interrupt. */ 759 res = ns8250_interrupt_enable(dev); 760 if (EOK != res) { 761 printf(NAME ": failed to enable the interrupt. Error code = " 762 "%d.\n", res); 755 763 ns8250_dev_cleanup(dev); 756 764 ns8250_unregister_interrupt_handler(dev); 757 765 return res; 758 } 759 760 / / set device operations766 } 767 768 /* Set device operations. */ 761 769 dev->ops = &ns8250_dev_ops; 762 770 763 771 add_device_to_class(dev, "serial"); 764 772 765 printf(NAME ": the %s device has been successfully initialized.\n", dev->name); 773 printf(NAME ": the %s device has been successfully initialized.\n", 774 dev->name); 766 775 767 776 return EOK; … … 769 778 770 779 /** Open the device. 771 * 772 * This is a callback function called when a client tries to connect to the device. 773 * 774 * @param dev the device. 780 * 781 * This is a callback function called when a client tries to connect to the 782 * device. 783 * 784 * @param dev The device. 775 785 */ 776 786 static int ns8250_open(device_t *dev) 777 787 { 778 ns8250_dev_data_t *data = (ns8250_dev_data_t *) dev->driver_data;788 ns8250_dev_data_t *data = (ns8250_dev_data_t *) dev->driver_data; 779 789 int res; 780 790 781 fibril_mutex_lock(&data->mutex); 782 791 fibril_mutex_lock(&data->mutex); 783 792 if (data->client_connected) { 784 793 res = ELIMIT; … … 787 796 data->client_connected = true; 788 797 } 789 790 798 fibril_mutex_unlock(&data->mutex); 791 799 … … 794 802 795 803 /** Close the device. 796 * 797 * This is a callback function called when a client tries to disconnect from the device. 798 * 799 * @param dev the device. 804 * 805 * This is a callback function called when a client tries to disconnect from 806 * the device. 807 * 808 * @param dev The device. 800 809 */ 801 810 static void ns8250_close(device_t *dev) 802 811 { 803 ns8250_dev_data_t *data = (ns8250_dev_data_t *) dev->driver_data;812 ns8250_dev_data_t *data = (ns8250_dev_data_t *) dev->driver_data; 804 813 805 814 fibril_mutex_lock(&data->mutex); 806 815 807 assert(data->client_connected); 816 assert(data->client_connected); 808 817 809 818 data->client_connected = false; 810 819 buf_clear(&data->input_buffer); 811 820 812 fibril_mutex_unlock(&data->mutex); 813 } 814 815 /** Get parameters of the serial communication which are set to the specified device. 816 * 817 * @param the serial port device. 818 * @param baud_rate the baud rate used by the device. 819 * @param the type of parity used by the device. 820 * @param word_length the size of one data unit in bits. 821 * @param stop_bits the number of stop bits used. 822 */ 823 static void ns8250_get_props(device_t *dev, unsigned int *baud_rate, 824 unsigned int *parity, unsigned int *word_length, unsigned int* stop_bits) 825 { 826 ns8250_dev_data_t *data = (ns8250_dev_data_t *)dev->driver_data; 821 fibril_mutex_unlock(&data->mutex); 822 } 823 824 /** Get parameters of the serial communication which are set to the specified 825 * device. 826 * 827 * @param dev The serial port device. 828 * @param baud_rate The baud rate used by the device. 829 * @param parity The type of parity used by the device. 830 * @param word_length The size of one data unit in bits. 831 * @param stop_bits The number of stop bits used. 832 */ 833 static void 834 ns8250_get_props(device_t *dev, unsigned int *baud_rate, unsigned int *parity, 835 unsigned int *word_length, unsigned int* stop_bits) 836 { 837 ns8250_dev_data_t *data = (ns8250_dev_data_t *) dev->driver_data; 827 838 ioport8_t *port = data->port; 828 839 829 fibril_mutex_lock(&data->mutex); 830 ns8250_port_interrupts_disable(port); // Disable all interrupts840 fibril_mutex_lock(&data->mutex); 841 ns8250_port_interrupts_disable(port); 831 842 *baud_rate = ns8250_port_get_baud_rate(port); 832 ns8250_port_get_com_props(port, parity, word_length, stop_bits); 843 ns8250_port_get_com_props(port, parity, word_length, stop_bits); 833 844 ns8250_port_interrupts_enable(port); 834 fibril_mutex_unlock(&data->mutex); 835 836 printf(NAME ": ns8250_get_props: baud rate %d, parity 0x%x, word length %d, stop bits %d\n", 837 *baud_rate, *parity, *word_length, * stop_bits); 838 } 839 840 /** Set parameters of the serial communication to the specified serial port device. 841 * 842 * @param the serial port device. 843 * @param baud_rate the baud rate to be used by the device. 844 * @param the type of parity to be used by the device. 845 * @param word_length the size of one data unit in bits. 846 * @param stop_bits the number of stop bits to be used. 847 */ 848 static int ns8250_set_props(device_t *dev, unsigned int baud_rate, 849 unsigned int parity, unsigned int word_length, unsigned int stop_bits) 850 { 851 printf(NAME ": ns8250_set_props: baud rate %d, parity 0x%x, word length %d, stop bits %d\n", 852 baud_rate, parity, word_length, stop_bits); 853 854 ns8250_dev_data_t *data = (ns8250_dev_data_t *)dev->driver_data; 845 fibril_mutex_unlock(&data->mutex); 846 847 printf(NAME ": ns8250_get_props: baud rate %d, parity 0x%x, word " 848 "length %d, stop bits %d\n", *baud_rate, *parity, *word_length, 849 *stop_bits); 850 } 851 852 /** Set parameters of the serial communication to the specified serial port 853 * device. 854 * 855 * @param dev The serial port device. 856 * @param baud_rate The baud rate to be used by the device. 857 * @param parity The type of parity to be used by the device. 858 * @param word_length The size of one data unit in bits. 859 * @param stop_bits The number of stop bits to be used. 860 */ 861 static int 862 ns8250_set_props(device_t *dev, unsigned int baud_rate, unsigned int parity, 863 unsigned int word_length, unsigned int stop_bits) 864 { 865 printf(NAME ": ns8250_set_props: baud rate %d, parity 0x%x, word " 866 "length %d, stop bits %d\n", baud_rate, parity, word_length, 867 stop_bits); 868 869 ns8250_dev_data_t *data = (ns8250_dev_data_t *) dev->driver_data; 855 870 ioport8_t *port = data->port; 856 871 int ret; 857 872 858 fibril_mutex_lock(&data->mutex); 859 ns8250_port_interrupts_disable(port); // Disable all interrupts873 fibril_mutex_lock(&data->mutex); 874 ns8250_port_interrupts_disable(port); 860 875 ret = ns8250_port_set_baud_rate(port, baud_rate); 861 if (EOK == ret) {876 if (EOK == ret) 862 877 ret = ns8250_port_set_com_props(port, parity, word_length, stop_bits); 863 }864 878 ns8250_port_interrupts_enable(port); 865 fibril_mutex_unlock(&data->mutex); 866 867 return ret; 868 } 869 870 871 /** Default handler for client requests which are not handled by the standardinterfaces.872 * 879 fibril_mutex_unlock(&data->mutex); 880 881 return ret; 882 } 883 884 /** Default handler for client requests which are not handled by the standard 885 * interfaces. 886 * 873 887 * Configure the parameters of the serial communication. 874 888 */ 875 static void ns8250_default_handler(device_t *dev, ipc_callid_t callid, ipc_call_t *call) 889 static void 890 ns8250_default_handler(device_t *dev, ipc_callid_t callid, ipc_call_t *call) 876 891 { 877 892 ipcarg_t method = IPC_GET_METHOD(*call); 878 893 int ret; 879 unsigned int baud_rate, parity, word_length, stop_bits; 880 881 switch(method) { 882 case SERIAL_GET_COM_PROPS: 883 ns8250_get_props(dev, &baud_rate, &parity, &word_length, &stop_bits); 884 ipc_answer_4(callid, EOK, baud_rate, parity, word_length, stop_bits); 885 break; 894 unsigned int baud_rate, parity, word_length, stop_bits; 895 896 switch (method) { 897 case SERIAL_GET_COM_PROPS: 898 ns8250_get_props(dev, &baud_rate, &parity, &word_length, 899 &stop_bits); 900 ipc_answer_4(callid, EOK, baud_rate, parity, word_length, 901 stop_bits); 902 break; 886 903 887 case SERIAL_SET_COM_PROPS: 888 baud_rate = IPC_GET_ARG1(*call); 889 parity = IPC_GET_ARG2(*call); 890 word_length = IPC_GET_ARG3(*call); 891 stop_bits = IPC_GET_ARG4(*call); 892 ret = ns8250_set_props(dev, baud_rate, parity, word_length, stop_bits); 893 ipc_answer_0(callid, ret); 894 break; 895 896 default: 897 ipc_answer_0(callid, ENOTSUP); 898 } 904 case SERIAL_SET_COM_PROPS: 905 baud_rate = IPC_GET_ARG1(*call); 906 parity = IPC_GET_ARG2(*call); 907 word_length = IPC_GET_ARG3(*call); 908 stop_bits = IPC_GET_ARG4(*call); 909 ret = ns8250_set_props(dev, baud_rate, parity, word_length, 910 stop_bits); 911 ipc_answer_0(callid, ret); 912 break; 913 914 default: 915 ipc_answer_0(callid, ENOTSUP); 916 } 899 917 } 900 918 901 919 /** Initialize the serial port driver. 902 * 903 * Initialize device operations structures with callback methods for handling 920 * 921 * Initialize device operations structures with callback methods for handling 904 922 * client requests to the serial port devices. 905 923 */ 906 static void ns8250_init( )924 static void ns8250_init(void) 907 925 { 908 926 ns8250_dev_ops.open = &ns8250_open; 909 ns8250_dev_ops.close = &ns8250_close; 927 ns8250_dev_ops.close = &ns8250_close; 910 928 911 929 ns8250_dev_ops.interfaces[CHAR_DEV_IFACE] = &ns8250_char_iface; … … 915 933 int main(int argc, char *argv[]) 916 934 { 917 printf(NAME ": HelenOS serial port driver\n"); 935 printf(NAME ": HelenOS serial port driver\n"); 918 936 ns8250_init(); 919 937 return driver_main(&ns8250_driver);
Note:
See TracChangeset
for help on using the changeset viewer.