Logo Search packages:      
Sourcecode: aboot version File versions  Download package

cons.c

#include <alloca.h>

#include <linux/kernel.h>
#include <linux/string.h>

#include <asm/console.h>
#include <asm/hwrpb.h>
#include <asm/system.h>

#include <aboot.h>
#include <cons.h>
#include <utils.h>

long cons_dev;                /* console device */
extern long int dispatch();   /* Need the full 64 bit return here...*/

long
cons_puts(const char *str, long len)
{
      long remaining, written;
      union ccb_stsdef {
            long int l_sts;
            struct {
                  int written;
                  unsigned discard : 29;
                  unsigned v_sts0  : 1;
                  unsigned v_sts1  : 1;
                  unsigned v_err   : 1;
            } s;
      } ccb_sts;
      
      for (remaining = len; remaining; remaining -= written) {
            ccb_sts.l_sts = dispatch(CCB_PUTS, cons_dev, str, remaining);
            if (!ccb_sts.s.v_err) {
                  written = ccb_sts.s.written;
                  str += written;
            } else {
                  if (ccb_sts.s.v_sts1)
                        halt();           /* This is a hard error */
                  written = 0;
            }
      }
      return len;
}

void
cons_putchar(char c)
{
      char buf[2];

      buf[0] = c;
      buf[1] = 0;
      cons_puts(buf,1);
}

int
cons_getchar(void)
{
      long c;

      while ((c = dispatch(CCB_GETC, cons_dev)) < 0)
            ;
      return c;
}


long
cons_getenv(long index, char *envval, long maxlen)
{
      /*
       * This may seem silly, but some SRM implementations have
       * problems returning values to buffers that are not 8 byte
       * aligned.  We work around this by always using a buffer
       * allocated on the stack (which guaranteed to by 8 byte
       * aligned).
       */
      char * tmp = alloca(maxlen);
      long len;

      len = dispatch(CCB_GET_ENV, index, tmp, maxlen - 1);
      if (len >= 0) {
            memcpy(envval, tmp, len);
            envval[len] = '\0';
      }
      return len;
}


long
cons_open(const char *devname)
{
      return dispatch(CCB_OPEN, devname, strlen(devname));
}


long
cons_close(long dev)
{
      return dispatch(CCB_CLOSE, dev);
}


long
cons_read(long dev, void *buf, long count, long offset)
{
      static char readbuf[SECT_SIZE];           /* minimize frame size */

      if ((count & (SECT_SIZE-1)) == 0 && (offset & (SECT_SIZE-1)) == 0) {
            /* I/O is aligned... this is easy! */
            return dispatch(CCB_READ, dev, count, buf,
                        offset / SECT_SIZE);
      } else {
            long bytesleft, iocount, blockoffset, iosize, lbn, retval;

            bytesleft = count;
            iocount = 0;
            blockoffset = offset % SECT_SIZE;
            lbn = offset / SECT_SIZE;

            while (bytesleft > 0) {
                  if ((blockoffset == 0) && (bytesleft >= SECT_SIZE)) {
                        /*
                         * This portion of the I/O is aligned,
                         * so read it straight in:
                         */
                        iosize = SECT_SIZE;
                        retval = dispatch(CCB_READ, dev, iosize, buf,
                                      lbn);
                        if (retval != iosize) {
                              printf("read error 0x%lx\n",retval);
                              return -1;
                        }
                  } else {
                        /*
                         * Not aligned; must read it into a
                         * temporary buffer and go from there.
                         */
                        retval = dispatch(CCB_READ, dev, SECT_SIZE,
                                      readbuf, lbn);
                        if (retval != SECT_SIZE) {
                              printf("read error, lbn %ld: 0x%lx\n",
                                     lbn, retval);
                              return -1;
                        }
                        iosize = bytesleft;
                        if (blockoffset + iosize >= SECT_SIZE) {
                              iosize = SECT_SIZE - blockoffset;
                        }
                        memcpy(buf, readbuf + blockoffset, iosize);
                  }
                  buf += iosize;
                  iocount += iosize;
                  bytesleft -= iosize;
                  blockoffset = 0;
                  ++lbn;
            }
            return iocount;
      }
}


void
cons_init(void)
{
      char envval[256];

      if (cons_getenv(ENV_TTY_DEV, envval, sizeof(envval)) < 0) {
            halt();           /* better than random crash */
      }
      cons_dev = simple_strtoul(envval, 0, 10);
}

Generated by  Doxygen 1.6.0   Back to index