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

Subversion Repositories s6soc

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

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

Rev 22 Rev 27
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//
//
// 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"
 
 
#ifndef NULL
#ifndef NULL
#define NULL    (void *)0
#define NULL    (void *)0
#endif
#endif
 
 
static  void    clear_syspipe(SYSPIPE *p) {
 
        p->m_head  = 0;
 
        p->m_tail  = 0;
 
        p->m_error = 0;
 
 
 
        for(int i=0; i<=(int)p->m_mask; i++)
 
                p->m_buf[i] = 0;
 
 
 
        if ((p->m_rdtask)&&(p->m_rdtask != INTERRUPT_READ_TASK)) {
 
                p->m_rdtask->context[1] = p->m_nread;
 
                if (p->m_nread == 0)
 
                        p->m_rdtask->errno = -EFAULT;
 
                p->m_rdtask->state = SCHED_READY;
 
        } else if (p->m_wrtask) {
 
                p->m_wrtask->context[1] = p->m_nwritten;
 
                if (p->m_nwritten == 0)
 
                        p->m_wrtask->errno = -EFAULT;
 
                p->m_wrtask->state = SCHED_READY;
 
        }
 
 
 
        if (p->m_rdtask != INTERRUPT_READ_TASK)
 
                p->m_rdtask   = 0;
 
        p->m_wrtask   = 0;
 
        p->m_nread    = 0;
 
        p->m_nwritten = 0;
 
}
 
 
 
void    kpush_syspipe(SYSPIPE *pipe, int val) {
void    kpush_syspipe(SYSPIPE *pipe, int 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;
}
}
 
 
void    txchr(char v) {
extern  void    pipe_panic(SYSPIPE *p);
        volatile IOSPACE        *sys = (IOSPACE *)IOADDR;
 
        if (v < 10)
 
                return;
 
        v &= 0x0ff;
 
        sys->io_pic = INT_UARTTX;
 
        while((sys->io_pic&INT_UARTTX)==0)
 
                ;
 
        sys->io_uart = v;
 
}
 
 
 
void    txstr(const char *str) {
 
        const char *ptr = str;
 
        while(*ptr) {
 
                txchr(*ptr++);
 
        }
 
}
 
 
 
void    txhex(int num) {
 
        for(int ds=28; ds>=0; ds-=4) {
 
                int     ch;
 
                ch = (num>>ds)&0x0f;
 
                if (ch >= 10)
 
                        ch = 'A'+ch-10;
 
                else
 
                        ch += '0';
 
                txchr(ch);
 
        } txstr("\r\n");
 
}
 
 
 
void    pipe_panic(SYSPIPE *pipe) {
 
        extern void     kpanic(void);
 
        volatile IOSPACE        *sys = (IOSPACE *)IOADDR;
 
 
 
        sys->io_spio = 0x0fa;
 
 
 
        txstr("SYSPIPE PANIC!\r\n");
 
        txstr("ADDR: "); txhex((int)pipe);
 
        txstr("MASK: "); txhex(pipe->m_mask);
 
        txstr("HEAD: "); txhex(pipe->m_head);
 
        txstr("TAIL: "); txhex(pipe->m_tail);
 
        kpanic();
 
}
 
 
 
int     kpop_syspipe(SYSPIPE *pipe, int *vl) {
int     kpop_syspipe(SYSPIPE *pipe, int *vl) {
        if (pipe->m_head != pipe->m_tail) {
        if (pipe->m_head != pipe->m_tail) {
                *vl = pipe->m_buf[pipe->m_tail];
                *vl = pipe->m_buf[pipe->m_tail];
                pipe->m_tail++;
                pipe->m_tail = (pipe->m_tail+1)&pipe->m_mask;
                if ((unsigned)pipe->m_tail > pipe->m_mask)
 
                        pipe->m_tail = 0;
 
                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
SYSPIPE *new_syspipe(const unsigned int len) {
 
        unsigned        msk;
 
 
 
        for(msk=2; msk<len; msk<<=1)
 
                ;
 
        SYSPIPE *pipe = sys_malloc(sizeof(SYSPIPE)-1+msk);
 
        pipe->m_mask = msk-1;
 
        pipe->m_rdtask = pipe->m_wrtask = 0;
 
        clear_syspipe(pipe);
 
        return pipe;
 
}
}
 
 
int     len_syspipe(SYSPIPE *p) {
/* Returns how many values are in the pipe
        return (p->m_head-p->m_tail) & p->m_mask;
 */
}
/* Of course ... if it's not used, why include it?
 
int     len_syspipe(SYSPIPE *p) {
 
        return (p->m_head-p->m_tail) & p->m_mask;
 
} */
 
/* Returns how many empty spaces are in the pipe
 
 */
int     num_avail_syspipe(SYSPIPE *p) {
int     num_avail_syspipe(SYSPIPE *p) {
        return (p->m_mask + p->m_tail-p->m_head) & p->m_mask;
        // if (head+1 == tail)  PIPE is full
 
        //      (mask+tail-tail+1)=mask+1 &mask = 0
 
        // if (head == tail) PIPE is empty
 
        //      (mask+tail-tail)=mask & mask = mask
 
        // if (head == tail+2) PIPE has two within it
 
        //      (mask+tail-tail-2)=mask-2 & mask = mask-2
 
        //
 
        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, int *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];
                                register int *src = &p->m_buf[p->m_tail];
                                for(int i=0; i<ln1; i++)
                                for(int i=0; i<ln1; i++)
                                        *dst++ = *src++;
                                        *dst++ = *src++;
 
 
                                p->m_nread += ln1;
                                p->m_nread += ln1;
                                nleft -= ln1;
                                nleft -= ln1;
                                p->m_tail += ln1;
 
                                if ((unsigned)p->m_tail > p->m_mask)
                                int nt = p->m_tail+ln1;
                                        p->m_tail = 0;
                                if ((unsigned)nt > p->m_mask)
 
                                        nt = 0;
 
                                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];
                        int *src = &p->m_buf[p->m_tail];
                        for(int i=0; i<ln1; i++)
                        for(int i=0; i<ln1; i++)
                                *dst++ = *src++;
                                *dst++ = *src++;
 
 
                        p->m_nread += ln1;
                        p->m_nread += ln1;
                        nleft -= ln1;
                        nleft -= ln1;
                        p->m_tail += ln1;
                        int nt = p->m_tail+ln1; // nt = new tail value
                        if (p->m_tail == (int)p->m_mask+1)
                        if ((unsigned)nt > p->m_mask)
                                p->m_tail = 0;
                                nt = 0;
 
                        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     *src, ln;
 
 
                        // 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 = (int *)p->m_wrtask->context[3];
 
 
                        for(int i=0; i<ln; i++)
                        for(int i=0; i<ln; i++)
                                *dst++ = *src++;
                                *dst++ = *src++;
 
 
                        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__)), SYSPIPE *p, int *src, int len) {
static int      uwrite_syspipe(TASKP tsk __attribute__((__unused__)),
 
                SYSPIPE *p, int *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) {
// #warning "The previous code should have worked"
 
                // if (((unsigned)rdtask+1) & -2)
 
                        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];
                        int *dst = (int *)p->m_rdtask->context[3];
                        for(int i=0; i<ln; i++)
                        for(int i=0; i<ln; i++)
                                *dst++ = *src++;
                                *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
                if ((nleft <= num_avail_syspipe(p))||(rdtask == INTERRUPT_READ_TASK)) {
                int     navail = num_avail_syspipe(p);
 
                if ((nleft <= navail)
 
                        ||((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
 
                        // so that it remains consistent under interrupt
 
                        // 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];
                                int *dst = &p->m_buf[p->m_head];
                                if (ln > nleft) ln = nleft;
                                if (ln > nleft) ln = nleft;
 
                                if (ln > navail) ln = navail;
 
 
                                for(int i=0; i<ln; i++)
                                for(int i=0; i<ln; i++)
                                        *dst++ = *src++;
                                        *dst++ = *src++;
 
 
                                p->m_head += ln;
                                p->m_head = (p->m_head+ln)&p->m_mask;
                                nleft -= ln;
                                nleft -= ln;
                                p->m_nwritten += ln;
                                p->m_nwritten += ln;
                                if (p->m_head > (int)p->m_mask)
                                navail -= ln;
                                        p->m_head = 0;
 
                        }
                        }
 
 
                        // Write into the rest of the pipe
                        /*
                        if (nleft > 0) {
                        // Write into the rest of the pipe
                                int ln = num_avail_syspipe(p);
                        if ((0 == p->m_head)&&(nleft>0)&&(navail>0)) {
                                if (nleft < ln)
                                int ln = navail;
                                        ln = nleft;
                                if (nleft < ln)
                                int *dst = &p->m_buf[p->m_head];
                                        ln = nleft;
 
                                int *dst = &p->m_buf[p->m_head];
 
 
                                for(int i=0; i<ln; i++)
                                for(int i=0; i<ln; i++)
                                        *dst++ = *src++;
                                        *dst++ = *src++;
 
 
                                p->m_head += ln;
                                p->m_head += ln;
                                p->m_nwritten += ln;
                                p->m_nwritten += ln;
                                nleft -= ln;
                                nleft -= ln;
                        }
                        }*/
                }
                }
 
 
                if (nleft > 0) {
                if ((nleft > 0)&&(navail == 0)) {
                        if (rdtask == INTERRUPT_READ_TASK) {
                        if (rdtask == INTERRUPT_READ_TASK) {
                                DISABLE_INTS();
                                DISABLE_INTS();
                                if (num_avail_syspipe(p)==0)
                                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, int *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, int *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.