unix_devs.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2000-2004 by ETH Zurich
00003  *
00004  * Redistribution and use in source and binary forms, with or without
00005  * modification, are permitted provided that the following conditions
00006  * are met:
00007  *
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the copyright holders nor the names of
00014  *    contributors may be used to endorse or promote products derived
00015  *    from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY ETH ZURICH AND CONTRIBUTORS
00018  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00019  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00020  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ETH ZURICH
00021  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00022  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00023  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00024  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00025  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00026  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00027  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00028  * SUCH DAMAGE.
00029  *
00030  * For additional information see http://www.ethernut.de/
00031  *
00032  */
00033 
00034 /* unix_devs.c - a nut/os device driver for native unix devices
00035  *
00036  * 2004.04.01 Matthias Ringwald <matthias.ringwald@inf.ethz.ch>
00037  *
00038  * \todo check block read implementation
00039  * \todo allow native filee accesss using names like "FAT_C:/.." \see fs/fat.c
00040  * \todo implement cooked mode and use it as default mode
00041  *
00042  */
00043 
00044 /* avoid stdio nut wrapper */
00045 #define NO_STDIO_NUT_WRAPPER
00046 
00047 #include <fcntl_orig.h>
00048 #include <arch/unix.h>
00049 #include <sys/atom.h>
00050 #include <sys/device.h>
00051 #include <sys/file.h>
00052 #include <sys/timer.h>
00053 #include <sys/thread.h>
00054 #include <sys/event.h>
00055 #include <dev/usart.h>
00056 #include <dev/irqreg.h>
00057 #include <errno.h>
00058 
00059 #include <stdio.h>
00060 #include <stdlib.h>
00061 #include <string.h>
00062 #include <unistd.h>
00063 #include <termios.h>
00064 
00065 #include <dev/unix_devs.h>
00066 
00067 // for sockets 
00068 #include <sys/types.h>
00069 #include <sys/socket.h>  // 
00070 #include <netinet/in.h>  // 
00071 #include <arpa/inet.h>   // 
00072 #include <netdb.h>
00073 #include <sys/uio.h>     
00074 #include <unistd.h>
00075 #include <string.h>
00076 
00077 
00078 #ifdef __CYGWIN__
00079 #include <sys/select.h>
00080 #endif
00081 
00082 /* on mac os x, not all baud rates are defined in termios.h but
00083    they are mapped to the numeric value anyway, so we define them here */
00084 #ifdef __APPLE__
00085 #ifndef B460800
00086 #define B460800 460800
00087 #endif
00088 #ifndef B500000
00089 #define B500000 500000
00090 #endif
00091 #ifndef B576000
00092 #define B576000 576000
00093 #endif
00094 #ifndef B921600
00095 #define B921600 921600
00096 #endif
00097 #endif
00098 
00099 
00100 
00101 /* thread attributes */
00102 pthread_attr_t unix_devs_attr;
00103 
00104 /* protect thread signaling */
00105 pthread_mutex_t unix_devs_mutex;
00106 
00107 /* to get a new thread start acked'd */
00108 pthread_cond_t unix_devs_cv;
00109 
00110 
00111 /*
00112  * functions available on avr somehow -- not implemented properly here :(
00113  */
00114 char *dtostre(double f, char *str, uint8_t prec, uint8_t flags);
00115 char *dtostre(double f, char *str, uint8_t prec, uint8_t flags)
00116 {
00117     sprintf(str, "%e", f);
00118     return str;
00119 }
00120 char *dtostrf(double f, char width, char prec, char *str);
00121 char *dtostrf(double f, char width, char prec, char *str)
00122 {
00123     sprintf(str, "%f", f);
00124     return str;
00125 }
00126 
00127 /*
00128  * Quite unnecessary functions, because linux doesn't define B19200 as 19200
00129  * we have to map those value to their symbolic counterparts:
00130  * 0
00131  * 50
00132  * 75
00133  * 110
00134  * 134
00135  * 150
00136  * 200
00137  * 300
00138  * 600
00139  * 1200
00140  * 1800
00141  * 2400
00142  * 4800
00143  * 9600
00144  * 19200
00145  * 38400
00146  * 57600
00147  * 115200
00148  * 230400
00149  * 460800
00150  * 500000
00151  * 576000
00152  * 921600
00153  */
00154 static int convertToRealSpeed(int baudSpeed)
00155 {
00156     switch (baudSpeed) {
00157     case B0:
00158         return 0;
00159     case B50:
00160         return 50;
00161     case B75:
00162         return 75;
00163     case B110:
00164         return 110;
00165     case B134:
00166         return 134;
00167     case B150:
00168         return 150;
00169     case B200:
00170         return 200;
00171     case B300:
00172         return 300;
00173     case B600:
00174         return 600;
00175     case B1200:
00176         return 1200;
00177     case B1800:
00178         return 1800;
00179     case B2400:
00180         return 2400;
00181     case B4800:
00182         return 4800;
00183     case B9600:
00184         return 9600;
00185     case B19200:
00186         return 19200;
00187     case B38400:
00188         return 38400;
00189     case B57600:
00190         return 57600;
00191     case B115200:
00192         return 115200;
00193     case B230400:
00194         return 230400;
00195 #ifndef __CYGWIN__
00196     case B460800:
00197         return 460800;
00198     case B500000:
00199         return 500000;
00200     case B576000:
00201         return 576000;
00202     case B921600:
00203         return 921600;
00204 #endif
00205     }
00206     return -1;
00207 }
00208 
00209 
00210 static int convertToBaudSpeed(int realSpeed)
00211 {
00212     switch (realSpeed) {
00213     case 0:
00214         return B0;
00215     case 50:
00216         return B50;
00217     case 75:
00218         return B75;
00219     case 110:
00220         return B110;
00221     case 134:
00222         return B134;
00223     case 150:
00224         return B150;
00225     case 200:
00226         return B200;
00227     case 300:
00228         return B300;
00229     case 600:
00230         return B600;
00231     case 1200:
00232         return B1200;
00233     case 1800:
00234         return B1800;
00235     case 2400:
00236         return B2400;
00237     case 4800:
00238         return B4800;
00239     case 9600:
00240         return B9600;
00241     case 19200:
00242         return B19200;
00243     case 38400:
00244         return B38400;
00245     case 57600:
00246         return B57600;
00247     case 115200:
00248         return B115200;
00249     case 230400:
00250         return B230400;
00251 #ifndef __CYGWIN__
00252     case 460800:
00253         return B460800;
00254     case 500000:
00255         return B500000;
00256     case 576000:
00257         return B576000;
00258     case 921600:
00259         return B921600;
00260 #endif
00261     }
00262     return -1;
00263 }
00264 
00265 /* ======================= sockets ======================== */
00266 
00267 unsigned int resolve(char *);
00268 unsigned int resolve(char *ip_addr)
00269 {
00270     struct hostent *hp;
00271     unsigned int ip;
00272     hp = gethostbyname(ip_addr);
00273     if (!hp)
00274     {
00275         ip = inet_addr(ip_addr);
00276         if ((int)ip == -1) {
00277             return -1;
00278         } else {
00279             return ip;
00280         }
00281     }
00282     // hp->h_length should equal to 4
00283     memcpy(&ip, hp->h_addr, 4);
00284     return ip;
00285 }
00286 
00287 
00288 /*
00289  * IRQ Handler for correct signaling
00290  * not currently used (see UnixDevReadThread for more info on variants
00291 static void UnixDevRxIntr(void *arg){
00292     NUTDEVICE* dev = (NUTDEVICE*) arg;
00293     UNIXDCB *  dcb = (UNIXDCB*) dev->dev_dcb;
00294     // printf("UnixDevRxIntr(%s)\n",dev->dev_name);
00295     NutEventPostFromIrq( &dcb->dcb_rx_rdy);
00296 }
00297  */
00298 
00299 
00300 /*
00301  * Read Thread
00302  *
00303  */
00304 static void *UnixDevReadThread( void * arg )
00305 {
00306     int ret;
00307     int fd;
00308     fd_set rfd_set;
00309 
00310     NUTDEVICE* dev = (NUTDEVICE*) arg;
00311     UNIXDCB *  dcb = (UNIXDCB*) dev->dev_dcb;
00312     
00313     // fd
00314     fd = dcb->dcb_fd;
00315     if (fd == STDOUT_FILENO)
00316         fd = STDIN_FILENO;
00317 
00318     // non-nut thread => block IRQ signals
00319     pthread_sigmask(SIG_BLOCK, &irq_signal, 0);
00320 
00321     // printf("UnixDevReadThread() started\n");
00322     
00323     // be ready to receive requests
00324     pthread_mutex_lock(&dcb->dcb_rx_mutex);
00325 
00326     // confirm start
00327     pthread_mutex_lock(&unix_devs_mutex);
00328     pthread_cond_signal(&unix_devs_cv);
00329     pthread_mutex_unlock(&unix_devs_mutex);
00330 
00331     // printf("UnixDevReadThread(%s) start confirmed\n", dev->dev_name);
00332 
00333     // 
00334     for (;;) {
00335 
00336         pthread_cond_wait(&dcb->dcb_rx_trigger, &dcb->dcb_rx_mutex);
00337 
00338         // printf("UnixDevReadThread(%s) triggered\n", dev->dev_name);
00339 
00340         // wait for data to become ready //
00341         do {
00342 
00343             FD_ZERO(&rfd_set);
00344             FD_SET(fd, &rfd_set);
00345             ret = select(fd + 1, &rfd_set, NULL, NULL, NULL);
00346         } while (FD_ISSET(fd, &rfd_set) == 0);
00347 
00348         // printf("UnixDevReadThread(%s) task processed\n", dev->dev_name);
00349 
00350         // signale waiting thread
00351 
00352         /* version 1 (working but could cause a race condition)
00353         NutEventPostAsync( &dcb->dcb_rx_rdy);
00354         */
00355         
00356         /* version 2 (correct, but currently very slow)
00357         if (dev->dev_name[4] == '0') {
00358             NutIRQTrigger(IRQ_UART0_RX);
00359         } else {
00360             NutIRQTrigger(IRQ_UART1_RX);
00361         }*/
00362  
00363         /* version 3 (another hack, but fast and correct */
00364         switch (dev->dev_name[4]) {
00365             case '0':
00366                 NutUnixIrqEventPostAsync( IRQ_UART0_RX,  &dcb->dcb_rx_rdy);
00367                 break;
00368             case '1':
00369                 NutUnixIrqEventPostAsync( IRQ_UART1_RX,  &dcb->dcb_rx_rdy);
00370                 break;
00371             case '2':
00372                 NutUnixIrqEventPostAsync( IRQ_UART2_RX,  &dcb->dcb_rx_rdy);
00373                 break;
00374         }
00375 
00376     }
00377    
00378     return 0;
00379 }
00380 
00381 
00387 static NUTFILE *UnixDevOpen(NUTDEVICE * dev, const char *name, int mode, int acc)
00388 {
00389     NUTFILE *nf;
00390 
00391     int nativeFile;
00392     char *nativeName;
00393     struct termios t;
00394     long baud;
00395     pthread_t *thread;
00396 
00397     // sockets
00398     struct sockaddr_in sinaddr;
00399     struct sockaddr_in remote;
00400     unsigned int remote_ip;
00401     unsigned int remote_port;
00402     char *ip;
00403     char *port;
00404 //    char *idx;
00405     
00406     // map from dev->name to unix name
00407     if (strncmp("uart", dev->dev_name, 4) == 0) {
00408         // uart
00409         switch (dev->dev_name[4]) {
00410             case '0':
00411                 nativeName = emulation_options.uart_options[0].device;
00412                 break;
00413             case '1':
00414                 nativeName = emulation_options.uart_options[1].device;
00415                 break;
00416             case '2':
00417                 nativeName = emulation_options.uart_options[2].device;
00418                 break;
00419             default:
00420                 return NULL;
00421         }
00422     } else
00423         return NULL;
00424 
00425     // check for sockets
00426     // try to split "device name" into ip:port
00427     if (strncmp("stdio", nativeName, 5)==0) {
00428         ip = nativeName;
00429         port = NULL;
00430     } else { 
00431         ip = strtok( nativeName, ":");
00432         port = strtok ( NULL, ":");
00433     }
00434 
00435     // printf("UnixDevOpen: Nut name = %s, unix name = %s\n",  dev->dev_name, nativeName);
00436 
00437     // determine mode -- not implemented yet 
00438     // set default mode
00439     mode = O_RDWR | O_NOCTTY;
00440 
00441     // fopen unix device
00442     if (strcmp("stdio", nativeName) == 0) {
00443 
00444         nativeFile = STDOUT_FILENO;
00445 
00446         // make raw
00447         if (tcgetattr(nativeFile, &t) == 0) {
00448 
00449             /* set input mode (non-canonical, no echo,...) but allow INTR signal */
00450             // bzero(&t, sizeof(t));
00451             t.c_lflag = ISIG;
00452             t.c_cc[VTIME] = 0;  /* inter-character timer unused */
00453             t.c_cc[VMIN] = 0;   /* non-blocking read */
00454 
00455             // apply file descriptor options
00456             if (tcsetattr(nativeFile, TCSANOW, &t) < 0) {
00457                 printf("UnixDevOpen: tcsetattr failed\n\r");
00458             }
00459             ((UNIXDCB*)dev->dev_dcb)->dcb_socket = 0;
00460         }
00461 
00462     } else if (port) {
00463 
00464         // tcp/ip socket
00465         remote_ip = resolve ( ip );
00466         remote_port = atoi( port );
00467         
00468         if ( ip ) {
00469         
00470             NutEnterCritical();
00471 
00472             // create socket
00473             nativeFile = socket(AF_INET, SOCK_STREAM, 0);
00474             
00475             // set inbound address
00476             sinaddr.sin_family = AF_INET;
00477             sinaddr.sin_addr.s_addr = INADDR_ANY;
00478             sinaddr.sin_port = htons(0);
00479 
00480             // bind to socket
00481             bind(nativeFile, (struct sockaddr *)&sinaddr, sizeof(sinaddr));
00482             
00483             // set remote address
00484             remote.sin_family = AF_INET;
00485             remote.sin_port = htons(remote_port);
00486             remote.sin_addr.s_addr = remote_ip;
00487             
00488             // try to connect
00489             if ( connect ( nativeFile, (struct sockaddr *)&remote, sizeof(remote) ) == 0) {
00490                 // connected
00491                 ((UNIXDCB*)dev->dev_dcb)->dcb_socket = 1;
00492                 
00493             } else {
00494                 NutExitCritical();
00495                 printf( "UnixDevOpen: Connect to %s port %d failed (errno = %d)\n\r", ip, remote_port, errno);
00496                 return NULL;
00497             }            
00498         } else {
00499             NutExitCritical();
00500             printf("UnixDevOpen: Could not resolve IP address of '%s'!\n", ip);
00501             return NULL;
00502         }  
00503         
00504 
00505     } else {
00506 
00507         nativeFile = open(nativeName, mode);
00508         
00509         if (nativeFile < 0) {
00510             printf("UnixDevOpen: open('%s',%d) failed!\n", nativeName, mode);
00511             return NULL;
00512         }
00513         
00514         /* flush pending data*/
00515         if (tcflush( nativeFile, TCIOFLUSH)) {
00516             printf("UnixDevOpen: tcflush('%s',%d) failed!\n", nativeName, TCIOFLUSH);
00517             return NULL;
00518         } 
00519 
00520         if (tcgetattr(nativeFile, &t) == 0) {
00521 
00522             baud = convertToBaudSpeed(USART_INITSPEED);
00523 
00524             bzero(&t, sizeof(t));
00525             t.c_cflag = CS8 | CLOCAL | CREAD;
00526             t.c_iflag = IGNPAR;
00527             t.c_oflag = 0;
00528 
00529             cfsetospeed(&t, baud);
00530             cfsetispeed(&t, baud);
00531 
00532             /* set input mode (non-canonical, no echo,...) */
00533             t.c_lflag = 0;
00534             t.c_cc[VTIME] = 0;  /* inter-character timer unused */
00535             t.c_cc[VMIN] = 0;   /* non-blocking read */
00536 
00537             tcflush(nativeFile, TCIFLUSH);
00538 
00539             // apply file descriptor options
00540             if (tcsetattr(nativeFile, TCSANOW, &t) < 0) {
00541                 printf("UnixDevOpen: tcsetattr failed\n\r");
00542             }
00543         }
00544         ((UNIXDCB*)dev->dev_dcb)->dcb_socket = 0;
00545 
00546     }
00547 
00548     if (nativeFile == 0)
00549         return NULL;
00550 
00551     // set non-blocking
00552     if (fcntl(nativeFile, F_SETFL, O_NONBLOCK) < 0) {
00553         printf("UnixDevOpen: fcntl O_NONBLOCK failed\n\r");
00554     }
00555 
00556     // store unix fd in dev
00557     ((UNIXDCB*)dev->dev_dcb)->dcb_fd = nativeFile;
00558 
00559     // printf("UnixDevOpen: %s, fd * %d\n\r", nativeName, nativeFile);
00560     // printf("UnixDevOpen: stdout %d, stdin %d, stderr %d \n\r", fileno(stdin), fileno(stdout), fileno(stderr));
00561 
00562     /* initialized rx IRQ handler -- not currently used (see UnixDevReadThread for more info on variants 
00563     if (dev->dev_name[4] == '0') {
00564         NutRegisterIrqHandler(IRQ_UART0_RX, UnixDevRxIntr, dev);
00565     } else
00566     {
00567         NutRegisterIrqHandler(IRQ_UART1_RX, UnixDevRxIntr, dev);
00568     }
00569     */
00570         
00571     /* Initialize mutex and condition variable objects */
00572     pthread_mutex_init(&unix_devs_mutex, NULL);
00573     pthread_mutex_init(&((UNIXDCB*)dev->dev_dcb)->dcb_rx_mutex, NULL);
00574 
00575     pthread_attr_init(&unix_devs_attr);
00576     pthread_attr_setdetachstate(&unix_devs_attr, PTHREAD_CREATE_JOINABLE);
00577 
00578     // unix_devs_cv init
00579     pthread_cond_init(&unix_devs_cv, NULL);
00580     pthread_cond_init( &((UNIXDCB*)dev->dev_dcb)->dcb_rx_trigger, NULL);
00581 
00582     // get thread struct
00583     thread = malloc(sizeof(pthread_t));
00584 
00585     // lock mutex and start thread
00586     pthread_mutex_lock(&unix_devs_mutex);
00587     pthread_create(thread, &unix_devs_attr, UnixDevReadThread, dev);
00588 
00589     // printf("UnixDevOpen: %s, waiting for UnixDevRead ack\n\r", nativeName);
00590 
00591     // wait for ack
00592     pthread_cond_wait(&unix_devs_cv, &unix_devs_mutex);
00593     pthread_mutex_unlock(&unix_devs_mutex);
00594 
00595     // printf("UnixDevOpen: %s, ack from UnixDevRead received\n\r", nativeName);
00596 
00597     // create new NUTFILE using malloc
00598     nf = malloc(sizeof(NUTFILE));
00599 
00600     // enter data
00601     nf->nf_next = 0;
00602     nf->nf_dev = dev;
00603     nf->nf_fcb = 0;
00604 
00605     return nf;
00606 }
00607 
00608 
00614 static int UnixDevWrite(NUTFILE * nf, CONST void *buffer, int len)
00615 {
00616     int rc;
00617     int remaining = len;
00618     UNIXDCB * dcb = (UNIXDCB*) nf->nf_dev->dev_dcb;
00619     
00620     /* flush ? */
00621     if (len == 0)
00622         return 0;
00623         
00624     do {
00625         rc = write(dcb->dcb_fd, buffer, remaining);
00626         if (rc > 0) {
00627             buffer += rc;
00628             remaining -= rc;
00629         }
00630     } while (remaining > 0);
00631     return len;
00632 }
00633 
00634 
00635 
00636  
00642 static int UnixDevRead(NUTFILE * nf, void *buffer, int len)
00643 {
00644     int newBytes;
00645     int fd;
00646     fd_set rfd_set;
00647     int ret;
00648     struct timeval timeout;
00649 
00650     int rc = 0;
00651     UNIXDCB * dcb = (UNIXDCB*) nf->nf_dev->dev_dcb;
00652 
00653     // fd
00654     fd = dcb->dcb_fd;
00655     if (fd == STDOUT_FILENO)
00656         fd = STDIN_FILENO;
00657     
00658     // test for read len. len == 0 => flush fd
00659     if (len == 0){
00660         tcflush(fd, TCIFLUSH);
00661         return 0;
00662     }
00663     
00664     // printf("UnixDevRead: called: len = %d\n\r",len);
00665     timeout.tv_usec = 0;
00666     timeout.tv_sec  = 0;
00667 
00668     do {
00669 
00670         // data available ?
00671         FD_ZERO(&rfd_set);
00672         FD_SET(fd, &rfd_set);
00673         ret = select(fd + 1, &rfd_set, NULL, NULL, &timeout);
00674       
00675         if (FD_ISSET(fd, &rfd_set) == 0) {
00676 
00677             // no data available. let's block the nut way...
00678 
00679             // printf("UnixDevRead(%s): no data ready, signaling read thread\n\r", nf->nf_dev->dev_name);
00680 
00681             // prepared signaling
00682             dcb->dcb_rx_rdy = 0;
00683 
00684             // lock mutex and signal read thread
00685             pthread_mutex_lock(&dcb->dcb_rx_mutex);
00686             pthread_cond_signal(&dcb->dcb_rx_trigger);
00687             pthread_mutex_unlock(&dcb->dcb_rx_mutex);
00688 
00689             // printf("UnixDevRead(%s): no data ready, waiting for answer\n\r", nf->nf_dev->dev_name);
00690 
00691             // wait for data to be ready
00692             NutEventWait( &dcb->dcb_rx_rdy, dcb->dcb_rtimeout);
00693 
00694             // printf("UnixDevRead(%s): got answer\n\r", nf->nf_dev->dev_name);
00695 
00696         }
00697 
00698         //  printf("UnixDevRead(%s): before read\n\r", nf->nf_dev->dev_name);
00699         newBytes = read( fd, buffer, len);
00700         // printf("UnixDevRead(%s): read some bytes. res = %d\n\r", nf->nf_dev->dev_name, newBytes);
00701 
00702         /* error or timeout ? */
00703         if (newBytes < 0) {
00704 
00705             if (errno == EAGAIN) {
00706                 // timeout. No data available right now
00707                 // printf("UnixDevRead: no bytes available, trying again\n\r");
00708                 errno = 0;
00709                 continue;
00710             } else {
00711 
00712                 printf("UnixDevRead: error %d occured, giving up\n\r", errno);
00713                 return newBytes;
00714             }
00715         } else
00716             rc += newBytes;
00717 
00718 #ifdef UART_SETBLOCKREAD
00719         // printf("UnixDevRead: UART_SETBLOCKREAD defined\n\r");
00720         // check for blocking read: all bytes received
00721         if ( (dcb->dcb_modeflags & USART_MF_BLOCKREAD) && (rc < len)) {
00722             // printf("UnixDevRead: block read enabled, but not enough bytes read \n\r");
00723             continue;
00724         }
00725 #endif
00726         // did we get one?
00727         if (rc > 0)
00728             break;
00729 
00730     } while (1);
00731 
00732     return rc;
00733 }
00734 
00740 static int UnixDevClose(NUTFILE * nf)
00741 {
00742     UNIXDCB * dcb = (UNIXDCB*) nf->nf_dev->dev_dcb;
00743     if ( dcb->dcb_fd > STDERR_FILENO)
00744         close( dcb->dcb_fd );
00745     return 0;
00746 }
00747 
00781 int UnixDevIOCTL(NUTDEVICE * dev, int req, void *conf)
00782 {
00783     struct termios t;
00784     uint32_t *lvp = (uint32_t *) conf;
00785     uint32_t lv = *lvp;
00786     UNIXDCB * dcb = (UNIXDCB*) dev->dev_dcb;
00787     
00788     // printf("UnixDevIOCTL, native %x, req: %d, lv: %ld\n\r", dcb->dcb_fd , req, lv);
00789 
00790     switch (req) {
00791 
00792     case UART_SETSPEED:
00793     case UART_SETFLOWCONTROL:
00794     case UART_SETPARITY:
00795     case UART_SETDATABITS:
00796     case UART_SETSTOPBITS:
00797 
00798         // ok on stdio
00799         if ( dcb->dcb_fd <= STDERR_FILENO)
00800             return 0;
00801 
00802         // ok on sockets
00803         if ( dcb->dcb_socket)
00804             return 0;
00805 
00806         if (tcgetattr( dcb->dcb_fd , &t)) {
00807             printf("UnixDevIOCTL, tcgetattr failed\n\r");
00808             return -1;
00809         }
00810 
00811         switch (req) {
00812 
00813         case UART_SETSPEED:
00814             lv = convertToBaudSpeed(lv);
00815             cfsetospeed(&t, lv);
00816             cfsetispeed(&t, lv);
00817 
00818             break;
00819 
00820         case UART_SETFLOWCONTROL:
00821             switch (lv) {
00822             case 0:
00823                 t.c_cflag &= ~CRTSCTS;
00824                 t.c_iflag &= ~(IXON | IXOFF | IXANY);
00825                 break;
00826             case UART_HS_SOFT:
00827                 t.c_cflag &= ~CRTSCTS;
00828                 t.c_iflag |= (IXON | IXOFF | IXANY);
00829                 return -1;
00830             case UART_HS_MODEM:
00831                 return -1;
00832             case UART_HS_RTSCTS:
00833                 t.c_cflag |= CRTSCTS;
00834                 t.c_iflag &= ~(IXON | IXOFF | IXANY);
00835                 break;
00836             default:
00837                 return -1;
00838             }
00839             break;
00840 
00841         case UART_SETPARITY:
00842             // 0 (none), 1 (odd) or 2 (even).
00843             t.c_cflag &= ~(PARODD | PARENB);
00844             switch (lv) {
00845             case 0:
00846                 break;
00847             case 1:
00848                 t.c_cflag |= PARENB | PARODD;
00849                 break;
00850             case 2:
00851                 t.c_cflag |= PARENB;
00852             default:
00853                 return -1;
00854             }
00855             break;
00856 
00857 
00858         case UART_SETDATABITS:
00859             t.c_cflag &= ~CSIZE;
00860             switch (lv) {
00861             case 5:
00862                 t.c_cflag |= CS5;
00863                 break;
00864             case 6:
00865                 t.c_cflag |= CS6;
00866                 break;
00867             case 7:
00868                 t.c_cflag |= CS7;
00869                 break;
00870             case 8:
00871                 t.c_cflag |= CS8;
00872                 break;
00873             default:
00874                 return -1;
00875             }
00876             break;
00877 
00878         case UART_SETSTOPBITS:
00879             switch (lv) {
00880             case 1:
00881                 t.c_cflag &= ~CSTOPB;
00882                 break;
00883             case 2:
00884                 t.c_cflag |= CSTOPB;
00885                 break;
00886             default:
00887                 return -1;
00888             }
00889             break;
00890 
00891         }
00892 
00893         /* tcdrain fails on mac os x for some unknown reason -- work around */
00894         while (tcdrain( dcb->dcb_fd ) < 0) {
00895             // printf("UnixDevIOCTL: tcdrain failed: errno: %d\n\r", errno);
00896             errno = 0;
00897             usleep(1000);
00898         }
00899 
00900         if (tcsetattr( dcb->dcb_fd , TCSANOW, &t) < 0) {
00901             printf("UnixDevIOCTL: tcsetattr failed: errno: %d\n\r", errno);
00902             errno = 0;
00903             return -1;
00904         }
00905         return 0;
00906 
00907     case UART_GETSPEED:
00908     case UART_GETFLOWCONTROL:
00909     case UART_GETPARITY:
00910     case UART_GETDATABITS:
00911     case UART_GETSTOPBITS:
00912 
00913         if ((dcb->dcb_fd <= STDERR_FILENO) || ( dcb->dcb_socket))
00914         {
00915             // default answers for sockets / stdio
00916             switch (req){
00917                 case UART_GETSPEED:
00918                     *lvp = 9600; return 0;
00919                 case UART_GETFLOWCONTROL:
00920                     *lvp = 0; return 0;
00921                 case UART_GETPARITY:
00922                     *lvp = 0; return 0;
00923                 case UART_GETDATABITS:
00924                     *lvp = 8; return 0;
00925                 case UART_GETSTOPBITS:
00926                     *lvp = 1; return 0;
00927             }
00928             return 0;
00929         }
00930         
00931         if (tcgetattr(dcb->dcb_fd, &t) != 0)
00932             return -1;
00933 
00934         switch (req) {
00935 
00936         case UART_GETSPEED:
00937             *lvp = convertToRealSpeed(cfgetospeed(&t));
00938             break;
00939 
00940         case UART_GETFLOWCONTROL:
00941             if (t.c_cflag & CRTSCTS)
00942                 *lvp = UART_HS_RTSCTS;
00943             else if (t.c_iflag & IXANY)
00944                 *lvp = UART_HS_SOFT;
00945             else
00946                 *lvp = 0;
00947             break;
00948 
00949         case UART_GETPARITY:
00950             if (t.c_cflag & PARENB) {
00951                 if (t.c_cflag & PARODD)
00952                     *lvp = 1;
00953                 else
00954                     *lvp = 2;
00955             } else
00956                 *lvp = 0;
00957             break;
00958 
00959         case UART_GETDATABITS:
00960             switch (t.c_cflag & CSIZE) {
00961             case CS5:
00962                 *lvp = 5;
00963                 break;
00964             case CS6:
00965                 *lvp = 6;
00966                 break;
00967             case CS7:
00968                 *lvp = 7;
00969                 break;
00970             case CS8:
00971                 *lvp = 8;
00972                 break;
00973             default:
00974                 return -1;
00975             }
00976             break;
00977 
00978         case UART_GETSTOPBITS:
00979             if (t.c_cflag & CSTOPB)
00980                 *lvp = 2;
00981             else
00982                 *lvp = 1;
00983             break;
00984         }
00985         return 0;
00986 
00987 #ifdef UART_SETBLOCKREAD
00988     case UART_SETBLOCKREAD:
00989         if (lv)
00990             dcb->dcb_modeflags |= USART_MF_BLOCKREAD;
00991         else
00992             dcb->dcb_modeflags &= ~USART_MF_BLOCKREAD;
00993         return 0;
00994 
00995     case UART_GETBLOCKREAD:
00996         if ( dcb->dcb_modeflags & USART_MF_BLOCKREAD)
00997             *lvp = 1;
00998         else
00999             *lvp = 0;
01000         return 0;
01001 #endif
01002 
01003     case UART_SETCOOKEDMODE:
01004         if (*lvp == 0)
01005             return 0;
01006         else
01007             return -1;
01008             
01009     case UART_GETSTATUS:
01010         *lvp = 0;
01011         return 0;
01012 
01013     case UART_SETTXBUFSIZ:
01014     case UART_SETRXBUFSIZ:
01015     case UART_SETTXBUFHWMARK:
01016     case UART_SETRXBUFHWMARK:
01017     case UART_SETTXBUFLWMARK:
01018     case UART_SETRXBUFLWMARK:
01019     case UART_SETSTATUS:
01020         return 0;
01021         
01022     default:
01023         return -1;
01024     }
01025     return -1;
01026 }
01027 
01028 
01029 
01030 
01031 /* ======================= Devices ======================== */
01032 
01036 static UNIXDCB dcb_usart0 = {
01037     0,                          /* dcb_modeflags */
01038     0,                          /* dcb_statusflags */
01039     0,                          /* dcb_rtimeout */
01040     0,                          /* dcb_wtimeout */
01041     0,                          /* dbc_last_eol */
01042     0,                          /* dcb_fd */
01043     0,                          /* dcb_rx_rdy */
01044 /*  xx,                            dcb_rx_mutex */
01045 /*  xx,                            dcb_rx_trigger */
01046 };
01047 
01051 static UNIXDCB dcb_usart1 = {
01052     0,                          /* dcb_modeflags */
01053     0,                          /* dcb_statusflags */
01054     0,                          /* dcb_rtimeout */
01055     0,                          /* dcb_wtimeout */
01056     0,                          /* dbc_last_eol */
01057     0,                          /* dcb_fd */
01058     0,                          /* dcb_rx_rdy */
01059 /*  xx,                            dcb_rx_mutex */
01060 /*  xx,                            dcb_rx_trigger */
01061 };
01062 
01066 static UNIXDCB dcb_usart2 = {
01067     0,                          /* dcb_modeflags */
01068     0,                          /* dcb_statusflags */
01069     0,                          /* dcb_rtimeout */
01070     0,                          /* dcb_wtimeout */
01071     0,                          /* dbc_last_eol */
01072     0,                          /* dcb_fd */
01073     0,                          /* dcb_rx_rdy */
01074 /*  xx,                            dcb_rx_mutex */
01075 /*  xx,                            dcb_rx_trigger */
01076 };
01077 
01081 NUTDEVICE devDebug0 = {
01082     0,                          
01083     {'u', 'a', 'r', 't', '0', 0, 0, 0, 0}
01084     ,                           
01085     0,                          
01086     0,                          
01087     0,                          
01088     0,                          
01089     &dcb_usart0,                
01090     0,                          
01091     UnixDevIOCTL,               
01092     UnixDevRead,
01093     UnixDevWrite,
01094     UnixDevOpen,
01095     UnixDevClose,
01096     0
01097 };
01098 
01102 NUTDEVICE devDebug1 = {
01103     0,                          
01104     {'u', 'a', 'r', 't', '1', 0, 0, 0, 0}
01105     ,                           
01106     0,                          
01107     0,                          
01108     0,                          
01109     0,                          
01110     &dcb_usart1,                
01111     0,                          
01112     UnixDevIOCTL,               
01113     UnixDevRead,
01114     UnixDevWrite,
01115     UnixDevOpen,
01116     UnixDevClose,
01117     0
01118 };
01119 
01120 
01124 NUTDEVICE devUart0 = {
01125     0,                          
01126     {'u', 'a', 'r', 't', '0', 0, 0, 0, 0}
01127     ,                           
01128     0,                          
01129     0,                          
01130     0,                          
01131     0,                          
01132     &dcb_usart0,                
01133     0,                          
01134     UnixDevIOCTL,               
01135     UnixDevRead,
01136     UnixDevWrite,
01137     UnixDevOpen,
01138     UnixDevClose,
01139     0
01140 };
01141 
01145 NUTDEVICE devUart1 = {
01146     0,                          
01147     {'u', 'a', 'r', 't', '1', 0, 0, 0, 0}
01148     ,                           
01149     0,                          
01150     0,                          
01151     0,                          
01152     0,                          
01153     &dcb_usart1,                
01154     0,                          
01155     UnixDevIOCTL,               
01156     UnixDevRead,
01157     UnixDevWrite,
01158     UnixDevOpen,
01159     UnixDevClose,
01160     0
01161 };
01162 
01166 NUTDEVICE devUart2 = {
01167     0,                          
01168     {'u', 'a', 'r', 't', '2', 0, 0, 0, 0}
01169     ,                           
01170     0,                          
01171     0,                          
01172     0,                          
01173     0,                          
01174     &dcb_usart2,                
01175     0,                          
01176     UnixDevIOCTL,               
01177     UnixDevRead,
01178     UnixDevWrite,
01179     UnixDevOpen,
01180     UnixDevClose,
01181     0
01182 };
01183 
01187 NUTDEVICE devUsartAvr0 = {
01188     0,                          
01189     {'u', 'a', 'r', 't', '0', 0, 0, 0, 0}
01190     ,                           
01191     0,                          
01192     0,                          
01193     0,                          
01194     0,                          
01195     &dcb_usart0,                
01196     0,                          
01197     UnixDevIOCTL,               
01198     UnixDevRead,
01199     UnixDevWrite,
01200     UnixDevOpen,
01201     UnixDevClose,
01202     0
01203 };
01204 
01208 NUTDEVICE devUsartAvr1 = {
01209     0,                          
01210     {'u', 'a', 'r', 't', '1', 0, 0, 0, 0}
01211     ,                           
01212     0,                          
01213     0,                          
01214     0,                          
01215     0,                          
01216     &dcb_usart1,                
01217     0,                          
01218     UnixDevIOCTL,               
01219     UnixDevRead,
01220     UnixDevWrite,
01221     UnixDevOpen,
01222     UnixDevClose,
01223     0
01224 };
01225 
01229 NUTDEVICE devUsartAvr2 = {
01230     0,                          
01231     {'u', 'a', 'r', 't', '2', 0, 0, 0, 0}
01232     ,                           
01233     0,                          
01234     0,                          
01235     0,                          
01236     0,                          
01237     &dcb_usart2,                
01238     0,                          
01239     UnixDevIOCTL,               
01240     UnixDevRead,
01241     UnixDevWrite,
01242     UnixDevOpen,
01243     UnixDevClose,
01244     0
01245 };
01246 
01247 

© 2000-2007 by egnite Software GmbH - visit http://www.ethernut.de/