Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/c/generic/io/chardev.c

    r19ea61d r75751db6  
    11/*
    22 * Copyright (c) 2011 Jan Vesely
    3  * Copyright (c) 2017 Jiri Svoboda
    43 * All rights reserved.
    54 *
     
    2827 */
    2928
    30 /** @addtogroup libc
    31  * @{
    32  */
    33 /**
    34  * @file
    35  * @brief Character device client interface
    36  */
    37 
    3829#include <errno.h>
    3930#include <mem.h>
    4031#include <io/chardev.h>
    4132#include <ipc/chardev.h>
    42 #include <stddef.h>
    43 #include <stdlib.h>
    4433
    45 /** Open character device.
    46  *
    47  * @param sess Session with the character device
    48  * @param rchardev Place to store pointer to the new character device structure
    49  *
    50  * @return EOK on success, ENOMEM if out of memory, EIO on I/O error
    51  */
    52 int chardev_open(async_sess_t *sess, chardev_t **rchardev)
     34ssize_t chardev_read(async_exch_t *exch, void *data, size_t size)
    5335{
    54         chardev_t *chardev;
     36        if (!exch)
     37                return EBADMEM;
     38        if (size > 4 * sizeof(sysarg_t))
     39                return ELIMIT;
    5540
    56         chardev = calloc(1, sizeof(chardev_t));
    57         if (chardev == NULL)
    58                 return ENOMEM;
    59 
    60         chardev->sess = sess;
    61         *rchardev = chardev;
    62 
    63         /* EIO might be used in a future implementation */
    64         return EOK;
     41        sysarg_t message[4] = { 0 };
     42        const ssize_t ret = async_req_1_4(exch, CHARDEV_READ, size,
     43            &message[0], &message[1], &message[2], &message[3]);
     44        if (ret > 0 && (size_t)ret <= size)
     45                memcpy(data, message, size);
     46        return ret;
    6547}
    6648
    67 /** Close character device.
    68  *
    69  * Frees the character device structure. The underlying session is
    70  * not affected.
    71  *
    72  * @param chardev Character device or @c NULL
    73  */
    74 void chardev_close(chardev_t *chardev)
     49ssize_t chardev_write(async_exch_t *exch, const void *data, size_t size)
    7550{
    76         free(chardev);
     51        if (!exch)
     52                return EBADMEM;
     53        if (size > 3 * sizeof(sysarg_t))
     54                return ELIMIT;
     55
     56        sysarg_t message[3] = { 0 };
     57        memcpy(message, data, size);
     58        return async_req_4_0(exch, CHARDEV_WRITE, size,
     59            message[0], message[1], message[2]);
    7760}
    78 
    79 /** Read from character device.
    80  *
    81  * Read as much data as is available from character device up to @a size
    82  * bytes into @a buf. On success EOK is returned and at least one byte
    83  * is read (if no byte is available the function blocks). The number
    84  * of bytes read is stored in @a *nread.
    85  *
    86  * On error a non-zero error code is returned and @a *nread is filled with
    87  * the number of bytes that were successfully transferred.
    88  *
    89  * @param chardev Character device
    90  * @param buf Destination buffer
    91  * @param size Maximum number of bytes to read
    92  * @param nread Place to store actual number of bytes read
    93  *
    94  * @return EOK on success or non-zero error code
    95  */
    96 int chardev_read(chardev_t *chardev, void *buf, size_t size, size_t *nread)
    97 {
    98         async_exch_t *exch = async_exchange_begin(chardev->sess);
    99 
    100         if (size > DATA_XFER_LIMIT) {
    101                 /* This should not hurt anything. */
    102                 size = DATA_XFER_LIMIT;
    103         }
    104 
    105         ipc_call_t answer;
    106         aid_t req = async_send_0(exch, CHARDEV_READ, &answer);
    107         int rc = async_data_read_start(exch, buf, size);
    108         async_exchange_end(exch);
    109 
    110         if (rc != EOK) {
    111                 async_forget(req);
    112                 *nread = 0;
    113                 return rc;
    114         }
    115 
    116         sysarg_t retval;
    117         async_wait_for(req, &retval);
    118 
    119         if (retval != EOK) {
    120                 *nread = 0;
    121                 return retval;
    122         }
    123 
    124         *nread = IPC_GET_ARG2(answer);
    125         /* In case of partial success, ARG1 contains the error code */
    126         return IPC_GET_ARG1(answer);
    127 
    128 }
    129 
    130 /** Write up to DATA_XFER_LIMIT bytes to character device.
    131  *
    132  * Write up to @a size or DATA_XFER_LIMIT bytes from @a data to character
    133  * device. On success EOK is returned, bytes were written and @a *nwritten
    134  * is set to min(@a size, DATA_XFER_LIMIT)
    135  *
    136  * On error a non-zero error code is returned and @a *nwritten is filled with
    137  * the number of bytes that were successfully transferred.
    138  *
    139  * @param chardev Character device
    140  * @param buf Destination buffer
    141  * @param size Maximum number of bytes to read
    142  * @param nwritten Place to store actual number of bytes written
    143  *
    144  * @return EOK on success or non-zero error code
    145  */
    146 static int chardev_write_once(chardev_t *chardev, const void *data,
    147     size_t size, size_t *nwritten)
    148 {
    149         async_exch_t *exch = async_exchange_begin(chardev->sess);
    150         ipc_call_t answer;
    151         aid_t req;
    152         int rc;
    153 
    154         /* Break down large transfers */
    155         if (size > DATA_XFER_LIMIT)
    156                 size = DATA_XFER_LIMIT;
    157 
    158         req = async_send_0(exch, CHARDEV_WRITE, &answer);
    159         rc = async_data_write_start(exch, data, size);
    160         async_exchange_end(exch);
    161 
    162         if (rc != EOK) {
    163                 async_forget(req);
    164                 *nwritten = 0;
    165                 return rc;
    166         }
    167 
    168         sysarg_t retval;
    169         async_wait_for(req, &retval);
    170         if (retval != EOK) {
    171                 *nwritten = 0;
    172                 return retval;
    173         }
    174 
    175         *nwritten = IPC_GET_ARG2(answer);
    176         /* In case of partial success, ARG1 contains the error code */
    177         return IPC_GET_ARG1(answer);
    178 }
    179 
    180 /** Write to character device.
    181  *
    182  * Write @a size bytes from @a data to character device. On success EOK
    183  * is returned, all bytes were written and @a *nwritten is set to @a size.
    184  *
    185  * On error a non-zero error code is returned and @a *nwritten is filled with
    186  * the number of bytes that were successfully transferred.
    187  *
    188  * @param chardev Character device
    189  * @param buf Destination buffer
    190  * @param size Maximum number of bytes to read
    191  * @param nwritten Place to store actual number of bytes written
    192  *
    193  * @return EOK on success or non-zero error code
    194  */
    195 int chardev_write(chardev_t *chardev, const void *data, size_t size,
    196     size_t *nwritten)
    197 {
    198         size_t nw;
    199         size_t p;
    200         int rc;
    201 
    202         p = 0;
    203         while (p < size) {
    204                 rc = chardev_write_once(chardev, data + p, size - p, &nw);
    205                 /* nw is always valid, we can have partial success */
    206                 p += nw;
    207 
    208                 if (rc != EOK) {
    209                         /* We can return partial success */
    210                         *nwritten = p;
    211                         return rc;
    212                 }
    213         }
    214 
    215         *nwritten = p;
    216         return EOK;
    217 }
    218 
    219 /** @}
    220  */
Note: See TracChangeset for help on using the changeset viewer.