Search
lxdream.org :: lxdream/src/drivers/serial_unix.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/drivers/serial_unix.c
changeset 1077:136fc24d17ef
next1079:691f9f621c5a
author nkeynes
date Wed Oct 07 17:53:56 2009 +1000 (12 years ago)
permissions -rw-r--r--
last change Create a host attachment for the SCIF serial port. By default, uses /dev/console
Add general fd listening to netutil, and rename to ioutil
Add SCIF update on port read/write - fixes KOS timing problems but needs to
be redone properly.
file annotate diff log raw
nkeynes@1077
     1
/**
nkeynes@1077
     2
 * $Id$
nkeynes@1077
     3
 *
nkeynes@1077
     4
 * Host driver for a serial port attachment, that can be hooked to a character
nkeynes@1077
     5
 * device, fifo or named pipe.
nkeynes@1077
     6
 *
nkeynes@1077
     7
 * Copyright (c) 2009 Nathan Keynes.
nkeynes@1077
     8
 *
nkeynes@1077
     9
 * This program is free software; you can redistribute it and/or modify
nkeynes@1077
    10
 * it under the terms of the GNU General Public License as published by
nkeynes@1077
    11
 * the Free Software Foundation; either version 2 of the License, or
nkeynes@1077
    12
 * (at your option) any later version.
nkeynes@1077
    13
 *
nkeynes@1077
    14
 * This program is distributed in the hope that it will be useful,
nkeynes@1077
    15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
nkeynes@1077
    16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
nkeynes@1077
    17
 * GNU General Public License for more details.
nkeynes@1077
    18
 */
nkeynes@1077
    19
nkeynes@1077
    20
#include <stdio.h>
nkeynes@1077
    21
#include <stdlib.h>
nkeynes@1077
    22
#include <fcntl.h>
nkeynes@1077
    23
#include <sys/stat.h>
nkeynes@1077
    24
nkeynes@1077
    25
#include "lxdream.h"
nkeynes@1077
    26
#include "config.h"
nkeynes@1077
    27
#include "ioutil.h"
nkeynes@1077
    28
#include "serial.h"
nkeynes@1077
    29
nkeynes@1077
    30
nkeynes@1077
    31
typedef struct serial_fd_device {
nkeynes@1077
    32
    struct serial_device dev;
nkeynes@1077
    33
    FILE *in;
nkeynes@1077
    34
    FILE *out;
nkeynes@1077
    35
    gboolean closeOnDestroy;
nkeynes@1077
    36
    io_listener_t listener;
nkeynes@1077
    37
} *serial_fd_device_t;
nkeynes@1077
    38
nkeynes@1077
    39
static void serial_fd_device_attach(serial_device_t dev);
nkeynes@1077
    40
static void serial_fd_device_detach(serial_device_t dev);
nkeynes@1077
    41
static void serial_fd_device_destroy(serial_device_t dev);
nkeynes@1077
    42
static void serial_fd_device_set_line_speed(struct serial_device *dev, uint32_t bps);
nkeynes@1077
    43
static void serial_fd_device_set_line_params(struct serial_device *dev, int flags);
nkeynes@1077
    44
static void serial_fd_device_receive_data(struct serial_device *dev, uint8_t value);
nkeynes@1077
    45
static gboolean serial_fd_device_transmit_data( int fd, void *dev);
nkeynes@1077
    46
nkeynes@1077
    47
static gboolean serial_config_changed(void *data, struct lxdream_config_group *group, unsigned item,
nkeynes@1077
    48
                                      const gchar *oldval, const gchar *newval);
nkeynes@1077
    49
nkeynes@1077
    50
struct lxdream_config_group serial_group =
nkeynes@1077
    51
    { "serial", serial_config_changed, NULL, NULL,
nkeynes@1077
    52
       {{ "device", N_("Serial device"), CONFIG_TYPE_FILE, "/dev/console" },
nkeynes@1077
    53
        { NULL, CONFIG_TYPE_NONE }} };
nkeynes@1077
    54
nkeynes@1077
    55
void serial_init()
nkeynes@1077
    56
{
nkeynes@1077
    57
    const gchar *name = serial_group.params[0].value;
nkeynes@1077
    58
    if( name != NULL ) {
nkeynes@1077
    59
        serial_device_t dev = serial_fd_device_new_filename(name);
nkeynes@1077
    60
        if( dev != NULL ) {
nkeynes@1077
    61
            serial_attach_device( dev );
nkeynes@1077
    62
        }
nkeynes@1077
    63
    }
nkeynes@1077
    64
}
nkeynes@1077
    65
nkeynes@1077
    66
static gboolean serial_config_changed(void *data, struct lxdream_config_group *group, unsigned item,
nkeynes@1077
    67
                                      const gchar *oldval, const gchar *newval)
nkeynes@1077
    68
{
nkeynes@1077
    69
    if( item == 0 ) {
nkeynes@1077
    70
        serial_destroy_device(serial_detach_device());
nkeynes@1077
    71
        serial_device_t dev = serial_fd_device_new_filename(newval);
nkeynes@1077
    72
        if( dev != NULL ) {
nkeynes@1077
    73
            serial_attach_device( dev );
nkeynes@1077
    74
        }
nkeynes@1077
    75
    }
nkeynes@1077
    76
}
nkeynes@1077
    77
nkeynes@1077
    78
nkeynes@1077
    79
nkeynes@1077
    80
serial_device_t serial_fd_device_new_filename( const gchar *filename )
nkeynes@1077
    81
{
nkeynes@1077
    82
    FILE *out = fopen( filename, "w+" );
nkeynes@1077
    83
    FILE *in;
nkeynes@1077
    84
    struct stat st;
nkeynes@1077
    85
nkeynes@1077
    86
    if( out == NULL ) {
nkeynes@1077
    87
        return NULL;
nkeynes@1077
    88
    }
nkeynes@1077
    89
nkeynes@1077
    90
    if( fstat( fileno(out), &st ) != 0 ) {
nkeynes@1077
    91
        fclose(out);
nkeynes@1077
    92
        return NULL;
nkeynes@1077
    93
    }
nkeynes@1077
    94
nkeynes@1077
    95
    if( S_ISCHR(st.st_mode) || S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode) ) {
nkeynes@1077
    96
        in = out;
nkeynes@1077
    97
    } else {
nkeynes@1077
    98
        in = NULL;
nkeynes@1077
    99
    }
nkeynes@1077
   100
nkeynes@1077
   101
    return (serial_device_t)serial_fd_device_new_file(in, out, TRUE);
nkeynes@1077
   102
}
nkeynes@1077
   103
nkeynes@1077
   104
serial_device_t serial_fd_device_new_console()
nkeynes@1077
   105
{
nkeynes@1077
   106
    return serial_fd_device_new_file( stdin, stdout, FALSE );
nkeynes@1077
   107
}
nkeynes@1077
   108
nkeynes@1077
   109
serial_device_t serial_fd_device_new_file( FILE *in, FILE *out, gboolean closeOnDestroy )
nkeynes@1077
   110
{
nkeynes@1077
   111
    if( in != NULL )
nkeynes@1077
   112
        fcntl( fileno(in), F_SETFL, O_NONBLOCK );
nkeynes@1077
   113
nkeynes@1077
   114
    serial_fd_device_t dev = (serial_fd_device_t)malloc(sizeof(struct serial_fd_device));
nkeynes@1077
   115
    if( dev == NULL ) {
nkeynes@1077
   116
        if( closeOnDestroy ) {
nkeynes@1077
   117
            if( in != NULL )
nkeynes@1077
   118
                fclose(in);
nkeynes@1077
   119
            if( out != NULL && out != in )
nkeynes@1077
   120
                fclose(out);
nkeynes@1077
   121
        }
nkeynes@1077
   122
        return NULL;
nkeynes@1077
   123
    }
nkeynes@1077
   124
nkeynes@1077
   125
    dev->dev.attach = serial_fd_device_attach;
nkeynes@1077
   126
    dev->dev.detach = serial_fd_device_detach;
nkeynes@1077
   127
    dev->dev.destroy = serial_fd_device_destroy;
nkeynes@1077
   128
    dev->dev.set_line_speed = serial_fd_device_set_line_speed;
nkeynes@1077
   129
    dev->dev.set_line_params = serial_fd_device_set_line_params;
nkeynes@1077
   130
    dev->dev.receive_data = serial_fd_device_receive_data;
nkeynes@1077
   131
    dev->in = in;
nkeynes@1077
   132
    dev->out = out;
nkeynes@1077
   133
    dev->closeOnDestroy = closeOnDestroy;
nkeynes@1077
   134
    return (serial_device_t)dev;
nkeynes@1077
   135
}
nkeynes@1077
   136
nkeynes@1077
   137
static void serial_fd_device_attach(serial_device_t dev)
nkeynes@1077
   138
{
nkeynes@1077
   139
    serial_fd_device_t fddev = (serial_fd_device_t)dev;
nkeynes@1077
   140
    if( fddev->in != NULL )
nkeynes@1077
   141
        fddev->listener = io_register_listener( fileno(fddev->in), serial_fd_device_transmit_data, fddev, NULL );
nkeynes@1077
   142
}
nkeynes@1077
   143
nkeynes@1077
   144
static void serial_fd_device_detach(serial_device_t dev)
nkeynes@1077
   145
{
nkeynes@1077
   146
    serial_fd_device_t fddev = (serial_fd_device_t)dev;
nkeynes@1077
   147
    if( fddev->in != NULL )
nkeynes@1077
   148
        io_unregister_listener( fddev->listener );
nkeynes@1077
   149
}
nkeynes@1077
   150
nkeynes@1077
   151
static void serial_fd_device_destroy(serial_device_t dev)
nkeynes@1077
   152
{
nkeynes@1077
   153
    serial_fd_device_t fddev = (serial_fd_device_t)dev;
nkeynes@1077
   154
    if( fddev->closeOnDestroy ) {
nkeynes@1077
   155
        if( fddev->in != NULL )
nkeynes@1077
   156
            fclose(fddev->in);
nkeynes@1077
   157
        if( fddev->out != NULL && fddev->out != fddev->in )
nkeynes@1077
   158
            fclose(fddev->out);
nkeynes@1077
   159
    }
nkeynes@1077
   160
    fddev->in = NULL;
nkeynes@1077
   161
    fddev->out = NULL;
nkeynes@1077
   162
    free(fddev);
nkeynes@1077
   163
}
nkeynes@1077
   164
static void serial_fd_device_set_line_speed(struct serial_device *dev, uint32_t bps)
nkeynes@1077
   165
{
nkeynes@1077
   166
    /* Do nothing for now */
nkeynes@1077
   167
}
nkeynes@1077
   168
static void serial_fd_device_set_line_params(struct serial_device *dev, int flags)
nkeynes@1077
   169
{
nkeynes@1077
   170
    /* Do nothing for now */
nkeynes@1077
   171
}
nkeynes@1077
   172
static void serial_fd_device_receive_data(struct serial_device *dev, uint8_t value)
nkeynes@1077
   173
{
nkeynes@1077
   174
    serial_fd_device_t fddev = (serial_fd_device_t)dev;
nkeynes@1077
   175
    if( fddev->out != NULL )
nkeynes@1077
   176
        fputc( value, fddev->out );
nkeynes@1077
   177
}
nkeynes@1077
   178
nkeynes@1077
   179
static gboolean serial_fd_device_transmit_data( int fd, void *dev )
nkeynes@1077
   180
{
nkeynes@1077
   181
    serial_fd_device_t fddev = (serial_fd_device_t)dev;
nkeynes@1077
   182
    char buf[4096];
nkeynes@1077
   183
    size_t len = fread(buf, 1, sizeof(buf), fddev->in);
nkeynes@1077
   184
    if( len > 0 ) {
nkeynes@1077
   185
        serial_transmit_data(buf, len);
nkeynes@1077
   186
    }
nkeynes@1077
   187
    return TRUE;
nkeynes@1077
   188
}
.