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 1081:ef31ae97bb8b
prev1079:691f9f621c5a
author nkeynes
date Sat Jan 26 14:00:48 2013 +1000 (11 years ago)
permissions -rw-r--r--
last change Change glib includes to #include <glib.h> rather than the individual
headers, as recent glib versions are breaking on this
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@1079
    52
       {{ "device", N_("Serial device"), CONFIG_TYPE_FILE, "/dev/tty" },
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@1081
    76
    return TRUE;
nkeynes@1077
    77
}
nkeynes@1077
    78
nkeynes@1077
    79
nkeynes@1077
    80
nkeynes@1077
    81
serial_device_t serial_fd_device_new_filename( const gchar *filename )
nkeynes@1077
    82
{
nkeynes@1077
    83
    FILE *out = fopen( filename, "w+" );
nkeynes@1077
    84
    FILE *in;
nkeynes@1077
    85
    struct stat st;
nkeynes@1077
    86
nkeynes@1077
    87
    if( out == NULL ) {
nkeynes@1077
    88
        return NULL;
nkeynes@1077
    89
    }
nkeynes@1077
    90
nkeynes@1077
    91
    if( fstat( fileno(out), &st ) != 0 ) {
nkeynes@1077
    92
        fclose(out);
nkeynes@1077
    93
        return NULL;
nkeynes@1077
    94
    }
nkeynes@1077
    95
nkeynes@1077
    96
    if( S_ISCHR(st.st_mode) || S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode) ) {
nkeynes@1077
    97
        in = out;
nkeynes@1077
    98
    } else {
nkeynes@1077
    99
        in = NULL;
nkeynes@1077
   100
    }
nkeynes@1077
   101
nkeynes@1077
   102
    return (serial_device_t)serial_fd_device_new_file(in, out, TRUE);
nkeynes@1077
   103
}
nkeynes@1077
   104
nkeynes@1077
   105
serial_device_t serial_fd_device_new_console()
nkeynes@1077
   106
{
nkeynes@1077
   107
    return serial_fd_device_new_file( stdin, stdout, FALSE );
nkeynes@1077
   108
}
nkeynes@1077
   109
nkeynes@1077
   110
serial_device_t serial_fd_device_new_file( FILE *in, FILE *out, gboolean closeOnDestroy )
nkeynes@1077
   111
{
nkeynes@1077
   112
    if( in != NULL )
nkeynes@1077
   113
        fcntl( fileno(in), F_SETFL, O_NONBLOCK );
nkeynes@1077
   114
nkeynes@1077
   115
    serial_fd_device_t dev = (serial_fd_device_t)malloc(sizeof(struct serial_fd_device));
nkeynes@1077
   116
    if( dev == NULL ) {
nkeynes@1077
   117
        if( closeOnDestroy ) {
nkeynes@1077
   118
            if( in != NULL )
nkeynes@1077
   119
                fclose(in);
nkeynes@1077
   120
            if( out != NULL && out != in )
nkeynes@1077
   121
                fclose(out);
nkeynes@1077
   122
        }
nkeynes@1077
   123
        return NULL;
nkeynes@1077
   124
    }
nkeynes@1077
   125
nkeynes@1077
   126
    dev->dev.attach = serial_fd_device_attach;
nkeynes@1077
   127
    dev->dev.detach = serial_fd_device_detach;
nkeynes@1077
   128
    dev->dev.destroy = serial_fd_device_destroy;
nkeynes@1077
   129
    dev->dev.set_line_speed = serial_fd_device_set_line_speed;
nkeynes@1077
   130
    dev->dev.set_line_params = serial_fd_device_set_line_params;
nkeynes@1077
   131
    dev->dev.receive_data = serial_fd_device_receive_data;
nkeynes@1077
   132
    dev->in = in;
nkeynes@1077
   133
    dev->out = out;
nkeynes@1077
   134
    dev->closeOnDestroy = closeOnDestroy;
nkeynes@1077
   135
    return (serial_device_t)dev;
nkeynes@1077
   136
}
nkeynes@1077
   137
nkeynes@1077
   138
static void serial_fd_device_attach(serial_device_t dev)
nkeynes@1077
   139
{
nkeynes@1077
   140
    serial_fd_device_t fddev = (serial_fd_device_t)dev;
nkeynes@1077
   141
    if( fddev->in != NULL )
nkeynes@1077
   142
        fddev->listener = io_register_listener( fileno(fddev->in), serial_fd_device_transmit_data, fddev, NULL );
nkeynes@1077
   143
}
nkeynes@1077
   144
nkeynes@1077
   145
static void serial_fd_device_detach(serial_device_t dev)
nkeynes@1077
   146
{
nkeynes@1077
   147
    serial_fd_device_t fddev = (serial_fd_device_t)dev;
nkeynes@1077
   148
    if( fddev->in != NULL )
nkeynes@1077
   149
        io_unregister_listener( fddev->listener );
nkeynes@1077
   150
}
nkeynes@1077
   151
nkeynes@1077
   152
static void serial_fd_device_destroy(serial_device_t dev)
nkeynes@1077
   153
{
nkeynes@1077
   154
    serial_fd_device_t fddev = (serial_fd_device_t)dev;
nkeynes@1077
   155
    if( fddev->closeOnDestroy ) {
nkeynes@1077
   156
        if( fddev->in != NULL )
nkeynes@1077
   157
            fclose(fddev->in);
nkeynes@1077
   158
        if( fddev->out != NULL && fddev->out != fddev->in )
nkeynes@1077
   159
            fclose(fddev->out);
nkeynes@1077
   160
    }
nkeynes@1077
   161
    fddev->in = NULL;
nkeynes@1077
   162
    fddev->out = NULL;
nkeynes@1077
   163
    free(fddev);
nkeynes@1077
   164
}
nkeynes@1077
   165
static void serial_fd_device_set_line_speed(struct serial_device *dev, uint32_t bps)
nkeynes@1077
   166
{
nkeynes@1077
   167
    /* Do nothing for now */
nkeynes@1077
   168
}
nkeynes@1077
   169
static void serial_fd_device_set_line_params(struct serial_device *dev, int flags)
nkeynes@1077
   170
{
nkeynes@1077
   171
    /* Do nothing for now */
nkeynes@1077
   172
}
nkeynes@1077
   173
static void serial_fd_device_receive_data(struct serial_device *dev, uint8_t value)
nkeynes@1077
   174
{
nkeynes@1077
   175
    serial_fd_device_t fddev = (serial_fd_device_t)dev;
nkeynes@1077
   176
    if( fddev->out != NULL )
nkeynes@1077
   177
        fputc( value, fddev->out );
nkeynes@1077
   178
}
nkeynes@1077
   179
nkeynes@1077
   180
static gboolean serial_fd_device_transmit_data( int fd, void *dev )
nkeynes@1077
   181
{
nkeynes@1077
   182
    serial_fd_device_t fddev = (serial_fd_device_t)dev;
nkeynes@1077
   183
    char buf[4096];
nkeynes@1077
   184
    size_t len = fread(buf, 1, sizeof(buf), fddev->in);
nkeynes@1077
   185
    if( len > 0 ) {
nkeynes@1077
   186
        serial_transmit_data(buf, len);
nkeynes@1077
   187
    }
nkeynes@1077
   188
    return TRUE;
nkeynes@1077
   189
}
.