Drives and serial. #3

Closed
sam wants to merge 4 commits from sam/LuPPC:blkdev-and-serial into master
9 changed files with 419 additions and 2 deletions
Showing only changes of commit f2436f8aa5 - Show all commits

155
src/c/blkdev.c Normal file
View File

@ -0,0 +1,155 @@
#include "lupi.h"
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <linux/fs.h>
#include <linux/hdreg.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <errno.h>
#include <string.h>
struct blkdev {
int fd;
int secsize;
int platters;
size_t size;
char * buffer;
};
int blk_open(lua_State * L) {
char * path = luaL_checkstring(L, 1);
char rpath[255];
sprintf(rpath, "/dev/%s", path);
int fd = open(rpath, O_RDWR | O_DSYNC);
if (fd == -1) {
luaL_error(L, "Failed to open %s: %s", rpath, strerror(errno));
}
struct blkdev * dev = lua_newuserdata(L, sizeof(struct blkdev));
dev->fd = fd;
struct hd_driveid driveid;
if (ioctl(fd, HDIO_GET_IDENTITY, &driveid) < 0) {
//luaL_error("Failed to get identity for %s", rpath);
dev->platters = 3;
// Use another ioctl call to get sector size.
if (!ioctl(fd, BLKSSZGET, &dev->secsize)) {
// Fuck it, i guess it's 512 bytes.
dev->secsize = 512;
// Maybe a warning here?
}
dev->size = lseek(fd, 0, SEEK_END);
lseek(fd, 0, SEEK_SET);
} else {
dev->size = driveid.lba_capacity_2*driveid.sector_bytes;
dev->platters = driveid.cur_heads/2;
dev->secsize = driveid.sector_bytes;
if (dev->size == 0) {
dev->size = lseek(fd, 0, SEEK_END);
lseek(fd, 0, SEEK_SET);
}
if (dev->platters == 0) {
dev->platters = 3;
}
if (dev->secsize == 0) {
if (!ioctl(fd, BLKSSZGET, &dev->secsize)) {
// Fuck it, i guess it's 512 bytes.
dev->secsize = 512;
// Maybe a warning here too?
}
}
}
dev->buffer = malloc(dev->secsize);
return 1;
}
int blk_readbyte(lua_State * L) {
struct blkdev * dev = lua_touserdata(L, 1);
off_t offset = luaL_checkinteger(L, 2);
lseek(dev->fd, offset-1, SEEK_SET);
uint8_t c = 0;
size_t ioc = 0;
if ((ioc = read(dev->fd, &c, 1)) != 1) {
luaL_error(L, "io error! %llu != %llu", ioc, 1);
}
lua_pushinteger(L, c);
return 1;
}
int blk_writebyte(lua_State * L) {
struct blkdev * dev = lua_touserdata(L, 1);
off_t offset = luaL_checkinteger(L, 2);
long byte = luaL_checkinteger(L, 3);
if (byte > 255 || byte < 0)
luaL_error(L, "%lld is out of range (should be between 0 and 255)", byte);
uint8_t i = byte & 0xFF;
lseek(dev->fd, offset-1, SEEK_SET);
size_t ioc = 0;
if ((ioc = write(dev->fd, &i, 1)) != 1) {
luaL_error(L, "io error! %llu != %llu", ioc, 1);
}
return 0;
}
int blk_readsector(lua_State * L) {
struct blkdev * dev = lua_touserdata(L, 1);
off_t offset = luaL_checkinteger(L, 2);
lseek(dev->fd, (offset-1)*dev->secsize, SEEK_SET);
size_t ioc = 0;
if ((ioc = read(dev->fd, dev->buffer, dev->secsize)) != dev->secsize) {
luaL_error(L, "io error! %llu != %llu", ioc, dev->secsize);
}
lua_pushlstring(L, dev->buffer, dev->secsize);
return 1;
}
int blk_writesector(lua_State * L) {
struct blkdev * dev = lua_touserdata(L, 1);
off_t offset = luaL_checkinteger(L, 2);
size_t len = 0;
char * sec = luaL_checklstring(L, 3, &len);
lseek(dev->fd, (offset-1)*dev->secsize, SEEK_SET);
if (len > dev->secsize) {
len = dev->secsize;
}
size_t ioc = 0;
if ((ioc = write(dev->fd, sec, len)) != len) {
luaL_error(L, "io error! %llu != %llu", ioc, dev->secsize);
}
return 0;
}
int blk_getsecsize(lua_State * L) {
struct blkdev * dev = lua_touserdata(L, 1);
lua_pushinteger(L, dev->secsize);
return 1;
}
int blk_getsize(lua_State * L) {
struct blkdev * dev = lua_touserdata(L, 1);
lua_pushinteger(L, dev->size);
return 1;
}
int blk_getplatcount(lua_State * L) {
struct blkdev * dev = lua_touserdata(L, 1);
lua_pushinteger(L, dev->platters);
return 1;
}
void blk_start(lua_State * L) {
struct luaL_Reg blklib[] = {
{"open", blk_open},
{"readbyte", blk_readbyte},
{"writebyte", blk_writebyte},
{"readsector", blk_readsector},
{"writesector", blk_writesector},
{"secsize", blk_getsecsize},
{"size", blk_getsize},
{"platcount", blk_getplatcount},
{NULL, NULL}
};
luaL_openlib(L, "blk", blklib, 0);
}

View File

@ -12,6 +12,7 @@ void lupi_init() {
mount(NULL, "/sys", "sysfs", 0, NULL);
mount(NULL, "/proc", "procfs", 0, NULL);
mount(NULL, "/tmp", "tmpfs", 0, NULL);
mount(NULL, "/dev", "devtmpfs", 0, NULL);
}
struct statvfs fsstat;

View File

@ -14,12 +14,14 @@ void setup_modules(lua_State *L) {
pushstuple(L, "component", lua_component);
pushstuple(L, "computer", lua_computer);
pushstuple(L, "debug", lua_debug);
pushstuple(L, "drive", lua_drive);
pushstuple(L, "eeprom", lua_eeprom);
pushstuple(L, "filesystem", lua_filesystem);
pushstuple(L, "gpio", lua_gpio);
pushstuple(L, "gpudetect", lua_gpudetect);
pushstuple(L, "internet", lua_internet);
pushstuple(L, "sandbox", lua_sandbox);
pushstuple(L, "serial", lua_serial);
pushstuple(L, "textgpu", lua_textgpu);
pushstuple(L, "fbgpu", lua_fbgpu);
pushstuple(L, "winapigpu", lua_winapigpu);

View File

@ -31,6 +31,8 @@ void run_init(int argc, char **argv) {
#endif
fb_start (L);
termutils_start (L);
serial_start (L);
blk_start (L);
event_prepare();
int status = luaL_loadbuffer(L, lua_init, strlen(lua_init), "=INIT");

159
src/c/serial.c Normal file
View File

@ -0,0 +1,159 @@
#include "lupi.h"
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
#include <sys/stat.h>
int s_listports(lua_State * L) {
DIR * d = opendir("/sys/class/tty");
struct dirent * ent = NULL;
struct stat statbuf;
char path[255];
char linkpath[255];
lua_newtable(L);
size_t index = 1;
while ((ent = readdir(d)) != NULL) {
sprintf(path, "/sys/class/tty/%s/device", ent->d_name);
if (stat(path, &statbuf) == 0) {
readlink(path, linkpath, 255);
if (strstr(linkpath, "serial8250") == NULL) {
// We have a serial port
lua_pushinteger(L, index);
lua_pushstring(L, ent->d_name);
lua_settable(L, -3);
}
}
}
return 1;
}
struct baudrate {
uint32_t baud;
tcflag_t flags;
};
// taken from here: https://man7.org/linux/man-pages/man3/termios.3.html
struct baudrate baudrates[] = {
{0, B0},
{50, B50},
{75, B75},
{110, B110},
{134, B134},
{150, B150},
{200, B200},
{300, B300},
{600, B600},
{1200, B1200},
{1800, B1800},
{2400, B2400},
{4800, B4800},
{9600, B9600},
{19200, B19200},
{38400, B38400},
{57600, B57600},
{115200, B115200},
{230400, B230400}
};
struct baudrate * getbaud(uint32_t baud) {
for (size_t i=0; i<sizeof(baudrates)/sizeof(struct baudrate); ++i) {
if (baudrates[i].baud == baud) {
return &baudrates[i];
} else if (baudrates[i].baud > baud) {
return &baudrates[i-1];
}
}
return getbaud(230400);
}
struct sport {
uint32_t baudrate;
int fd;
struct termios options;
};
int s_openport(lua_State * L) {
char * path = luaL_checkstring(L, 1);
struct sport * port = lua_newuserdata(L, sizeof(struct sport));
port->baudrate = 9600;
char rpath[255];
sprintf(rpath, "/dev/%s", path);
port->fd = open(rpath, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK);
if (port->fd == -1)
luaL_error(L, "unable to open port %s: ", path, strerror(errno));
tcgetattr(port->fd, &port->options);
cfsetispeed(&port->options, B9600);
cfsetospeed(&port->options, B9600);
tcsetattr(port->fd, TCSANOW, &port->options);
return 1;
}
int s_setbaudrate(lua_State * L) {
struct sport * port = lua_touserdata(L, 1);
long raw_br = luaL_checkinteger(L, 2);
struct baudrate * br = getbaud(raw_br & 0xFFFFFFFF);
//port->options.c_cflag &= ~(CBAUD);
//port->options.c_cflag |= br->flags;
cfsetispeed(&port->options, br->flags);
cfsetospeed(&port->options, br->flags);
port->baudrate = br->baud;
lua_pushinteger(L, br->baud);
port->options.c_cflag &= ~PARENB;
port->options.c_cflag &= ~CSTOPB;
port->options.c_cflag &= ~CSIZE;
port->options.c_cflag |= CS8;
tcsetattr(port->fd, TCSANOW, &port->options);
return 1;
}
int s_getbaudrate(lua_State * L) {
struct sport * port = lua_touserdata(L, 1);
lua_pushinteger(L, port->baudrate);
return 1;
}
int s_write(lua_State * L) {
struct sport * port = lua_touserdata(L, 1);
size_t len = 0;
char * data = luaL_checklstring(L, 2, &len);
size_t ioc = 0;
if ((ioc = write(port->fd, data, len)) != len) {
luaL_error(L, "io error! %llu != %llu", ioc, len);
}
return 0;
}
int s_read(lua_State * L) {
struct sport * port = lua_touserdata(L, 1);
char buffer[2048]; // Max packet size
long size = luaL_checkinteger(L, 2);
size_t ioc = read(port->fd, buffer, size);
if (ioc != size && ioc != 0) {
luaL_error(L, "io error! %llu != %llu or 0", ioc, size);
} else if (ioc != 0) {
lua_pushlstring(L, buffer, size);
return 1;
}
return 0;
}
void serial_start(lua_State * L) {
struct luaL_Reg seriallib[] = {
{"open", s_openport},
{"list", s_listports},
{"write", s_write},
{"read", s_read},
{"setbaud", s_setbaudrate},
{"getbaud", s_getbaudrate},
{NULL, NULL}
};
luaL_openlib(L, "serial", seriallib, 0);
}

View File

@ -109,7 +109,7 @@ function api.invoke(address, method, ...)
local msg = tostring((native.uptime() - start) / 1000) .. " [+" .. native.uptime() - last .. "] " .. caller.short_src .. ":".. caller.currentline .. " > c.invoke(" .. address .. "): "
.. components[address].type .. "." .. method
.. "(" .. table.concat(t, ", ") .. ")"
native.log(msg)
--native.log(msg)
end
return components[address].rawproxy[method](...)
end

59
src/lua/core/drive.lua Normal file
View File

@ -0,0 +1,59 @@
local drive = {}
function drive.register()
local list = native.fs_list("/sys/block")
for _, ent in ipairs(list) do
-- Match hard drives. floppy drives, an rewindable tape drives
if (ent:match("sd%a%d*") or ent:match("hd%a%d*") or ent:match("fd%d+") or ent:match("n?st%d+[lma]?") or ent:match("n?ht%d+[lma]?")) then
--if true then
lprint("Attempting to open: "..ent)
local ok, disk = pcall(blk.open, ent)
if ok then
local component = {}
function component.readByte(offset)
return blk.readbyte(disk, offset)
end
function component.writeByte(offset, value)
return blk.writebyte(disk, offset, value)
end
function component.getLabel()
return ent
end
function component.setLabel(str)
-- stub
return ent
end
function component.readSector(sec)
return blk.readsector(disk, sec)
end
function component.writeSector(sec, val)
return blk.writesector(disk, sec, val)
end
function component.getPlatterCount()
return blk.platcount(disk)
end
function component.getSectorSize()
return blk.secsize(disk)
end
function component.getCapacity()
return blk.size(disk)
end
modules.component.api.register("Block:"..ent, "drive", component)
else
lprint("Can't open blkdev: "..ent..": "..disk)
end
end
end
end
return drive

View File

@ -44,6 +44,10 @@ lprint = function (...)
end
lprint("LuPI L1 INIT")
local ports = serial.list()
for i=1, #ports do
lprint(ports[i])
end
modules = {}
deadhooks = {}
@ -90,6 +94,8 @@ function main()
loadModule("gpudetect")
loadModule("filesystem")
loadModule("internet")
loadModule("serial")
loadModule("drive")
--Userspace
loadModule("sandbox")
@ -99,7 +105,8 @@ function main()
modules.component.prepare()
modules.computer.prepare()
_G.pushEvent = modules.computer.api.pushSignal
modules.serial.register()
modules.drive.register()
modules.eeprom.register()
modules.gpio.register()
modules.internet.start()

32
src/lua/core/serial.lua Normal file
View File

@ -0,0 +1,32 @@
local com = {}
function com.register()
local ports = serial.list()
for i=1, #ports do
lprint("Serial port: "..ports[i])
local component = {}
local ok, dev = pcall(serial.open, ports[i])
if not dev then lprint("Can't open port: "..ports[i]..": "..dev) goto continue end
--lprint(dev)
function component.setBaudRate(baud)
return serial.setbaud(dev, baud)
end
function component.getBaudRate()
return serial.getbaud(dev)
end
function component.write(s)
return serial.write(dev, s)
end
function component.read(amt)
return serial.read(dev, amt)
end
modules.component.api.register("Serial:"..ports[i], "serial", component)
::continue::
end
end
return com