File: [local] / sys / arch / mvmeppc / stand / libsa / tftpfs.c (download)
Revision 1.1.1.1 (vendor branch), Tue Mar 4 16:07:45 2008 UTC (16 years, 6 months ago) by nbrk
Branch: OPENBSD_4_2_BASE, MAIN
CVS Tags: jornada-partial-support-wip, HEAD Changes since 1.1: +0 -0 lines
Import of OpenBSD 4.2 release kernel tree with initial code to support
Jornada 720/728, StrongARM 1110-based handheld PC.
At this point kernel roots on NFS and boots into vfs_mountroot() and traps.
What is supported:
- glass console, Jornada framebuffer (jfb) works in 16bpp direct color mode
(needs some palette tweaks for non black/white/blue colors, i think)
- saic, SA11x0 interrupt controller (needs cleanup)
- sacom, SA11x0 UART (supported only as boot console for now)
- SA11x0 GPIO controller fully supported (but can't handle multiple interrupt
handlers on one gpio pin)
- sassp, SSP port on SA11x0 that attaches spibus
- Jornada microcontroller (jmcu) to control kbd, battery, etc throught
the SPI bus (wskbd attaches on jmcu, but not tested)
- tod functions seem work
- initial code for SA-1111 (chip companion) : this is TODO
Next important steps, i think:
- gpio and intc on sa1111
- pcmcia support for sa11x0 (and sa1111 help logic)
- REAL root on nfs when we have PCMCIA support (we may use any of supported pccard NICs)
- root on wd0! (using already supported PCMCIA-ATA)
|
/* $OpenBSD: tftpfs.c,v 1.4 2006/08/13 23:08:44 miod Exp $ */
/*-
* Copyright (c) 2001 Steve Murphree, Jr.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by TooLs GmbH.
* 4. The name of TooLs GmbH may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* TFTP file system.
*/
#include <sys/param.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <ufs/ffs/fs.h>
#include <lib/libkern/libkern.h>
#include "stand.h"
/*
* In-core open file.
*/
struct tftp_file {
char filename[128];
off_t f_seekp; /* seek pointer */
char *f_buf; /* buffer for data block */
off_t f_off; /* index into buffer for data block */
daddr_t f_buf_blkno; /* block number of data block */
size_t f_buf_size;
};
#define TFTP_BLOCK_SHIFT 9
#define TFTP_BLOCK_SIZE (1<<TFTP_BLOCK_SHIFT) /* 512 by tftp convention */
#define TFTP_BLOCK_NO(x) ((x >> TFTP_BLOCK_SHIFT) + 1)
#define TFTP_BLOCK_OFF(x) (x % TFTP_BLOCK_SIZE)
static int read_inode(ino_t, struct open_file *);
static int block_map(struct open_file *, daddr_t, daddr_t *);
static int tftp_read_file(struct open_file *, char **, size_t *);
/*
* Read a portion of a file into an internal buffer. Return
* the location in the buffer and the amount in the buffer.
*/
char tftp_buf[TFTP_BLOCK_SIZE]; /* static */
struct tftp_file tftp_ctrl;
static int
tftp_read_file(f, buf_p, size_p)
struct open_file *f;
char **buf_p; /* out */
size_t *size_p; /* out */
{
register struct tftp_file *fp = (struct tftp_file *)f->f_fsdata;
long off;
register daddr_t file_block;
size_t block_size;
int i, rc;
off = TFTP_BLOCK_OFF(fp->f_seekp);
file_block = TFTP_BLOCK_NO(fp->f_seekp);
block_size = TFTP_BLOCK_SIZE;
if (file_block == fp->f_buf_blkno + 1) {
/*
* Normal, incremental block transfer.
*/
rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
file_block, block_size, fp->f_buf, &fp->f_buf_size);
if (rc)
return (rc);
if (!(file_block % 4)) /* twiddle every 4 blocks */
twiddle();
fp->f_buf_blkno = file_block;
} else if (file_block > fp->f_buf_blkno + 1) {
/*
* Read ahead to the requested block; If we need
* those we skipped, see below.
*/
for (i = (fp->f_buf_blkno + 1); i <= file_block; i++) {
rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
i, block_size, fp->f_buf, &fp->f_buf_size);
if (rc)
return (rc);
}
fp->f_buf_blkno = file_block;
} else if (file_block < fp->f_buf_blkno) {
/*
* Uh oh... We can't rewind. Reopen the file
* and start again.
*/
char filename[64];
strlcpy(filename, fp->filename, sizeof filename);
tftpfs_close(f);
tftpfs_open(filename, f);
for (i = 1; i <= file_block; i++) {
rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
i, block_size, fp->f_buf, &fp->f_buf_size);
if (rc)
return (rc);
}
fp->f_buf_blkno = file_block;
}
/*
* Return address of byte in buffer corresponding to
* offset, and size of remainder of buffer after that
* byte.
*/
*buf_p = fp->f_buf + off;
*size_p = fp->f_buf_size - off;
/*
* But truncate buffer at end of file.
*/
if (fp->f_buf_size > block_size){
twiddle();
return(EIO);
}
return (0);
}
/*
* Open a file.
*/
int
tftpfs_open(path, f)
char *path;
struct open_file *f;
{
struct tftp_file *fp;
int rc = 0;
/* locate file system specific data structure and zero it.*/
fp = &tftp_ctrl;
bzero(fp, sizeof(struct tftp_file));
f->f_fsdata = (void *)fp;
fp->f_seekp = 0;
fp->f_buf = tftp_buf;
bzero(fp->f_buf, TFTP_BLOCK_SIZE);
fp->f_buf_size = 0;
strlcpy(fp->filename, path, sizeof fp->filename);
if (f->f_dev->dv_open == NULL) {
panic("No device open()!");
}
twiddle();
rc = (f->f_dev->dv_open)(f, path);
return (rc);
}
int
tftpfs_close(f)
struct open_file *f;
{
register struct tftp_file *fp = (struct tftp_file *)f->f_fsdata;
fp->f_buf = (void *)0;
f->f_fsdata = (void *)0;
(f->f_dev->dv_close)(f);
return (0);
}
/*
* Copy a portion of a file into kernel memory.
* Cross block boundaries when necessary.
*/
int
tftpfs_read(f, start, size, resid)
struct open_file *f;
void *start;
size_t size;
size_t *resid; /* out */
{
register struct tftp_file *fp = (struct tftp_file *)f->f_fsdata;
register size_t csize;
char *buf;
size_t buf_size;
int rc = 0;
register char *addr = start;
while (size != 0) {
rc = tftp_read_file(f, &buf, &buf_size);
if (rc)
break;
csize = size;
if (csize > buf_size)
csize = buf_size;
bcopy(buf, addr, csize);
fp->f_seekp += csize;
addr += csize;
size -= csize;
}
if (resid)
*resid = size;
return (rc);
}
/*
* Not implemented.
*/
int
tftpfs_write(f, start, size, resid)
struct open_file *f;
void *start;
size_t size;
size_t *resid; /* out */
{
return (EROFS);
}
/*
* We only see forward. We can't rewind.
*/
off_t
tftpfs_seek(f, offset, where)
struct open_file *f;
off_t offset;
int where;
{
register struct tftp_file *fp = (struct tftp_file *)f->f_fsdata;
switch (where) {
case SEEK_SET:
fp->f_seekp = offset;
break;
case SEEK_CUR:
fp->f_seekp += offset;
break;
case SEEK_END:
errno = EIO;
return (-1);
break;
default:
return (-1);
}
return (fp->f_seekp);
}
int
tftpfs_stat(f, sb)
struct open_file *f;
struct stat *sb;
{
return EIO;
}
#ifndef NO_READDIR
int
tftpfs_readdir (struct open_file *f, char *name)
{
return EIO;
}
#endif