filename | src/drivers/serial_unix.c |
changeset | 1077:136fc24d17ef |
next | 1079:691f9f621c5a |
author | nkeynes |
date | Wed Oct 07 17:53:56 2009 +1000 (14 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 |
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +00001.2 +++ b/src/drivers/serial_unix.c Wed Oct 07 17:53:56 2009 +10001.3 @@ -0,0 +1,188 @@1.4 +/**1.5 + * $Id$1.6 + *1.7 + * Host driver for a serial port attachment, that can be hooked to a character1.8 + * device, fifo or named pipe.1.9 + *1.10 + * Copyright (c) 2009 Nathan Keynes.1.11 + *1.12 + * This program is free software; you can redistribute it and/or modify1.13 + * it under the terms of the GNU General Public License as published by1.14 + * the Free Software Foundation; either version 2 of the License, or1.15 + * (at your option) any later version.1.16 + *1.17 + * This program is distributed in the hope that it will be useful,1.18 + * but WITHOUT ANY WARRANTY; without even the implied warranty of1.19 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the1.20 + * GNU General Public License for more details.1.21 + */1.22 +1.23 +#include <stdio.h>1.24 +#include <stdlib.h>1.25 +#include <fcntl.h>1.26 +#include <sys/stat.h>1.27 +1.28 +#include "lxdream.h"1.29 +#include "config.h"1.30 +#include "ioutil.h"1.31 +#include "serial.h"1.32 +1.33 +1.34 +typedef struct serial_fd_device {1.35 + struct serial_device dev;1.36 + FILE *in;1.37 + FILE *out;1.38 + gboolean closeOnDestroy;1.39 + io_listener_t listener;1.40 +} *serial_fd_device_t;1.41 +1.42 +static void serial_fd_device_attach(serial_device_t dev);1.43 +static void serial_fd_device_detach(serial_device_t dev);1.44 +static void serial_fd_device_destroy(serial_device_t dev);1.45 +static void serial_fd_device_set_line_speed(struct serial_device *dev, uint32_t bps);1.46 +static void serial_fd_device_set_line_params(struct serial_device *dev, int flags);1.47 +static void serial_fd_device_receive_data(struct serial_device *dev, uint8_t value);1.48 +static gboolean serial_fd_device_transmit_data( int fd, void *dev);1.49 +1.50 +static gboolean serial_config_changed(void *data, struct lxdream_config_group *group, unsigned item,1.51 + const gchar *oldval, const gchar *newval);1.52 +1.53 +struct lxdream_config_group serial_group =1.54 + { "serial", serial_config_changed, NULL, NULL,1.55 + {{ "device", N_("Serial device"), CONFIG_TYPE_FILE, "/dev/console" },1.56 + { NULL, CONFIG_TYPE_NONE }} };1.57 +1.58 +void serial_init()1.59 +{1.60 + const gchar *name = serial_group.params[0].value;1.61 + if( name != NULL ) {1.62 + serial_device_t dev = serial_fd_device_new_filename(name);1.63 + if( dev != NULL ) {1.64 + serial_attach_device( dev );1.65 + }1.66 + }1.67 +}1.68 +1.69 +static gboolean serial_config_changed(void *data, struct lxdream_config_group *group, unsigned item,1.70 + const gchar *oldval, const gchar *newval)1.71 +{1.72 + if( item == 0 ) {1.73 + serial_destroy_device(serial_detach_device());1.74 + serial_device_t dev = serial_fd_device_new_filename(newval);1.75 + if( dev != NULL ) {1.76 + serial_attach_device( dev );1.77 + }1.78 + }1.79 +}1.80 +1.81 +1.82 +1.83 +serial_device_t serial_fd_device_new_filename( const gchar *filename )1.84 +{1.85 + FILE *out = fopen( filename, "w+" );1.86 + FILE *in;1.87 + struct stat st;1.88 +1.89 + if( out == NULL ) {1.90 + return NULL;1.91 + }1.92 +1.93 + if( fstat( fileno(out), &st ) != 0 ) {1.94 + fclose(out);1.95 + return NULL;1.96 + }1.97 +1.98 + if( S_ISCHR(st.st_mode) || S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode) ) {1.99 + in = out;1.100 + } else {1.101 + in = NULL;1.102 + }1.103 +1.104 + return (serial_device_t)serial_fd_device_new_file(in, out, TRUE);1.105 +}1.106 +1.107 +serial_device_t serial_fd_device_new_console()1.108 +{1.109 + return serial_fd_device_new_file( stdin, stdout, FALSE );1.110 +}1.111 +1.112 +serial_device_t serial_fd_device_new_file( FILE *in, FILE *out, gboolean closeOnDestroy )1.113 +{1.114 + if( in != NULL )1.115 + fcntl( fileno(in), F_SETFL, O_NONBLOCK );1.116 +1.117 + serial_fd_device_t dev = (serial_fd_device_t)malloc(sizeof(struct serial_fd_device));1.118 + if( dev == NULL ) {1.119 + if( closeOnDestroy ) {1.120 + if( in != NULL )1.121 + fclose(in);1.122 + if( out != NULL && out != in )1.123 + fclose(out);1.124 + }1.125 + return NULL;1.126 + }1.127 +1.128 + dev->dev.attach = serial_fd_device_attach;1.129 + dev->dev.detach = serial_fd_device_detach;1.130 + dev->dev.destroy = serial_fd_device_destroy;1.131 + dev->dev.set_line_speed = serial_fd_device_set_line_speed;1.132 + dev->dev.set_line_params = serial_fd_device_set_line_params;1.133 + dev->dev.receive_data = serial_fd_device_receive_data;1.134 + dev->in = in;1.135 + dev->out = out;1.136 + dev->closeOnDestroy = closeOnDestroy;1.137 + return (serial_device_t)dev;1.138 +}1.139 +1.140 +static void serial_fd_device_attach(serial_device_t dev)1.141 +{1.142 + serial_fd_device_t fddev = (serial_fd_device_t)dev;1.143 + if( fddev->in != NULL )1.144 + fddev->listener = io_register_listener( fileno(fddev->in), serial_fd_device_transmit_data, fddev, NULL );1.145 +}1.146 +1.147 +static void serial_fd_device_detach(serial_device_t dev)1.148 +{1.149 + serial_fd_device_t fddev = (serial_fd_device_t)dev;1.150 + if( fddev->in != NULL )1.151 + io_unregister_listener( fddev->listener );1.152 +}1.153 +1.154 +static void serial_fd_device_destroy(serial_device_t dev)1.155 +{1.156 + serial_fd_device_t fddev = (serial_fd_device_t)dev;1.157 + if( fddev->closeOnDestroy ) {1.158 + if( fddev->in != NULL )1.159 + fclose(fddev->in);1.160 + if( fddev->out != NULL && fddev->out != fddev->in )1.161 + fclose(fddev->out);1.162 + }1.163 + fddev->in = NULL;1.164 + fddev->out = NULL;1.165 + free(fddev);1.166 +}1.167 +static void serial_fd_device_set_line_speed(struct serial_device *dev, uint32_t bps)1.168 +{1.169 + /* Do nothing for now */1.170 +}1.171 +static void serial_fd_device_set_line_params(struct serial_device *dev, int flags)1.172 +{1.173 + /* Do nothing for now */1.174 +}1.175 +static void serial_fd_device_receive_data(struct serial_device *dev, uint8_t value)1.176 +{1.177 + serial_fd_device_t fddev = (serial_fd_device_t)dev;1.178 + if( fddev->out != NULL )1.179 + fputc( value, fddev->out );1.180 +}1.181 +1.182 +static gboolean serial_fd_device_transmit_data( int fd, void *dev )1.183 +{1.184 + serial_fd_device_t fddev = (serial_fd_device_t)dev;1.185 + char buf[4096];1.186 + size_t len = fread(buf, 1, sizeof(buf), fddev->in);1.187 + if( len > 0 ) {1.188 + serial_transmit_data(buf, len);1.189 + }1.190 + return TRUE;1.191 +}
.