Changeset cf8cc36 in mainline


Ignore:
Timestamp:
2010-05-14T13:45:28Z (14 years ago)
Author:
Lenka Trochtova <trochtova.lenka@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
c47e1a8
Parents:
04c7003f
Message:

get/set parameters of the serial communication (baud rate, parity, number of stop bits, word size)

Location:
uspace
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • uspace/app/test_serial/test_serial.c

    r04c7003f rcf8cc36  
    9292        }
    9393       
    94         res = ipc_call_sync_1_0(phone, SERIAL_SET_BAUD_RATE, 1200);
     94        unsigned int old_baud, old_par, old_stop, old_word_size;
     95       
     96        res = ipc_call_sync_0_4(phone, SERIAL_GET_COM_PROPS, &old_baud, &old_par, &old_word_size, &old_stop);   
    9597        if (EOK != res) {
    96                 printf(NAME ": failed to set baud rate, errno = %d.\n", -res);
     98                printf(NAME ": failed to get old communication parameters, errno = %d.\n", -res);
    9799                devman_hangup_phone(DEVMAN_CLIENT);
    98100                ipc_hangup(phone);
    99101                free(buf);
    100                 return 4;               
     102                return 4;
    101103        }
     104       
     105        res = ipc_call_sync_4_0(phone, SERIAL_SET_COM_PROPS, 1200, SERIAL_NO_PARITY, 8, 1);     
     106        if (EOK != res) {
     107                printf(NAME ": failed to set communication parameters, errno = %d.\n", -res);
     108                devman_hangup_phone(DEVMAN_CLIENT);
     109                ipc_hangup(phone);
     110                free(buf);
     111                return 4;
     112        }
     113       
    102114       
    103115        int total = 0;
     
    107119                if (0 > read) {
    108120                        printf(NAME ": failed read from device, errno = %d.\n", -read);
     121                        ipc_call_sync_4_0(phone, SERIAL_SET_COM_PROPS, old_baud, old_par, old_word_size, old_stop);     
    109122                        ipc_hangup(phone);
    110123                        devman_hangup_phone(DEVMAN_CLIENT);
     
    126139        write_dev(phone, the_end, str_size(the_end));
    127140       
     141        // restore original communication settings
     142        ipc_call_sync_4_0(phone, SERIAL_SET_COM_PROPS, old_baud, old_par, old_word_size, old_stop);     
    128143        devman_hangup_phone(DEVMAN_CLIENT);
    129144        ipc_hangup(phone);
  • uspace/lib/libc/include/ipc/serial_ctl.h

    r04c7003f rcf8cc36  
    3232#include <ipc/dev_iface.h>
    3333
     34/** ipc methods for getting/setting serial communication properties
     35 *      1st ipc arg: baud rate
     36 *      2nd ipc arg: parity
     37 *      3rd ipc arg: number of bits in one word
     38 *      4th ipc arg: number of stop bits
     39 */
    3440typedef enum { 
    35         SERIAL_SET_BAUD_RATE = DEV_FIRST_CUSTOM_METHOD,
    36         SERIAL_SET_PARITY,
    37         SERIAL_SET_STOP_BITS
     41        SERIAL_GET_COM_PROPS = DEV_FIRST_CUSTOM_METHOD,
     42        SERIAL_SET_COM_PROPS
    3843} serial_ctl_t;
    3944
     45typedef enum {
     46        SERIAL_NO_PARITY = 0,
     47        SERIAL_ODD_PARITY = 1,
     48        SERIAL_EVEN_PARITY = 3,
     49        SERIAL_MARK_PARITY = 5,
     50        SERIAL_SPACE_PARITY = 7
     51} serial_parity_t;
    4052
    4153#endif
  • uspace/srv/drivers/ns8250/ns8250.c

    r04c7003f rcf8cc36  
    6767#define REG_COUNT 7
    6868#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.*/
     72typedef 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. */
     80typedef 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 */
    7089typedef struct ns8250_dev_data {
     90        /** Is there any client conntected to the device? */
    7191        bool client_connected;
     92        /** The irq assigned to this device. */
    7293        int irq;
     94        /** The base i/o address of the devices registers. */
    7395        uint32_t io_addr;
     96        /** The i/o port used to access the serial ports registers. */
    7497        ioport8_t *port;
     98        /** The buffer for incomming data.*/
    7599        cyclic_buffer_t input_buffer;
     100        /** The fibril mutex for synchronizing the access to the device.*/
    76101        fibril_mutex_t mutex;           
    77102} ns8250_dev_data_t;
    78103
     104/** Create driver data for a device.
     105 *
     106 * @return the driver data.
     107 */
    79108static ns8250_dev_data_t * create_ns8250_dev_data()
    80109{
     
    87116}
    88117
     118/** Delete driver data.
     119 *
     120 * @param data the driver data structure.
     121 */
    89122static void delete_ns8250_dev_data(ns8250_dev_data_t *data)
    90123{
     
    94127}
    95128
     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 */
    96134static bool ns8250_received(ioport8_t *port)
    97135{
     
    99137}
    100138
     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 */
    101144static uint8_t ns8250_read_8(ioport8_t *port)
    102145{
     
    104147}
    105148
     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 */
    106153static bool is_transmit_empty(ioport8_t *port)
    107154{
     
    109156}
    110157
     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 */
    111163static void ns8250_write_8(ioport8_t *port, uint8_t c)
    112164{
     
    117169}
    118170
     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 */
    119179static int ns8250_read(device_t *dev, char *buf, size_t count)
    120180{
    121181        // printf(NAME ": ns8250_read %s\n", dev->name);
    122182       
    123         int ret = 0;
     183        int ret = EOK;
    124184       
    125185        ns8250_dev_data_t *data = (ns8250_dev_data_t *)dev->driver_data;
    126186        fibril_mutex_lock(&data->mutex);
    127187       
    128         while (!buf_is_empty(&data->input_buffer) && ret < count) {
     188        while (!buf_is_empty(&data->input_buffer) && (size_t)ret < count) {
    129189                buf[ret] = (char)buf_pop_front(&data->input_buffer);
    130190                ret++;
     
    136196}
    137197
     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 */
    138203static inline void ns8250_putchar(ns8250_dev_data_t *data, uint8_t c)
    139204{       
     
    143208}
    144209
     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 */
    145218static int ns8250_write(device_t *dev, char *buf, size_t count)
    146219{
     
    157230static device_class_t ns8250_dev_class;
    158231
     232/** The character interface's callbacks.
     233 */
    159234static char_iface_t ns8250_char_iface = {
    160235        .read = &ns8250_read,
     
    177252};
    178253
     254/** Clean up the serial port device structure.
     255 *
     256 * @param dev the device structure.
     257 */
    179258static void ns8250_dev_cleanup(device_t *dev)
    180259{
     
    190269}
    191270
     271/** Enable the i/o ports of the device.
     272 *
     273 * @param the serial port device.
     274 * @return true on success, false otherwise.
     275 */
    192276static bool ns8250_pio_enable(device_t *dev)
    193277{
     
    205289}
    206290
     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 */
    207296static bool ns8250_dev_probe(device_t *dev)
    208297{
     
    235324}
    236325
     326/** Initialize serial port device.
     327 *
     328 * @param dev the serial port device.
     329 * @return 0 on success, negative error number otherwise.
     330 */
    237331static int ns8250_dev_initialize(device_t *dev)
    238332{
     
    309403}
    310404
     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 */
    311411static inline void ns8250_port_interrupts_enable(ioport8_t *port)
    312412{       
     
    315415}
    316416
     417/** Disable interrupts on the serial port device.
     418 *
     419 * @param port the base address of the serial port device's ports.
     420 */
    317421static inline void ns8250_port_interrupts_disable(ioport8_t *port)
    318422{
     
    320424}
    321425
     426/** Enable interrupts for the serial port device.
     427 *
     428 * @param dev the device.
     429 * @return 0 on success, negative error number otherwise.
     430 */
    322431static int ns8250_interrupt_enable(device_t *dev)
    323432{
     
    336445}
    337446
     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 */
     454static 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 */
     464static 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 */
    338477static int ns8250_port_set_baud_rate(ioport8_t *port, unsigned int baud_rate)
    339478{
     
    350489        div_high = (uint8_t)(divisor >> 8);     
    351490       
    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);       
    358500       
    359501        return EOK;             
    360502}
    361503
    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 */
     509static 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 */
     534static 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 */
     573static 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 */
     629static void ns8250_initialize_port(device_t *dev)
    363630{
    364631        ns8250_dev_data_t *data = (ns8250_dev_data_t *)dev->driver_data;
    365632        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
    385637        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 */
    392651static void ns8250_read_from_device(device_t *dev)
    393652{
     
    399658                fibril_mutex_lock(&data->mutex);
    400659               
    401                 if (cont = ns8250_received(port)) {
     660                cont = ns8250_received(port);
     661                if (cont) {
    402662                        uint8_t val = ns8250_read_8(port);
    403663                        // printf(NAME ": character %c read from %s.\n", val, dev->name);                       
     
    420680}
    421681
     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 */
    422689static inline void ns8250_interrupt_handler(device_t *dev, ipc_callid_t iid, ipc_call_t *icall)
    423690{
     
    425692}
    426693
     694/** Register the interrupt handler for the device.
     695 *
     696 * @param dev the serial port device.
     697 */
    427698static inline int ns8250_register_interrupt_handler(device_t *dev)
    428699{
     
    432703}
    433704
     705/** Unregister the interrupt handler for the device.
     706 *
     707 * @param dev the serial port device.
     708 */
    434709static inline int ns8250_unregister_interrupt_handler(device_t *dev)
    435710{
     
    439714}
    440715
     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 */
    441722static int ns8250_add_device(device_t *dev)
    442723{
     
    529810}
    530811
     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 */
     820static 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 */
     845static 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
    531868/** Default handler for client requests which are not handled by the standard interfaces.
    532869 *
     
    537874        ipcarg_t method = IPC_GET_METHOD(*call);
    538875        int ret;
     876        unsigned int baud_rate, parity, word_length, stop_bits;
    539877       
    540878        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);
    543890                        ipc_answer_0(callid, ret);
    544891                        break;
    545                 case SERIAL_SET_PARITY:
    546                         // TODO
    547                         break;
    548                 case SERIAL_SET_STOP_BITS:
    549                         // TODO
    550                         break;
     892                       
    551893                default:
    552894                        ipc_answer_0(callid, ENOTSUP);         
    553         }
     895        }       
    554896}
    555897
Note: See TracChangeset for help on using the changeset viewer.