FPPS4/sys/dev/dev_null.pas

202 lines
3.3 KiB
Plaintext

unit dev_null;
{$mode ObjFPC}{$H+}
{$CALLING SysV_ABI_CDecl}
interface
uses
sys_conf;
const
ZERO_REGION_SIZE=(2 * 1024 * 1024); // 2MB
var
zero_region:Pointer;
procedure init_zero_region;
procedure free_zero_region;
Function null_modevent(_mod,_type:Integer):Integer; //DEV_MODULE(nil, null_modevent, nil);
implementation
uses
errno,
vuio,
vdisk,
vfilio,
subr_uio;
var
{ For use with destroy_dev(9). }
null_dev:p_cdev;
zero_dev:p_cdev;
Function null_write(dev:p_cdev;uio:p_uio;ioflag:Integer):Integer; forward;
Function null_ioctl(dev:p_cdev;cmd:QWORD;data:Pointer;fflag:Integer):Integer; forward;
Function zero_ioctl(dev:p_cdev;cmd:QWORD;data:Pointer;fflag:Integer):Integer; forward;
Function zero_read(dev:p_cdev;uio:p_uio;ioflag:Integer):Integer; forward;
const
null_cdevsw:t_cdevsw=(
d_version :D_VERSION;
d_flags :0;
d_name :'null';
d_read :d_read_t(@_nullop);
d_write :@null_write;
d_ioctl :@null_ioctl;
);
zero_cdevsw:t_cdevsw=(
d_version :D_VERSION;
d_flags :D_MMAP_ANON;
d_name :'zero';
d_read :@zero_read;
d_write :@null_write;
d_ioctl :@zero_ioctl;
);
{ ARGSUSED }
Function null_write(dev:p_cdev;uio:p_uio;ioflag:Integer):Integer;
begin
uio^.uio_resid:=0;
Exit(0);
end;
{ ARGSUSED }
Function null_ioctl(dev:p_cdev;cmd:QWORD;data:Pointer;fflag:Integer):Integer;
var
error:Integer;
begin
error:=0;
case (cmd) of
DIOCSKERNELDUMP:
begin
error:=EPERM;
//error:=priv_check(td, PRIV_SETDUMPER);
//if (error=0)
// error:=set_dumper(nil);
end;
FIONBIO:;
FIOASYNC:
begin
if (PInteger(data)^<>0) then
begin
error:=EINVAL;
end;
end;
else
begin
error:=ENOIOCTL;
end;
end;
Exit(error);
end;
{ ARGSUSED }
Function zero_ioctl(dev:p_cdev;cmd:QWORD;data:Pointer;fflag:Integer):Integer;
var
error:Integer;
begin
error:=0;
case (cmd) of
FIONBIO:;
FIOASYNC:
begin
if (PInteger(data)^<>0) then
begin
error:=EINVAL;
end;
end;
else
begin
error:=ENOIOCTL;
end;
end;
Exit(error);
end;
procedure init_zero_region;
var
buf:Pointer;
begin
if (zero_region=nil) then
begin
buf:=AllocMem(ZERO_REGION_SIZE);
if (System.InterlockedCompareExchange(zero_region,buf,nil)<>nil) then
begin
FreeMem(buf);
end;
end;
end;
procedure free_zero_region;
var
buf:Pointer;
begin
buf:=System.InterlockedExchange(zero_region,nil);
FreeMem(buf);
end;
{ ARGSUSED }
Function zero_read(dev:p_cdev;uio:p_uio;ioflag:Integer):Integer;
var
zbuf:Pointer;
len:QWORD;
error:Integer;
begin
error:=0;
Assert(uio^.uio_rw=UIO_READ,'Cant be in %s for write');
init_zero_region;
zbuf:=zero_region;
while (uio^.uio_resid > 0) and (error=0) do
begin
len:=uio^.uio_resid;
if (len > ZERO_REGION_SIZE) then
begin
len:=ZERO_REGION_SIZE;
end;
error:=uiomove(zbuf, len, uio);
end;
Exit(error);
end;
{ ARGSUSED }
Function null_modevent(_mod,_type:Integer):Integer;
begin
case (_type) of
MOD_LOAD:
begin
null_dev:=make_dev_credf(0, @null_cdevsw, 0, UID_ROOT, GID_WHEEL, &666, 'null',[]);
zero_dev:=make_dev_credf(0, @zero_cdevsw, 0, UID_ROOT, GID_WHEEL, &666, 'zero',[]);
end;
MOD_UNLOAD:
begin
destroy_dev(null_dev);
destroy_dev(zero_dev);
free_zero_region;
end;
MOD_SHUTDOWN:;
else
Exit(EOPNOTSUPP);
end;
Exit(0);
end;
end.