##############################
1. Intro

(All directory and file references are relative <urjtag-git top dir>/urjtag.)

All "cable" drivers lives in:
 src/tap/cable

Currently theese parport drivers are available:
 arcom.c
 byteblaster.c
 dlc5.c
 ea253.c
 ei012.c
 keithkoep.c
 lattice.c
 minimal.c
 mpcbdm.c
 triton.c
 wiggler.c
 wiggler2.c

To write a new driver, you make a new file in that directory named by
convention by the driver name. In this case I'll describe the steps I
took to make the driver for the aspo adapter card (as of july 2019).

##############################
2. Build system, adding a driver.

(This section is valid for all cable driver, parport, usb and others.)

Before I describe the driver code, let's look into how to integrate
the .c file into the build system.

You have to update the following files:
 MAINTAINERS
 configure.ac
 doc/UrJTAG.txt
 po/POTFILES.in
 src/tap/Makefile.am
 src/tap/cable_list.h

2.1 MAINTAINERS

To be kind to others, please fill in the MAINTAINERS file, and keep it
sorted. I added the entry:

ASPO CABLE DRIVER
M:      Karl Hammar <karl at aspodata.se>
F:      src/tap/cable/aspo.c
S:      Tested

between the "ARCOM CABLE DRIVER" and "AU1500 BUS DRIVER".

2.2 configure.ac

In configure.ac there is a list of all possible "cable" drivers around
line 655:

# Enable cable drivers
URJ_DRIVER_SET([cable], [
        arcom
        byteblaster
        dirtyjtag
        dlc5
        ea253
... (omitted lines)
        wiggler
        xpc
],[
        ep9307
        jim
        ts7800
],[
        # automatically disable cable drivers when a required feature is not available
... (omitted lines)
        ])
])


add your name there. This will make it possible to enable your driver
when you running autogen.sh and configure (look in config.h to make sure).

URJ_DRIVER_SET() have four parameters
 1st is the driver set name
 2nd is the list of drivers to enable by default
 3rd is the list of drivers to disable by default
 4th is some extra code to run before processing user list
you will probably add your driver name to the 2nd argument.

I added the line:
    aspo
between the lines with arcom and byteblaster to keep the list sorted.

2.3 doc/UrJTAG.txt

Make a note here about your driver so others has a chance to know that
it exist. The best place is below line 202 under the headers:

==== Supported JTAG adapters/cables ====

See 'help cable' command for up-to-date info.

Parallel-port cables:

2.4 po/POTFILES.in

Add your driver source file in the list.
 TODO:
Still don't know at this moment how to make gettext to update
po/urjtag.pot so translators can do their job properly.

2.5 src/tap/Makefile.am

Add, if-endif code to add your code if your driver is enabled.
I added:

if ENABLE_CABLE_ASPO
libtap_la_SOURCES += \
        cable/aspo.c
endif

between the similar lines for ARCOM and BYTEBLASTER to keep the list
sorted.

2.6 src/tap/cable_list.h

Add your _URJ_CABLE() section here so your driver entry point can be
included. This file is then included in:
 src/tap/cable.h 
 src/tap/cable.c
and via cpp hackery makes the driver entry points available.
As before, keep the list sorted

I added this section (between the ARCOM and BYTEBLASTER sections):

#ifdef ENABLE_CABLE_ASPO
_URJ_CABLE(aspo)
#endif

##############################
3. Driver code.

3.1 Test building

Copy a similar driver as your initial source file and replace the old
driver name with the new one.

In my case it amounted to:
sed -e 's/wiggler2/aspo/g' < src/tap/cable/wiggler2.c > src/tap/cable/aspo.c
and then change the first two text entries of the const
urj_cable_driver_t last in the file to say something else than the
original, just for testing.

Now, run
  ./autogen.sh
  # ./configure done by autogen.sh; run it here with special options if needed
  make
  make install

Look at the make output and make sure you see your source compiling,
something like:
  CC       cable/aspo.lo

Test with jtag and verify that your driver is there with "help
cable" without any actual "cable" attached to the paralell port.

For me it worked out as (on linux using ppdev as the lowlevel driver):

$ jtag

UrJTAG 2018.09 #
Copyright (C) 2002, 2003 ETC s.r.o.
Copyright (C) 2007, 2008, 2009 Kolja Waschk and the respective authors
... (omitted lines)
jtag> help cable
Usage: cable DRIVER [DRIVER_OPTS]
Select JTAG cable type.

DRIVER      name of cable
DRIVER_OPTS options for the selected cable

Type "cable DRIVER help" for info about options for cable DRIVER.
You can also use the driver "probe" to attempt autodetection.

List of supported cables:
ARCOM           Arcom JTAG Cable
ASPO            Aspo JTAG Cable (experimental)
ByteBlaster     Altera ByteBlaster/ByteBlaster II/ByteBlasterMV Parallel Port Download Cable
DLC5            Xilinx DLC5 JTAG Parallel Cable III
... (omitted lines)
DirtyJTAG       DirtyJTAG STM32-based cable
jtag> cable aspo ppdev /dev/parport0
Initializing ppdev port /dev/parport0
jtag> cable ASPO ppdev /dev/parport0
Initializing ppdev port /dev/parport0
jtag> quit

As you can see, the driver name is case insensitive, the function that
finds the driver is urj_tap_cable_find() (in src/tap/cable.c) and it
uses strcasecmp().

3.2 The jtag command

When you run the command jtag, you run the code found in
src/apps/jtag/jtag.c, which, if run interactively, calls
jtag_readline_loop() -> jtag_readline_multiple_commands_support() ->
urj_parse_line() (which is found in src/global/parse.c) ->
urj_cmd_run() (src/cmd/cmd_cmd.c). urj_cmd_run() has two arguments,
chain and params. Chain is the found chain of tap controllers among
other things. Params is the command line entered, but tokenized.
The word chain is used in the combination JTAG chain in
doc/UrJTAG.txt.

urj_cmd_run() searches urj_cmds[] for the command to run. The
urj_cmds[] list is generated by Makefile from the files in src/cmd
that contaings a const urj_cmd_t urj_cmd_* variable.

So, if we enter quit to the command line, urj_cmd_run() finds "quit"
in urj_cmd_quit variable last in src/cmd/cmd_quit.c and runs
cmd_quit_run() since that is the run element of the urj_cmd_t struct.

The process is similar for other commands and you can find them all in
the src/cmd directory.

3.2.1 The jtag cable command

In 3.1 we entered the command line "cable aspo ppdev /dev/parport0".
By doing so urj_cmd_run() finds the data in urj_cmd_cable last in
src/cmd/cmd_cable.c and extracts the run member of that struct, i.e.
the function pointer cmd_cable_run. As seen in src/cmd/cmd_cable.c,
cmd_cable_run() does some checks and calls
urj_tap_chain_connect(chain, params[1], &params[2]) (src/tap/chain.c),
params[1] is in this case is "aspo", and &params[2] is a pointer to
{ "ppdev", "/dev/parport0" }.

It seems that everything hardware related goes through urj_tap_*()
functions, they reside in the usr/tap directory.

urj_tap_chain_connect() finds our driver (aspo), sees that it is a
parport driver, finds the parport devtype (ppdev) and calls
urj_tap_cable_parport_connect() (src/tap/cable.c).

For some reason, the urj_parport_driver_t (include/urjtag/parport.h)
struct doesn't contain a searchable string (e.g. "ppdev") like the
urj_cable_driver_t (struct URJ_CABLE_DRIVER, include/urjtag/cable.h),
and the search is done through a switch statement in
urj_cable_parport_devtype_string(). So first we search for an int and
then what driver struct matches that int.

urj_tap_cable_parport_connect() then allocs an urj_cable_t cable,
setting its .driver to a pointer to the driver, and runs the driver's
connect(), usually urj_tap_cable_generic_parport_connect()
(src/tap/cable/generic_parport.c) which finds the entry point (i.e. a
struct with function pointers) for devtype, and runs its connect() entry.
In our example, it is ppdev_connect(), which checks that we arn't
already using the device (/dev/parport0 in our example), and then sets
up a port_node_t (src/tap/parport.h) structure.

Back in urj_tap_cable_parport_connect(), it runs urj_tap_cable_start(),
which runs urj_tap_cable_init() (src/tap/cable.c) and
urj_tap_trst_reset() (src/tap/tap.c).
urj_tap_cable_init() sets up the urj_cable_t variable and calls the
cable drivers init (aspo_init() in our example), which is calling
ppdev_open() (in our example) which actually does open the device file.

3.3 driver documentation

3.3.1 driver entry point

Your driver is reached with the "const urj_cable_driver_t" struct,
usually found near the end of the driver code. The name of the struct
must match what comes out of the _URJ_CABLE(<driver name>) macro found
in src/tap/cable.[ch] and src/tap/cable_list.h. This macro is
differntly defined in the files src/tap/cable.[ch]:

 cable.c:
#define _URJ_CABLE(cable) &urj_tap_cable_##cable##_driver,
 cable.h:
#define _URJ_CABLE(cable) extern const urj_cable_driver_t urj_tap_cable_##cable##_driver;

but the struct name is the same for booth theese to definitions
urj_tap_cable_##cable##_driver, i.e. if you used _URJ_CABLE(foo) in
the cable_list.h file, then you must define the entry point as:

const urj_cable_driver_t urj_tap_cable_foo_driver = {
... (omitted lines)
};

This type, urj_cable_driver_t, is defined in include/urjtag/cable.h,
it is a typedef near the top of the file:
typedef struct URJ_CABLE_DRIVER urj_cable_driver_t;
and the actual struct is defined in middle of the file:

struct URJ_CABLE_DRIVER
{
...
 int  (*parport)       (urj_cable_t *cable, urj_cable_parport_devtype_t devtype,
 int  (*usb)           (urj_cable_t *cable, const urj_param_t *params[]);
 int  (*other)         (urj_cable_t *cable, const urj_param_t *params[]);
...
 void (*disconnect)    (urj_cable_t *cable);
 void (*cable_free)    (urj_cable_t *cable);
 int  (*init) 	       (urj_cable_t *);
 void (*done) 	       (urj_cable_t *);
 void (*set_frequency) (urj_cable_t *, uint32_t freq);
 void (*clock) 	       (urj_cable_t *, int, int, int);
 int  (*get_tdo)       (urj_cable_t *);
 int  (*transfer)      (urj_cable_t *, int, const char *, char *);
 int  (*set_signal)    (urj_cable_t *, int, int);
 int  (*get_signal)    (urj_cable_t *, urj_pod_sigsel_t);
 void (*flush) 	       (urj_cable_t *, urj_cable_flush_amount_t);
 void (*help) 	       (urj_log_level_t ll, const char *);
};

Your job as a driver writer is to fill in your struct variable with
the right set of functions for the operation of your hardware.

Most of theese entries are generic as seen in my example:

const urj_cable_driver_t urj_tap_cable_aspo_driver = {
    "ASPO",
    N_("Aspo JTAG Cable (experimental)"),
    URJ_CABLE_DEVICE_PARPORT,
    { .parport = urj_tap_cable_generic_parport_connect, },
    urj_tap_cable_generic_disconnect,
    urj_tap_cable_generic_parport_free,
    aspo_init,
    urj_tap_cable_generic_parport_done,
    urj_tap_cable_generic_set_frequency,
    aspo_clock,
    aspo_get_tdo,
    urj_tap_cable_generic_transfer,
    aspo_set_signal,
    urj_tap_cable_generic_get_signal,
    urj_tap_cable_generic_flush_one_by_one,
    urj_tap_cable_generic_parport_help
};

The only thing I had to add is the init, clock, get_tdo and set_signal
entries and the name ("ASPO") and the description (N_("...")).

The N_(...) thing is defined in sysdep.h as
#define N_(s)           gettext_noop(s)
and definition of gettext_noop() is found in include/urjtag/gettext.h.

3.3.2 Our first parameter, the urj_cable_t *cable

All function entries in the urj_cable_driver_t struct (except help) have a
"urj_cable_t *cable" first parameter, as can be seen from the extract below.

urj_cable_t is a struct URJ_CABLE (as seen in include/urjtag/types.h)
and that struct is declared in include/urjtag/cable.h, some 50 lines
below the struct URJ_CABLE_DRIVER declaration:

struct URJ_CABLE
{
    const urj_cable_driver_t *driver;
    union
    {
        urj_usbconn_t *usb;
        urj_parport_t *port;
        void *other;
    } link;
    void *params;
    urj_chain_t *chain;
    urj_cable_queue_info_t todo;
    urj_cable_queue_info_t done;
    uint32_t delay;
    uint32_t frequency;
};

The variable cable is initialized as

 urj_tap_cable_create():
cable = calloc()
cable->driver = driver (= your driver entry point)

 urj_tap_cable_generic_parport_connect()
cable->link.port = port
cable->params = cable_params
cable->chain = NULL

 urj_tap_cable_start()
chain->cable = cable

cable->delay = 0;
cable->frequency = 0;

 urj_tap_cable_init()
cable->todo = {}
cable->done = {}

 ppdev_parport_alloc()
cable->link.port = {}

 your parport driver _open (ppdev_open() in this example)
open() and ioctl(,PPCLAIM)

 your cable driver _init() (aspo_init() in this example)
PARAM_SIGNALS (cable) = ...

 urj_tap_chain_connect()
chain->cable->chain = chain

Of all struct members, only cable->params is of main interest for the
cable driver writer. urj_tap_cable_generic_params_t and
PARAM_SIGNALS() are declared in src/tap/cable/generic.h, and they are
only used within the src/tap/cable directory. Its value is leaked out
by urj_tap_cable_generic_get_signal() which is the default
driver->get_signal() function, so we must provide for that value since 
it is visible to the outside. That can be done by the default function
and types, by a custom one.

urj_tap_cable_get_signal() and urj_tap_cable_get_signal_late() via
urj_tap_chain_get_trst() and urj_tap_chain_get_pod_signal() is
used by the pod command (src/cmd/cmd_pod.c).

3.3.3 Talking to the hardware

Access to hw is done with the functions in src/tap/parport.c which are
shorthands for accessing the functions of the choosed parport handler
(ppdev in this example).

There are three registers on an ordinary paralell port: data, control
and status. Some bits in the control and status registers have
inverted signals to/from the connector pins, but theese functions
handles them so zero in an output bit given to thoose routines gives
you low voltage on the output pin and low on an input pin gives you a
zero on return on the corresponding bit.

3.3.4 Values to/from caller

The caller of the driver seems to treat tms/tdi/tck/trst/tdo values as:
1 => high voltage on jtag bus, 0 => low voltage on jtag bus. This is
guessed from the discussion below.

We have looked at driver->init() above. get_tdo() returns the TDO jtag
signal, and clock() and set_signal() sets the jtag signals.
So we must know if a clock(cable, 1, 1, 1) means that TMS and TDI
should be high (near Vcc) on the jtag bus on the target board, or low
and ditto for TRST and TCK.

From urj_svf_force_reset_state() (src/svf/svf.c) we know that tms == 1
implies that the jtag signal TMS is high since five TMS high clocked in
puts the TAP controller in the Test-Logic-Reset state.

urj_tap_trst_reset() (src/tap/tap.c) gives us that trst == 1 implies
that jtag nTRST signal is high.

urj_tap_reset_bypass() (src/tap/tap.c) gives that tdi == 1 implies
that jtag TDI signal is high, BYPASS instruction is all 1's.

By looking in various cables implementation of clock(), I guess that
tck == 1 implies that the TCK signal is high on jtag bus.