OpenCores
URL https://opencores.org/ocsvn/s6soc/s6soc/trunk

Subversion Repositories s6soc

[/] [s6soc/] [trunk/] [sw/] [zipos/] [syspipe.c] - Diff between revs 27 and 45

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 27 Rev 45
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//
//
// Filename:    syspipe.c
// Filename:    syspipe.c
//
//
// Project:     CMod S6 System on a Chip, ZipCPU demonstration project
// Project:     CMod S6 System on a Chip, ZipCPU demonstration project
//
//
// Purpose:     This "device" handles the primary device level interaction of
// Purpose:     This "device" handles the primary device level interaction of
//              almost all devices on the ZipOS: the pipe.  A pipe, as defined
//              almost all devices on the ZipOS: the pipe.  A pipe, as defined
//      here, is an O/S supported FIFO.  Information written to the FIFO will
//      here, is an O/S supported FIFO.  Information written to the FIFO will
//      be read from the FIFO in the order it was received.  Attempts to read
//      be read from the FIFO in the order it was received.  Attempts to read
//      from an empty FIFO, or equivalently to write to a full FIFO, will block
//      from an empty FIFO, or equivalently to write to a full FIFO, will block
//      the reading (writing) process until memory is available.
//      the reading (writing) process until memory is available.
//
//
// Creator:     Dan Gisselquist, Ph.D.
// Creator:     Dan Gisselquist, Ph.D.
//              Gisselquist Technology, LLC
//              Gisselquist Technology, LLC
//
//
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//
//
// Copyright (C) 2015-2016, Gisselquist Technology, LLC
// Copyright (C) 2015-2016, Gisselquist Technology, LLC
//
//
// This program is free software (firmware): you can redistribute it and/or
// This program is free software (firmware): you can redistribute it and/or
// modify it under the terms of  the GNU General Public License as published
// modify it under the terms of  the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or (at
// by the Free Software Foundation, either version 3 of the License, or (at
// your option) any later version.
// your option) any later version.
//
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
// for more details.
// for more details.
//
//
// You should have received a copy of the GNU General Public License along
// You should have received a copy of the GNU General Public License along
// with this program.  (It's in the $(ROOT)/doc directory, run make with no
// with this program.  (It's in the $(ROOT)/doc directory, run make with no
// target there if the PDF file isn't present.)  If not, see
// target there if the PDF file isn't present.)  If not, see
// <http://www.gnu.org/licenses/> for a copy.
// <http://www.gnu.org/licenses/> for a copy.
//
//
// License:     GPL, v3, as defined and found on www.gnu.org,
// License:     GPL, v3, as defined and found on www.gnu.org,
//              http://www.gnu.org/licenses/gpl.html
//              http://www.gnu.org/licenses/gpl.html
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
#include "errno.h"
#include "errno.h"
#include "board.h"
#include "board.h"
#include "taskp.h"
#include "taskp.h"
#include "syspipe.h"
#include "syspipe.h"
#include "zipsys.h"
#include "zipsys.h"
#include "ktraps.h"
#include "ktraps.h"
 
#include "string.h"
 
 
#ifndef NULL
#ifndef NULL
#define NULL    (void *)0
#define NULL    (void *)0
#endif
#endif
 
 
void    kpush_syspipe(SYSPIPE *pipe, int val) {
void    kpush_syspipe(SYSPIPE *pipe, char val) {
        int     tst = (pipe->m_head+1)&pipe->m_mask;
        int     tst = (pipe->m_head+1)&pipe->m_mask;
        if (tst != pipe->m_tail) {
        if (tst != pipe->m_tail) {
                pipe->m_buf[pipe->m_head] = val;
                pipe->m_buf[pipe->m_head] = val;
                pipe->m_head = tst;             // Increment the head pointer
                pipe->m_head = tst;             // Increment the head pointer
                if ((pipe->m_rdtask)&&(pipe->m_rdtask != INTERRUPT_READ_TASK))
                if ((pipe->m_rdtask)&&(pipe->m_rdtask != INTERRUPT_READ_TASK))
                        pipe->m_rdtask->state = SCHED_READY;
                        pipe->m_rdtask->state = SCHED_READY;
        } else pipe->m_error = 1;
        } else pipe->m_error = 1;
}
}
 
 
extern  void    pipe_panic(SYSPIPE *p);
extern  void    pipe_panic(SYSPIPE *p);
int     kpop_syspipe(SYSPIPE *pipe, int *vl) {
/*
 
 * kpop_syspipe
 
 *
 
 * Called from an interrupt context to pop one byte off of the syspipe.
 
 */
 
int     kpop_syspipe(SYSPIPE *pipe, char *vl) {
        if (pipe->m_head != pipe->m_tail) {
        if (pipe->m_head != pipe->m_tail) {
 
                // The head will *only* equal the tail if the pipe is empty.
 
                // We come in here, therefore, if the pipe is non-empty
                *vl = pipe->m_buf[pipe->m_tail];
                *vl = pipe->m_buf[pipe->m_tail];
                pipe->m_tail = (pipe->m_tail+1)&pipe->m_mask;
                pipe->m_tail = (pipe->m_tail+1)&pipe->m_mask;
                if (pipe->m_wrtask)
                if (pipe->m_wrtask)
                        pipe->m_wrtask->state = SCHED_READY;
                        pipe->m_wrtask->state = SCHED_READY;
                return 0;
                return 0;
        }
        }
        return 1; // Error condition
        return 1; // Error condition
}
}
 
 
/* Returns how many values are in the pipe
/*
 
 * kpop_short_syspipe
 
 *
 
 * This is identical to kpop_syspipe, save that we are pulling a short value
 
 * off of the syspipe (i.e. a pair of chars), not just a single char.
 */
 */
/* Of course ... if it's not used, why include it?
int     kpop_short_syspipe(SYSPIPE *pipe, unsigned short *vl) {
 
        if (pipe->m_head == pipe->m_tail)
 
                return 1; // Error condition
 
 
 
        unsigned short *sptr = (unsigned short *)&pipe->m_buf[pipe->m_tail];
 
        // sv = pipe->m_buf[pipe->m_tail];
 
        *vl = *sptr;;
 
        pipe->m_tail = (pipe->m_tail+2)&pipe->m_mask;
 
        if (pipe->m_wrtask)
 
                pipe->m_wrtask->state = SCHED_READY;
 
        return 0;
 
}
 
 
 
/*
int     len_syspipe(SYSPIPE *p) {
int     len_syspipe(SYSPIPE *p) {
        return (p->m_head-p->m_tail) & p->m_mask;
        return (p->m_head-p->m_tail) & p->m_mask;
} */
} */
 
 
/* Returns how many empty spaces are in the pipe
/* Returns how many empty spaces are in the pipe
 */
 */
int     num_avail_syspipe(SYSPIPE *p) {
int     num_avail_syspipe(SYSPIPE *p) {
        // if (head+1 == tail)  PIPE is full
        // if (head+1 == tail)  PIPE is full
        //      (mask+tail-tail+1)=mask+1 &mask = 0
        //      (mask+tail-tail+1)=mask+1 &mask = 0
        // if (head == tail) PIPE is empty
        // if (head == tail) PIPE is empty
        //      (mask+tail-tail)=mask & mask = mask
        //      (mask+tail-tail)=mask & mask = mask
        // if (head == tail+2) PIPE has two within it
        // if (head == tail+2) PIPE has two within it
        //      (mask+tail-tail-2)=mask-2 & mask = mask-2
        //      (mask+tail-tail-2)=mask-2 & mask = mask-2
        //
        //
        return (p->m_tail-p->m_head-1) & p->m_mask;
        return (p->m_tail-p->m_head-1) & p->m_mask;
}
}
 
 
// This will be called from a user context.
// This will be called from a user context.
// Another task may write to the pipe during this call.  If the pipe becomes
// Another task may write to the pipe during this call.  If the pipe becomes
// full, that task will block.
// full, that task will block.
//
//
static int      uread_syspipe(TASKP tsk __attribute__((__unused__)), SYSPIPE *p, int *dst, int len) {
static int uread_syspipe(TASKP tsk __attribute__((__unused__)),
 
                SYSPIPE *p, char *dst, int len) {
        int nleft= len, h;
        int nleft= len, h;
        if (len == 0) {
        if (len == 0) {
                // We'll only get here if we were released from within a 
                // We'll only get here if we were released from within a 
                // writing task.
                // writing task.
                return p->m_nread;
                return p->m_nread;
        } else do {
        } else do {
                // We have a valid read request, for a new process.  Continue
                // We have a valid read request, for a new process.  Continue
                // 'reading' until we have fulfilled the request.
                // 'reading' until we have fulfilled the request.
                //
                //
                // We can read from head, just not write to it
                // We can read from head, just not write to it
                // As for the tail pointer -- we own it, no one else can touch
                // As for the tail pointer -- we own it, no one else can touch
                // it.
                // it.
                h = ((volatile SYSPIPE *)p)->m_head;
                h = ((volatile SYSPIPE *)p)->m_head;
                if (h < p->m_tail) {
                if (h < p->m_tail) {
                        // The buffer wraps around the end.  Thus, we first
                        // The buffer wraps around the end.  Thus, we first
                        // read anything between the tail pointer and the end
                        // read anything between the tail pointer and the end
                        int ln1 = p->m_mask+1 - p->m_tail; // Navail to be read
                        int ln1 = p->m_mask+1 - p->m_tail; // Navail to be read
                        ln1 = (ln1 > nleft) ? nleft : ln1;
                        ln1 = (ln1 > nleft) ? nleft : ln1;
                        if (ln1 > 0) {
                        if (ln1 > 0) {
                                register int *src = &p->m_buf[p->m_tail];
                                memcpy(dst, &p->m_buf[p->m_tail], ln1);
                                for(int i=0; i<ln1; i++)
                                dst += ln1;
                                        *dst++ = *src++;
 
 
 
                                p->m_nread += ln1;
                                p->m_nread += ln1;
                                nleft -= ln1;
                                nleft -= ln1;
 
 
                                int nt = p->m_tail+ln1;
                                int nt = p->m_tail+ln1;
                                if ((unsigned)nt > p->m_mask)
                                if ((unsigned)nt > p->m_mask)
                                        nt = 0;
                                        nt = 0;
                                p->m_tail = nt;
                                p->m_tail = nt;
                        }
                        }
 
 
                        // nleft is either zero, or tail
                        // nleft is either zero, or tail
                        if (nleft & -2)
                        if (nleft & -2)
                                exit(nleft);
                                exit(nleft);
                        else if (p->m_nread & -2)
                        else if (p->m_nread & -2)
                                exit(p->m_nread);
                                exit(p->m_nread);
                }
                }
 
 
                // Then repeat with the second half of the buffer, from the
                // Then repeat with the second half of the buffer, from the
                // beginning to the head--unless we've exhausted our buffer.
                // beginning to the head--unless we've exhausted our buffer.
                if (nleft > 0) {
                if (nleft > 0) {
                        // Still need to do more, wrap around our buffer and
                        // Still need to do more, wrap around our buffer and
                        // restart
                        // restart
                        int ln1 = h - p->m_tail;
                        int ln1 = h - p->m_tail;
                        ln1 = (ln1 < nleft) ? ln1 : nleft;
                        ln1 = (ln1 < nleft) ? ln1 : nleft;
 
 
                        int *src = &p->m_buf[p->m_tail];
                        memcpy(dst, &p->m_buf[p->m_tail], ln1);
                        for(int i=0; i<ln1; i++)
                        dst += ln1;
                                *dst++ = *src++;
 
 
 
                        p->m_nread += ln1;
                        p->m_nread += ln1;
                        nleft -= ln1;
                        nleft -= ln1;
                        int nt = p->m_tail+ln1; // nt = new tail value
                        int nt = p->m_tail+ln1; // nt = new tail value
                        if ((unsigned)nt > p->m_mask)
                        if ((unsigned)nt > p->m_mask)
                                nt = 0;
                                nt = 0;
                        p->m_tail = nt;
                        p->m_tail = nt;
 
 
                        if (nleft & -2)
                        if (nleft & -2)
                                exit(nleft);
                                exit(nleft);
                        else if (p->m_nread & -2)
                        else if (p->m_nread & -2)
                                exit(p->m_nread);
                                exit(p->m_nread);
                }
                }
 
 
                if (nleft == 0)
                if (nleft == 0)
                        break;
                        break;
 
 
                // We didn't finish our read, check for a blocked writing
                // We didn't finish our read, check for a blocked writing
                // process to copy directly from.  Note that we don't need
                // process to copy directly from.  Note that we don't need
                // to check the status of the write task--if it is set and
                // to check the status of the write task--if it is set and
                // we are active, then it is blocked and waiting for us to
                // we are active, then it is blocked and waiting for us to
                // complete.  Note also that this is treated as a volatile
                // complete.  Note also that this is treated as a volatile
                // pointer.  It can change from one time through our loop
                // pointer.  It can change from one time through our loop
                // to the next.
                // to the next.
                if (((volatile SYSPIPE *)p)->m_wrtask) {
                if (((volatile SYSPIPE *)p)->m_wrtask) {
                        int     *src, ln;
                        int     ln;
 
                        char    *src;
 
 
                        // If the head changed before the write task blocked,
                        // If the head changed before the write task blocked,
                        // then go around again and copy some more before
                        // then go around again and copy some more before
                        // getting started
                        // getting started
                        //
                        //
                        // This should never happen, however.  If a write task
                        // This should never happen, however.  If a write task
                        // gets assigned while a read task exists, it doesn't
                        // gets assigned while a read task exists, it doesn't
                        // write its values into the buffer, it just waits.
                        // write its values into the buffer, it just waits.
                        // therefore we don't need to check for this.
                        // therefore we don't need to check for this.
                        //
                        //
                        // if (p->m_head != h)
                        // if (p->m_head != h)
                        //      continue;
                        //      continue;
 
 
                        ln = nleft;
                        ln = nleft;
                        if (p->m_wrtask->context[4] < nleft)
                        if (p->m_wrtask->context[4] < nleft)
                                ln = p->m_wrtask->context[4];
                                ln = p->m_wrtask->context[4];
                        src = (int *)p->m_wrtask->context[3];
                        src = (char *)p->m_wrtask->context[3];
 
                        memcpy(dst, src, ln);
                        for(int i=0; i<ln; i++)
                        dst += ln;
                                *dst++ = *src++;
                        src += ln;
 
 
                        p->m_nwritten += ln;
                        p->m_nwritten += ln;
                        p->m_nread    += ln;
                        p->m_nread    += ln;
 
 
                        nleft -= ln;
                        nleft -= ln;
                        p->m_wrtask->context[4] -= ln;
                        p->m_wrtask->context[4] -= ln;
                        p->m_wrtask->context[3]  = (int)src;
                        p->m_wrtask->context[3]  = (int)src;
 
 
                        // We have exhausted the write task.  Release it
                        // We have exhausted the write task.  Release it
                        if (p->m_wrtask->context[4] == 0) { // wr_len == 0
                        if (p->m_wrtask->context[4] == 0) { // wr_len == 0
                                // Release the write task, it has exhausted
                                // Release the write task, it has exhausted
                                // its buffer
                                // its buffer
                                TASKP   w = p->m_wrtask;
                                TASKP   w = p->m_wrtask;
                                // Now we allow other tasks to write into our
                                // Now we allow other tasks to write into our
                                // pipe
                                // pipe
                                p->m_wrtask = 0;
                                p->m_wrtask = 0;
                                // And here we actually release the writing
                                // And here we actually release the writing
                                // task
                                // task
                                w->state = SCHED_READY;
                                w->state = SCHED_READY;
                        }
                        }
                }
                }
 
 
                // Realistically, we need to block here 'till more data is
                // Realistically, we need to block here 'till more data is
                // available.  Need to determine how to do that.  Until then,
                // available.  Need to determine how to do that.  Until then,
                // we'll just tell the scheduler to yield.  This will in
                // we'll just tell the scheduler to yield.  This will in
                // effect create a busy wait--not what we want, but it'll work.
                // effect create a busy wait--not what we want, but it'll work.
                if (nleft > 0) {
                if (nleft > 0) {
                        DISABLE_INTS();
                        DISABLE_INTS();
                        h = ((volatile SYSPIPE *)p)->m_head;
                        h = ((volatile SYSPIPE *)p)->m_head;
                        if (h == p->m_tail)
                        if (h == p->m_tail)
                                wait(0,-1);
                                wait(0,-1);
                        else
                        else
                                ENABLE_INTS();
                                ENABLE_INTS();
                }
                }
        } while(nleft > 0);
        } while(nleft > 0);
 
 
        len = p->m_nread;
        len = p->m_nread;
        p->m_nread = 0;
        p->m_nread = 0;
        // Release our ownership of the read end of the pipe
        // Release our ownership of the read end of the pipe
        DISABLE_INTS();
        DISABLE_INTS();
        p->m_rdtask = NULL;
        p->m_rdtask = NULL;
        if (((volatile SYSPIPE *)p)->m_wrtask)
        if (((volatile SYSPIPE *)p)->m_wrtask)
                p->m_wrtask->state = SCHED_READY;
                p->m_wrtask->state = SCHED_READY;
        ENABLE_INTS();
        ENABLE_INTS();
 
 
        // We have accomplished our read
        // We have accomplished our read
        //
        //
        return len;
        return len;
}
}
 
 
static int      uwrite_syspipe(TASKP tsk __attribute__((__unused__)),
static int      uwrite_syspipe(TASKP tsk __attribute__((__unused__)),
                SYSPIPE *p, int *src, int len) {
                SYSPIPE *p, char *src, int len) {
        int nleft = len;
        int nleft = len;
 
 
        // The kernel guarantees, before we come into here, that we have a 
        // The kernel guarantees, before we come into here, that we have a 
        // valid write request.  
        // valid write request.  
        do {
        do {
                // We try to fill this request without going through the pipes
                // We try to fill this request without going through the pipes
                // memory at all.  Hence, if there is a read task that is
                // memory at all.  Hence, if there is a read task that is
                // waiting/suspended, waiting on a write (this must've happened
                // waiting/suspended, waiting on a write (this must've happened
                // since we started)--write directly into the read buffer first.
                // since we started)--write directly into the read buffer first.
 
 
                // If there is a read task blocked, the pipe must be empty
                // If there is a read task blocked, the pipe must be empty
                TASKP rdtask = ((volatile SYSPIPE *)p)->m_rdtask;
                TASKP rdtask = ((volatile SYSPIPE *)p)->m_rdtask;
                if (rdtask == INTERRUPT_READ_TASK) {
                if (rdtask == INTERRUPT_READ_TASK) {
                        // We need to copy everything to the buffer
                        // We need to copy everything to the buffer
                } else if (rdtask) {
                } else if (rdtask) {
                        int ln = nleft;
                        int ln = nleft;
                        if (ln > p->m_rdtask->context[4])
                        if (ln > p->m_rdtask->context[4])
                                ln = p->m_rdtask->context[4];
                                ln = p->m_rdtask->context[4];
                        int *dst = (int *)p->m_rdtask->context[3];
                        memcpy((char *)p->m_rdtask->context[3], src, ln);
                        for(int i=0; i<ln; i++)
                        src += ln;
                                *dst++ = *src++;
 
                        p->m_nread += ln;
                        p->m_nread += ln;
                        p->m_rdtask->context[3]+= ln;
                        p->m_rdtask->context[3]+= ln;
                        p->m_rdtask->context[4]-= ln;
                        p->m_rdtask->context[4]-= ln;
                        nleft -= ln;
                        nleft -= ln;
                        p->m_nwritten += ln;
                        p->m_nwritten += ln;
 
 
                        // Realistically, we always need to wake up the reader
                        // Realistically, we always need to wake up the reader
                        // at this point.  Either 1) we exhausted the readers
                        // at this point.  Either 1) we exhausted the readers
                        // buffer, or 2) we exhausted our own and the reader
                        // buffer, or 2) we exhausted our own and the reader
                        // needs to take over.  Here, we only handle the first
                        // needs to take over.  Here, we only handle the first
                        // case, leaving the rest for later.
                        // case, leaving the rest for later.
                        if (p->m_rdtask->context[4] == 0) {
                        if (p->m_rdtask->context[4] == 0) {
                                TASKP   r = p->m_rdtask;
                                TASKP   r = p->m_rdtask;
                                // Detach the reader task
                                // Detach the reader task
                                p->m_rdtask = 0;
                                p->m_rdtask = 0;
                                // Wake up the reader
                                // Wake up the reader
                                r->state = SCHED_READY;
                                r->state = SCHED_READY;
                        }
                        }
 
 
                        // While it might appear that we might close our loop
                        // While it might appear that we might close our loop
                        // here, that's not quite the case.  It may be that the
                        // here, that's not quite the case.  It may be that the
                        // pipe is read from an interrupt context.  In that
                        // pipe is read from an interrupt context.  In that
                        // case, there will never be any reader tasks, but we
                        // case, there will never be any reader tasks, but we
                        // will still need to loop.
                        // will still need to loop.
 
 
                        // Now that we've filled any existing reader task, we
                        // Now that we've filled any existing reader task, we
                        // check whether or not we fit into the buffer.  The
                        // check whether or not we fit into the buffer.  The
                        // rule is: don't write into the buffer unless
                        // rule is: don't write into the buffer unless
                        // everything will fit.  Why?  Well, if you have to
                        // everything will fit.  Why?  Well, if you have to
                        // block anyway, why not see if you can't avoid a
                        // block anyway, why not see if you can't avoid a
                        // double copy?
                        // double copy?
                        if (nleft == 0)
                        if (nleft == 0)
                                break;
                                break;
                }
                }
 
 
                // Copy whatever we have into the pipe's buffer
                // Copy whatever we have into the pipe's buffer
                int     navail = num_avail_syspipe(p);
                int     navail = num_avail_syspipe(p);
                if ((nleft <= navail)
                if ((nleft <= navail)
                        ||((rdtask == INTERRUPT_READ_TASK)&&(navail>0))) {
                        ||((rdtask == INTERRUPT_READ_TASK)&&(navail>0))) {
                        // Either there is no immediate reader task, or
                        // Either there is no immediate reader task, or
                        // the reader has been exhausted, but we've go
                        // the reader has been exhausted, but we've go
                        // more to write.
                        // more to write.
                        //
                        //
                        // Note that we no longer need to check what
                        // Note that we no longer need to check what
                        // will fit into the pipe.  We know the entire
                        // will fit into the pipe.  We know the entire
                        // rest of our buffer will fit.
                        // rest of our buffer will fit.
 
 
                        { // Write into the first half of the pipe
                        { // Write into the first half of the pipe
                        // Be careful not to change head until all is written
                        // Be careful not to change head until all is written
                        // so that it remains consistent under interrupt
                        // so that it remains consistent under interrupt
                        // conditions.
                        // conditions.
                                int ln = p->m_mask+1-p->m_head;
                                int ln = p->m_mask+1-p->m_head;
                                int *dst = &p->m_buf[p->m_head];
 
                                if (ln > nleft) ln = nleft;
                                if (ln > nleft) ln = nleft;
                                if (ln > navail) ln = navail;
                                if (ln > navail) ln = navail;
 
 
                                for(int i=0; i<ln; i++)
                                memcpy((void *)&p->m_buf[p->m_head], src, ln);
                                        *dst++ = *src++;
                                src += ln;
 
 
                                p->m_head = (p->m_head+ln)&p->m_mask;
                                p->m_head = (p->m_head+ln)&p->m_mask;
                                nleft -= ln;
                                nleft           -= ln;
                                p->m_nwritten += ln;
                                p->m_nwritten   += ln;
                                navail -= ln;
                                navail          -= ln;
                        }
                        }
 
 
                        /*
 
                        // Write into the rest of the pipe
 
                        if ((0 == p->m_head)&&(nleft>0)&&(navail>0)) {
 
                                int ln = navail;
 
                                if (nleft < ln)
 
                                        ln = nleft;
 
                                int *dst = &p->m_buf[p->m_head];
 
 
 
                                for(int i=0; i<ln; i++)
 
                                        *dst++ = *src++;
 
 
 
                                p->m_head += ln;
 
                                p->m_nwritten += ln;
 
                                nleft -= ln;
 
                        }*/
 
                }
                }
 
 
                if ((nleft > 0)&&(navail == 0)) {
                if ((nleft > 0)&&(navail == 0)) {
                        if (rdtask == INTERRUPT_READ_TASK) {
                        if (rdtask == INTERRUPT_READ_TASK) {
                                DISABLE_INTS();
                                DISABLE_INTS();
                                if (0==num_avail_syspipe(p))
                                if (0==num_avail_syspipe(p))
                                        wait(0,-1);
                                        wait(0,-1);
                                else ENABLE_INTS();
                                else ENABLE_INTS();
                        } else {
                        } else {
                                DISABLE_INTS();
                                DISABLE_INTS();
                                if (!((volatile SYSPIPE *)p)->m_rdtask)
                                if (!((volatile SYSPIPE *)p)->m_rdtask)
                                        wait(0,-1); // Should really be a wait
                                        wait(0,-1); // Should really be a wait
                                        // on JIFFIES and if JIFFIES expired
                                        // on JIFFIES and if JIFFIES expired
                                        // (i.e. write timeout) then break;
                                        // (i.e. write timeout) then break;
                                else ENABLE_INTS();
                                else ENABLE_INTS();
                        }
                        }
                }
                }
        } while(nleft > 0);
        } while(nleft > 0);
 
 
        int     nw= p->m_nwritten;
        int     nw= p->m_nwritten;
        p->m_wrtask = 0;
        p->m_wrtask = 0;
        return nw;
        return nw;
}
}
 
 
// This will be called from a kernel (interrupt) context
// This will be called from a kernel (interrupt) context
void    kread_syspipe(TASKP tsk, int dev, int *dst, int len) {
void    kread_syspipe(TASKP tsk, int dev, char *dst, int len) {
        SYSPIPE *p = (SYSPIPE *)dev;
        SYSPIPE *p = (SYSPIPE *)dev;
        if (p->m_rdtask != NULL) {
        if (p->m_rdtask != NULL) {
                // If the pipe already has a read task, then we fail
                // If the pipe already has a read task, then we fail
                tsk->context[1] = -EBUSY;
                tsk->context[1] = -EBUSY;
                zip_halt();
                zip_halt();
        } else if (p->m_error) {
        } else if (p->m_error) {
                // If there's been an overrun, let the reader know on the
                // If there's been an overrun, let the reader know on the
                // next read--i.e. this one.  Also, clear the error condition
                // next read--i.e. this one.  Also, clear the error condition
                // so that the following read will succeed.
                // so that the following read will succeed.
                tsk->context[1] = -EIO;
                tsk->context[1] = -EIO;
                p->m_tail = p->m_head;
                p->m_tail = p->m_head;
                p->m_error = 0;
                p->m_error = 0;
        } else if (len <= 0) {
        } else if (len <= 0) {
                tsk->context[1] = -EFAULT;
                tsk->context[1] = -EFAULT;
                zip_halt();
                zip_halt();
        } else if (!valid_ram_region(dst, len)) {
        } else if (!valid_ram_region(dst, len)) {
                // Bad parameters
                // Bad parameters
                tsk->context[1] = -EFAULT;
                tsk->context[1] = -EFAULT;
                zip_halt();
                zip_halt();
        } else {
        } else {
                // Take  ownership of the read end of the pipe
                // Take  ownership of the read end of the pipe
                p->m_rdtask = tsk;
                p->m_rdtask = tsk;
                p->m_nread  = 0;
                p->m_nread  = 0;
                tsk->context[1] = (int)tsk;
                tsk->context[1] = (int)tsk;
                tsk->context[2] = (int)p;
                tsk->context[2] = (int)p;
                // These are  already set, else we'd set them again
                // These are  already set, else we'd set them again
                // tsk->context[3] = (int)dst;
                // tsk->context[3] = (int)dst;
                // tsk->context[4] = len;
                // tsk->context[4] = len;
                tsk->context[15] = (int)uread_syspipe;
                tsk->context[15] = (int)uread_syspipe;
 
 
                // If there is already a write task, make sure it is awake
                // If there is already a write task, make sure it is awake
                if (p->m_wrtask) {
                if (p->m_wrtask) {
                        tsk->state = SCHED_WAITING;
                        tsk->state = SCHED_WAITING;
                        p->m_wrtask->state = SCHED_READY;
                        p->m_wrtask->state = SCHED_READY;
                } else if (p->m_head == p->m_tail)
                } else if (p->m_head == p->m_tail)
                        // If the pipe is empty, block the read task
                        // If the pipe is empty, block the read task
                        tsk->state = SCHED_WAITING;
                        tsk->state = SCHED_WAITING;
 
 
                // On return, this will bring us back to user space, inside our
                // On return, this will bring us back to user space, inside our
                // user space version of the read system call
                // user space version of the read system call
        }
        }
}
}
 
 
void    kwrite_syspipe(TASKP tsk, int dev, int *src, int len) {
void    kwrite_syspipe(TASKP tsk, int dev, char *src, int len) {
        SYSPIPE *p = (SYSPIPE *)dev;
        SYSPIPE *p = (SYSPIPE *)dev;
        if (p->m_wrtask != NULL) {
        if (p->m_wrtask != NULL) {
                // If the pipe already has a write task, then we fail
                // If the pipe already has a write task, then we fail
                tsk->context[1] = -EBUSY;
                tsk->context[1] = -EBUSY;
        } else if (len <= 0) {
        } else if (len <= 0) {
                tsk->context[1] = -EFAULT;
                tsk->context[1] = -EFAULT;
        } else if (!valid_mem_region(src, len)) {
        } else if (!valid_mem_region(src, len)) {
                // Bad parameters
                // Bad parameters
                tsk->context[1] = -EFAULT;
                tsk->context[1] = -EFAULT;
                zip_halt();
                zip_halt();
        } else {
        } else {
                // Take  ownership of the write end of the pipe
                // Take  ownership of the write end of the pipe
                p->m_wrtask    = tsk;
                p->m_wrtask    = tsk;
                p->m_nwritten = 0;
                p->m_nwritten = 0;
                tsk->context[1] = (int)tsk;
                tsk->context[1] = (int)tsk;
                tsk->context[2] = (int)p;
                tsk->context[2] = (int)p;
                // These are  already set, else we'd set them again
                // These are  already set, else we'd set them again
                // tsk->context[3] = (int)src;
                // tsk->context[3] = (int)src;
                // tsk->context[4] = len;
                // tsk->context[4] = len;
                tsk->context[15] = (int)uwrite_syspipe;
                tsk->context[15] = (int)uwrite_syspipe;
 
 
                // If a reader task currently exists, then block until that
                // If a reader task currently exists, then block until that
                // task either finishes or releases us
                // task either finishes or releases us
                if ((p->m_rdtask)&&(p->m_rdtask != INTERRUPT_READ_TASK)) {
                if ((p->m_rdtask)&&(p->m_rdtask != INTERRUPT_READ_TASK)) {
                        tsk->state = SCHED_WAITING;
                        tsk->state = SCHED_WAITING;
                        p->m_rdtask->state = SCHED_READY;
                        p->m_rdtask->state = SCHED_READY;
                } else if (((p->m_head+1)&p->m_mask) == (unsigned)p->m_tail)
                } else if (((p->m_head+1)&p->m_mask) == (unsigned)p->m_tail)
                        // If the pipe is empty, block until there's data
                        // If the pipe is empty, block until there's data
                        tsk->state = SCHED_WAITING;
                        tsk->state = SCHED_WAITING;
 
 
                // On return, this will bring us back to user space, in our
                // On return, this will bring us back to user space, in our
                // user space write call
                // user space write call
        }
        }
}
}
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.