Site Tools


documentation:software:opera:portfolio_os:device_drivers

There are 4 classes of device drivers that Portfolio OS supports:

  • Loadable named device driver.
  • OS Loadable named device driver.
  • CPort driver.
  • Device supplied device driver.

I'll describe each class below.

Common for most drivers is the device creation process. Please read Items, tag_args, signals and i/o architecture basics before proceeding.

Creating of the named device steps :

  1. You are in privileged main, but not in SVC mode. You can use SWI here, but do not access HW!!!
  2. Create KERNELNODE+DRIVERNODE Item with a minimum of following tags - that will be your actual driver work:
    1. TAG_ITEM_PRI (should be less than real time - pri>=1)
    2. TAG_ITEM_NAME - the name of your driver. Not the name of your named device!!
    3. CREATEDRIVER_TAG_MAXCMDS, minimum 3 driver commands : driver_write, driver_read, driver_status
    4. CREATEDRIVER_TAG_CMDTABLE , driver_cmdtable array of function pointers for the driver commands.
    5. CREATEDRIVER_TAG_INIT - driver_init function – do all the HW init stuff here.
    6. CREATEDRIVER_TAG_ABORTIO - driver_abortio function
  3. Create KERNELNODE+DEVICENOTE Item with a minimum of following tags - that will be your named device interface:
    1. TAG_ITEM_PRI (should be much less than real time, pri >=128)
    2. TAG_ITEM_NAME - the name of your named device. Used in “OpenNamedDevice()” call.
    3. CREATEDEVICE_TAG_DRVR - the item of your device driver – result of the previous step
    4. CREATEDEVICE_TAG_INIT - dev_init function of your named device – clear your reference counters, no HW work here
    5. CREATEDEVICE_TAG_OPEN - dev_open function of your named device – increment usage counter, and tell HW that it is open if counter was 0
    6. CREATEDEVICE_TAG_CLOSE - dev_close function of your named device – decrement usage counter, and tell HW that it is closed if counter reached 0
  4. Optionally obtain parent's id for the signal loop
  5. AllocSignal with mask 0 or what ever parent may send us
  6. enter the loop, with WaitSignal, and exit the loop if “SIGF_ABORT” was received
  7. clean after yourself.

Function overview :

  • Item driver_init(struct Driver * drv); – called in SVC context, do what you want with HW, and return dev→dev.n_Item or error.
  • void driver_abortio(struct IOReq * ior); – called in SVC context, let's you know that the SW finished this IORequest, and disposing them. For async devices – drop what you're doing and don't send signals back.
  • int32 driver_write(struct IOReq * ior); – called in SVC context, when DoIO is is called with ioinfo.ioi_Command == CMD_WRITE. Return value is passed as DoIO return value. ior→io_Info contains your ioinfo parameters. Typically ioi_Send has the buffer details. For async io use io_Callback when ready, but you have to track your IOReqs!!!
  • int32 driver_read(struct IOReq * ior); – called in SVC context, when DoIO is is called with ioinfo.ioi_Command == CMD_READ. Return value is passed as DoIO return value. ior→io_Info contains your ioinfo parameters. Typically ioi_Send has the buffer details. For async io use io_Callback when ready, but you have to track your IOReqs!!!
  • int32 driver_status(struct IOReq * ior); – called in SVC context, when DoIO is is called with ioinfo.ioi_Command == CMD_STATUS. Return value is passed as DoIO return value. ior→io_Info contains your ioinfo parameters. Typically the status is returned. No async statuses are supported. Use CMD_READ for anything async.
  • int32 dev_init(struct Device * dev); – called in SVC context, during the device creation call. It is intended for your named device init – software init : clear dev→dev_OpenCnt ; set dev→MaxUnitNum to something meaningful (0 - if you only have 1 unit). Think “/dev/tty0 , /dev/tty1…. /dev/ttyN , where N is dev→MaxUnitNum. You must return your item dev→dev.n_Item . Optionally you can do HW init here.
  • int32 dev_open(struct Device * dev); – called in SVC context, when OpenNamedDevice(“name”, unitNum) or FindAndOpenDevice is called. Do your house keeping, by incrementing dev→dev_OpenCnt . If it was the first open, take care of notifying your HW if needed. you must return your item dev→dev.n_Item or error. Unfortunately unitNum is not passed as of PF2.5 .. Eh???
  • void dev_close(struct Device * dev); – called in SVC context, when your named device item is closed. Do your house keeping, by decrementing dev→dev_OpenCnt . If it was the last close (i.e. count now is 0), take care of notifying your HW if needed.
  • driver_cmdtable - is an array of function pointers to your driver_write as [0], driver_read as [1], driver_status as [2]. You can add your own custom commands, taking care of indicating the size in CREATEDRIVER_TAG_MAXCMDS

All functions in SVC content must use non-swi style of Folio syscalls.. You cannot use SWI !!!!. See sample project's kernel_calls.s as example of how to access kernel syscalls.

Device classes:

  • Loadable named device - basically privileged aif (3do flags 2), but has to be loaded by the user app. OS is not aware of their existence until loaded.
  • OS Loadable named device - privileged daemonized aif (3do flags 2+4). Place it in System/Daemons. Loaded by the Operator Folio prior to shell.
  • CPort driver - CPort header followed by privileged aif (3do flags 2). EventBroker loads it as “$boot/System/Drivers/cport%x.rom” where %x is first 1-2 bytes of the device id on the PBus wire.
  • Device supplied device driver - only seen on XBus. CDRom or any other XBus devices can provide it's own driver. See 256kb NVRam extension as potential example. It has XBus header followed by privileged aif (3do flags 2).

CPort driver header :

typedef struct{

uint32 headerchecksum;

uint32 filesize;

uint32 familycode;

uint32 familyversion;

uint32 imagechecksum;

uint32 pad[3];

} cport_hdr_t;

NOTE : All privileged aifs must be signed by appropriate key (depending on flag 4).

documentation/software/opera/portfolio_os/device_drivers.txt · Last modified: 2022/01/16 19:03 by trapexit