arg_t _connect(void) { uint8_t flag; struct socket *s = sock_get(fd, &flag); struct sockaddr_in sin; if (s == NULL) return -1; if (s->s_state == SS_CONNECTING) { udata.u_error = EALREADY; return -1; } if (s->s_state == SS_UNCONNECTED && sock_autobind(s)) return -1; if (s->s_state == SS_BOUND) { if (sa_getremote(uaddr, &sin) == -1) return -1; s->s_addr[SADDR_DST].addr = sin.sin_addr.s_addr; s->s_addr[SADDR_DST].port = sin.sin_port; s->s_state = SS_CONNECTING; /* Protocol op to kick off */ } do { /* FIXME: return EINPROGRESS not EINTR for SS_CONNECTING */ if (psleep_flags(s, flag)) return -1; /* Protocol state check */ } while (s->s_state == SS_CONNECTING); return sock_error(s); }
int tty_read(uint8_t minor, uint8_t rawflag, uint8_t flag) { uint16_t nread; unsigned char c; struct s_queue *q; struct termios *t; rawflag; flag; // shut up compiler /* Minor == 0 means that it is the controlling tty of the process */ if (!minor) minor = udata.u_ptab->p_tty; if (!udata.u_ptab->p_tty) udata.u_ptab->p_tty = minor; q = &ttyinq[minor]; t = &ttydata[minor]; nread = 0; while (nread < udata.u_count) { for (;;) { if (deadflag[minor]) { udata.u_error = ENXIO; return -1; } if (remq(q, &c)) { if (udata.u_sysio) *udata.u_base = c; else uputc(c, udata.u_base); break; } if (psleep_flags(q, flag)) return -1; } ++nread; /* return according to mode */ if (!(t->c_lflag & ICANON)) { if (nread >= t->c_cc[VMIN]) break; } else { if (nread == 1 && (c == t->c_cc[VEOF])) { /* ^D */ nread = 0; break; } if (c == '\n') break; } ++udata.u_base; } wakeup(&q->q_count); return nread; }
/* Wait to enter a state. This will eventually need interrupt locking etc */ static int sock_wait_enter(struct socket *s, uint8_t flag, uint8_t state) { irqflags_t irq; irq = di(); while (s->s_state != state) { if (psleep_flags(s, flag)) { irqrestore(irq); return -1; } } irqrestore(irq); return 0; }
int tty_write(uint8_t minor, uint8_t rawflag, uint8_t flag) { struct termios *t; int towrite; uint8_t c; rawflag; flag; // shut up compiler /* Minor == 0 means that it is the controlling tty of the process */ if (!minor) minor = udata.u_ptab->p_tty; if (!udata.u_ptab->p_tty) udata.u_ptab->p_tty = minor; t = &ttydata[minor]; towrite = udata.u_count; while (udata.u_count-- != 0) { for (;;) { /* Wait on the ^S/^Q flag */ if (deadflag[minor]) { udata.u_error = ENXIO; return -1; } if (!stopflag[minor]) break; if (psleep_flags(&stopflag[minor], flag)) return -1; } if (!flshflag[minor]) { if (udata.u_sysio) c = *udata.u_base; else c = ugetc(udata.u_base); if (t->c_oflag & OPOST) { if (c == '\n' && (t->c_oflag & ONLCR)) tty_putc_wait(minor, '\r'); if (c == '\r' && (t->c_oflag & OCRNL)) c = '\n'; } tty_putc_wait(minor, c); } ++udata.u_base; } return towrite; }
int tty_open(uint8_t minor, uint16_t flag) { struct termios *t; /* FIXME : open/carrier logic is needed here, definitely before we enable ptys */ /* Minor == 0 means that it is the controlling tty of the process */ /* FIXME: need to propogate this minor change back into the file handle and inode somehow ??? */ if (!minor) minor = udata.u_ptab->p_tty; if (minor < 1 || minor > NUM_DEV_TTY + 1) { udata.u_error = ENODEV; return (-1); } /* Hung up but not yet cleared of users */ if (deadflag[minor]) { udata.u_error = ENXIO; return -1; } t = &ttydata[minor]; /* If there is no controlling tty for the process, establish it */ if (!udata.u_ptab->p_tty && !(flag & O_NOCTTY)) { udata.u_ptab->p_tty = minor; tty_pgrp[minor] = udata.u_ptab->p_pgrp; } tty_setup(minor); if ((t->c_cflag & CLOCAL) || (flag & O_NDELAY)) return 0; if (!tty_carrier(minor)) { if (psleep_flags(&t->c_cflag, flag)) return -1; } /* Carrier spiked ? */ if (deadflag[minor]) { udata.u_error = ENXIO; deadflag[minor] = 0; return -1; } return 0; }
int pty_read(uint8_t minor, uint8_t rawflag, uint8_t flag) { struct s_queue q = &ttyinq[minor + PTY_OFFSET + PTY_PAIR]; char c; while (nread < udata.u_count) { if (remq(q, &c)) { if (udata.u_sysio) *udata.u_base = c; else uputc(c, udata.u_base); udata.u_base++; nread++; continue; } if (nread == 0 && psleep_flags(q, flag)) return -1; } return nread; }
int pty_write(uint8_t minor, uint8_t rawflag, uint8_t flag) { uint16_t nwritten; minor += PTY_OFFSET; while (nwritten < udata.u_count) { if (udata.u_sysio) c = udata.u_base; else c = ugetc(udata.u_base); if (tty_inproc(minor, c)) { nwritten++; udata.u_count++; continue; } if (nwritten == 0 && psleep_flags(&ttyinq[minor].q_count, flag)) return -1; } return nwritten; }
int tty_open(uint8_t minor, uint16_t flag) { struct tty *t; if (minor > NUM_DEV_TTY) { udata.u_error = ENODEV; return -1; } t = &ttydata[minor]; /* Hung up but not yet cleared of users */ if (t->flag & TTYF_DEAD) { udata.u_error = ENXIO; return -1; } if (t->users) { t->users++; return 0; } tty_setup(minor); if ((t->termios.c_cflag & CLOCAL) || (flag & O_NDELAY)) goto out; /* FIXME: racy - need to handle IRQ driven carrier events safely */ if (!tty_carrier(minor)) { if (psleep_flags(&t->termios.c_cflag, flag)) return -1; } /* Carrier spiked ? */ if (t->flag & TTYF_DEAD) { udata.u_error = ENXIO; t->flag &= ~TTYF_DEAD; return -1; } out: t->users++; return 0; }
arg_t net_read(struct socket *s, uint8_t flag) { uint16_t n = 0; while(1) { if (s->s_state < SS_CONNECTED) { udata.u_error = EINVAL; return -1; } while(netat_ready() && n < udata.u_count) { uputc(netat_byte(), udata.u_base++); n++; } if (n) return n; s->s_iflag &= ~SI_DATA; netat_wake(); /* Could do with using timeouts here to be clever for non O_NDELAY so we aggregate data. For now assume a fifo */ if (psleep_flags(&s->s_iflag, flag)) return -1; } }
arg_t net_read(struct socket *s, uint8_t flag) { uint16_t n = 0xFFFF; uint16_t r; uint16_t i = sock2wiz_map[s - sockets]; uint8_t st; i <<= 8; /* FIXME: IRQ protection */ /* Wait for data - push int core code ? */ while (1) { /* See if we have lost the link */ if (s->s_state < SS_CONNECTED) { udata.u_error = EINVAL; return -1; } /* Check for an EOF (covers post close cases too) */ if (s->s_iflag & SI_EOF) return 0; /* Keep waiting until we get the right state */ /* Bytes available */ n = w5100_readw(Sn_RX_RSR + i); if (n) { s->s_iflag |= SI_DATA; break; } st = w5100_readb(Sn_SR); if (st >= SOCK_CLOSING && st <= SOCK_UDP) return 0; /* Need IRQ protection to avoid sleep race */ if (psleep_flags(&s->s_iflag, flag)) return -1; } switch (s->s_type) { case SOCKTYPE_RAW: case SOCKTYPE_UDP: /* UDP comes with a header */ w5100_dequeue(i, 4, (uint8_t *) & s->s_addr[SADDR_TMP].addr); if (s->s_type == SOCKTYPE_UDP) w5100_dequeue(i, 2, (uint8_t *) & s->s_addr[SADDR_TMP]. port); w5100_dequeue(i, 2, (uint8_t *) & n); /* Actual packet size */ n = ntohs(n); /* Big endian on device */ /* Fall through */ case SOCKTYPE_TCP: /* Bytes to consume */ r = min(n, udata.u_count); /* Now dequeue some bytes into udata.u_base */ w5100_dequeue_u(i, r, udata.u_base); /* For datagrams we always discard the entire frame */ if (s->s_type == SOCKTYPE_UDP) r = n + 8; w5100_writew(Sn_RX_RD0 + i, w5100_readw(Sn_RX_RD0 + i) + r); /* FIXME: figure out if SI_DATA should be cleared */ /* Now tell the device we ate the data */ w5100_writeb(Sn_CR, RECV); } return r; }
arg_t _flock(void) { inoptr ino; struct oft *o; staticfast uint8_t c; staticfast uint8_t lock; staticfast int self; lock = lockop & ~LOCK_NB; self = 0; if (lock > LOCK_UN) { udata.u_error = EINVAL; return -1; } if ((ino = getinode(file)) == NULLINODE) return -1; o = &of_tab[udata.u_files[file]]; c = ino->c_flags & CFLOCK; /* Upgrades and downgrades. Check if we are in fact doing a no-op */ if (o->o_access & O_FLOCK) { self = 1; /* Shared or exclusive to shared can't block and is easy */ if (lock == LOCK_SH) { if (c == CFLEX) c = 1; goto done; } /* Exclusive to exclusive - no op */ if (c == CFLEX && lock == LOCK_EX) return 0; /* Shared to exclusive - handle via the loop */ } /* Unlock - drop the locks, mark us not a lock holder. Doesn't block */ if (lockop == LOCK_UN) { o->o_access &= ~O_FLOCK; deflock(o); return 0; } do { /* Exclusive lock must have no holders */ if (c == self && lock == LOCK_EX) { c = CFLEX; goto done; } if (c < CFMAX) { c++; goto done; } if (c == CFMAX) { udata.u_error = ENOLCK; return -1; } /* LOCK_NB is defined as O_NDELAY... */ if (psleep_flags(&ino->c_flags, (lockop & LOCK_NB))) return -1; /* locks will hopefully have changed .. */ c = ino->c_flags & CFLOCK; } while (1); done: if (o->o_access & O_FLOCK) deflock(o); ino->c_flags &= ~CFLOCK; ino->c_flags |= c; o->o_access |= O_FLOCK; wakeup(&ino->c_flags); return 0; }