Date: Fri, 31 Jul 1998 16:22:51 -0700 From: Mike Smith <mike@smith.net.au> To: chanders@timing.com (Craig Anderson) Cc: Mike Smith <mike@smith.net.au>, freebsd-hackers@FreeBSD.ORG Subject: Re: Using FreeBSD for data acquisition? (long) Message-ID: <199807312322.QAA01183@dingo.cdrom.com> In-Reply-To: Your message of "Fri, 31 Jul 1998 15:31:37 MDT." <199807312131.PAA04940@count.timing.com>
next in thread | previous in thread | raw e-mail | index | archive | help
Looks like you might have some race conditions here; see commentary.
Also check the sleep priority; it looks like you might be seeing a
number of situations where you're coming up only when the timeout
expires.
>
> #if !defined(gt401_h)
> # define gt401_h
>
> #include <sys/ioccom.h>
>
> /* units of pt4 are 0.4 x 10^-6 sec */
>
> #define D_TYPE_NONE 99
> #define D_TYPE_ERROR 1
> #define D_TYPE_TIMETAG 2
>
> #define MIN_PERIOD_X_10000 1
> #define MAX_PERIOD_X_10000 50000
>
> typedef struct gt401_read_s
> {
> short overflow;
> short d_type;
> union
> {
> struct
> {
> unsigned int board_index;
> long long board_time_tag_usec;
> unsigned int driver_index;
> long long driver_board_usec;
> } tt;
> struct
> {
> short err_code;
> char err_str[58];
> } ee;
> } dd;
> }
> gt401_read;
>
> #define GT401_START_EVENTS \
> _IOW('G', 1, int)
> #define GT401_STOP_EVENTS \
> _IO('G', 2)
> #define GT401_GET_HIGH_WATER \
> _IOR('G', 3, int)
> #define GT401_CLEAR_HIGH_WATER \
> _IO('G', 4)
>
> #endif /* #if !defined(gt401_h) */
>
> --==_Exmh_18363059200
> Content-Type: text/plain ; name="Makefile"; charset=us-ascii
> Content-Description: Makefile
> Content-Transfer-Encoding: quoted-printable
> Content-Disposition: attachment; filename="Makefile"
>
> # $Id: Makefile,v 1.12 1998/07/30 17:19:23 chanders Exp $
>
> =2EPATH: .
> KMOD =3D gt401_mod
> SRCS =3D gt401.c gt401.h ngt401.h
> #MAN4 =3D gt401.4
> #MAN8 =3D gt401in.8
> LN =3D ln -f -s
>
> CFLAGS +=3D \
> -I. \
> -I/usr/src/sys \
> -DGT401_MODULE
>
> CLEANFILES +=3D ngt401.h
>
> ngt401.h:
> echo "#define NGT401 1" > ngt401.h
>
> r0: gt401_mod.o
> cp gt401_mod.o \
> /usr/local/tsc/rel/bin
>
>
> test03: test03.c
> cc -o test03 test03.c
>
> test04: test04.c
> cc -o test04 test04.c
>
> test05: test05.c
> cc -o test05 test05.c
>
> test06: test06.c
> cc -g -o test06 test06.c
>
> test07: test07.c
> cc -g -o test07 test07.c
>
> test08: test08.c
> cc -g -o test08 test08.c
>
> log_read_counts_980726: log_read_counts_980726.c
> cc -g -o log_read_counts_980726 log_read_counts_980726.c
>
> counts_to_histogram: counts_to_histogram.c
> cc -g -o counts_to_histogram counts_to_histogram.c
>
> kmem_gt401: kmem_gt401.c
> cc -g -o kmem_gt401 kmem_gt401.c
>
> =2Einclude <bsd.kmod.mk>
>
>
> --==_Exmh_18363059200
> Content-Type: text/plain ; name="gt401.c"; charset=us-ascii
> Content-Description: gt401.c
> Content-Transfer-Encoding: quoted-printable
> Content-Disposition: attachment; filename="gt401.c"
>
>
> #include <sys/errno.h>
> #include <sys/param.h>
> #include <sys/systm.h>
> #include <sys/conf.h>
> #include <sys/signalvar.h>
> #include <sys/proc.h>
> #include <sys/kernel.h>
>
> #include <machine/clock.h>
> #include <machine/endian.h>
>
> #include <i386/isa/isa.h>
> #include <i386/isa/isa_device.h>
> #include <i386/isa/timerreg.h>
> #include <i386/isa/icu.h>
>
> #include "ngt401.h"
> #include "gt401.h"
>
> #define UNIT(d) (minor(d) >> 16)
>
> #define CDEV_MAJOR 90
> #define MAX_GT401_RBUF (4*1024)
>
> enum
> {
> io_addr_status_reg =3D 0,
> io_addr_ram_addr_reg =3D 0,
> io_addr_cont_reg_1 =3D 1,
> io_addr_cont_reg_2 =3D 2,
> io_addr_mux_addr_reg =3D 3,
> io_addr_mux_data_reg =3D 4,
> io_addr_8254_data_reg =3D 5,
> io_addr_us_count0 =3D 6,
> io_addr_us_count1 =3D 7,
> io_addr_cmd_ready =3D 7,
> io_addr_dp_ram =3D 8,
> io_addr_err_reg =3D 13,
>
> dp_ram_lus_page =3D 0,
> dp_ram_command_first_page =3D 144,
> dp_ram_status_page =3D 146,
>
> mux_54_ctr_0 =3D 0,
> mux_54_ctr_1 =3D 8,
> mux_54_ctr_2 =3D 16,
> mux_54_cont =3D 24,
>
> cmd_poll_inner_loop =3D 512,
> cmd_poll_sleep_loop =3D 20,
> cmd_poll_usleep =3D 10000,
> cmd_buf_sz =3D 20,
>
> cmd_init =3D 1,
> cmd_self_test =3D 2,
> cmd_nop =3D 3,
> cmd_ext_osc =3D 7,
> cmd_pulse =3D 8,
> cmd_tt =3D 9,
> cmd_chan_off =3D 12,
> cmd_tt_size =3D 13,
> cmd_clr_tt =3D 15,
> cmd_clr_err =3D 20,
>
> cont_reg1_src_mask =3D 7,
> cont_reg1_pulse_en =3D 0x08,
> cont_reg1_sw_pulse =3D 0x10,
>
> status_reg_ready_for_cmd =3D 1,
>
> cont_reg2_irq_src_mask =3D 7,
> cont_reg2_irq_src_chan0 =3D 0,
> cont_reg2_irq_src_chan1 =3D 1,
> cont_reg2_irq_src_chan2 =3D 2,
> cont_reg2_irq_src_chan3 =3D 3,
> cont_reg2_irq_src_board_proc =3D 4,
> cont_reg2_irq_src_out0 =3D 5,
> cont_reg2_irq_src_out1 =3D 6,
> cont_reg2_irq_src_out2 =3D 7,
> cont_reg2_intr_en_bit =3D 0x08,
> cont_reg2_intr_edge_bit =3D 0x10,
>
> conn_CLK0 =3D 0, /* All CLKn values must be consecutive */
> conn_CLK1 =3D 1,
> conn_CLK2 =3D 2,
> conn_EXT_CLK0 =3D 3, /* All EXT_CLKn values must be consecutive */
> conn_EXT_CLK1 =3D 4,
> conn_EXT_CLK2 =3D 5,
> conn_GATE0 =3D 6, /* All GATEn values must be consecutive */
> conn_GATE1 =3D 7,
> conn_GATE2 =3D 8,
> conn_EXT_GATE0 =3D 9, /* All EXT_GATEn values must be consecutive */
> conn_EXT_GATE1 =3D 10,
> conn_EXT_GATE2 =3D 11,
> conn_OUT0 =3D 12, /* All OUTn values must be consecutive */
> conn_OUT1 =3D 13,
> conn_OUT2 =3D 14,
> conn_IO_CHAN0 =3D 15, /* All IO_CHANn values must be consecutive */
> conn_IO_CHAN1 =3D 16,
> conn_IO_CHAN2 =3D 17,
> conn_IO_CHAN3 =3D 18,
> conn_EXT_CHAN0 =3D 19, /* all EXT_CHANNn values must be consecutive */=
>
> conn_EXT_CHAN1 =3D 20,
> conn_EXT_CHAN2 =3D 21,
> conn_EXT_CHAN3 =3D 22,
> conn_TEN_MHZ =3D 23,
> conn_GATED_TEN_MHZ =3D 24,
> conn_SW_LOW =3D 25, /* To force an input low */
> conn_SW_HIGH =3D 26, /* To force an input high */
> conn_SW_INTR =3D 27, /* For selecting interrupts from */
>
> tt_ptr_reg =3D 12, /* in dpram status page */
> err_reg =3D 13, /* in dpram status page */
>
> tt_edge_neg =3D 0x08,
> tt_edge_pos =3D 0x10,
>
> ten_int =3D 2,
> ten_int_out =3D 3,
> ten_ext =3D 4,
>
> err_success =3D 0,
> err_no_io_fd =3D 1,
> err_timeout =3D 2,
> err_cmd_sz =3D 3,
> err_invalid_8254_ctr =3D 4,
> err_connect_dst =3D 5,
> err_connect_src =3D 6,
> err_io_open =3D 7,
> err_ten_mhz =3D 8,
> err_irq_src =3D 9
> };
>
> /* One dev per board */
> static struct isa_device devices[NGT401];
>
> /*
> * Setup the per-device structure defining routines used at 'boot' time.
> */
> static int gt401attach(struct isa_device* devices);
> static int gt401probe(struct isa_device* devices);
>
> void gt401intr(int unit);
>
> static int get_lus (int base_io_port, long long *lus);
> static int mux_matrix_connect (int unit,
> u_short src,
> u_short dst);
> static int pulse_out (int unit,
> int enable,
> int src);
> static int removeIntr(int irq);
> static int send_cmd (int unit, u_char *cmd_buf, u_int size);
> static int set_8254 (int unit,
> u_short counter,
> u_short mode,
> u_short initial_count);
> static int set_irq (int unit,
> int enable,
> int src,
> int edge);
> static int setupIntr(struct isa_device* device,
> int irq,
> inthand2_t* hand,
> int unit,
> u_int* maskp);
>
> static int start_tt (int unit);
> static int stop_tt (int unit);
> static int get_tt_count (int unit);
> static int get_tt (int unit, long long *tt);
> static int get_status(int unit);
>
> struct isa_driver gt401driver =3D
> {
> gt401probe,
> gt401attach,
> "gt401"
> };
>
> static d_open_t gt401open;
> static d_close_t gt401close;
> static d_read_t gt401read;
> static d_ioctl_t gt401ioctl;
> static d_select_t gt401select;
>
> static struct cdevsw gt401_cdevsw =3D
> {
> gt401open,
> gt401close,
> gt401read,
> nowrite,
> gt401ioctl,
> nostop,
> nullreset,
> nodevtotty,
> gt401select,
> nommap,
> NULL,
> "gt401",
> NULL,
> -1
> };
>
> struct gt401Unit
> {
> short inuse;
> short tagging_active;
>
> char * sleep_address;
>
> u_char cont_reg1;
> u_char cont_reg2;
> u_char mux_control[8];
> int counts_8254[2];
>
> u_int driver_index;
> u_int max_rbuf_count;
>
> /* rbuf_XXX is a ring buffer for reads */
> short rbuf_count;
> short rbuf_first;
> short rbuf_last;
> gt401_read rbuf [MAX_GT401_RBUF];
> };
>
> #if 1 /* debug */
> static char * save_sleep_address =3D 0;
> #endif
> static struct gt401Unit gt401Unit[NGT401];
>
> static int
> get_lus (int base_io_port, long long *lus)
> {
> char us_count[8] =3D {0};
> char bb[8] =3D {0};
> long long *ll_us =3D (long long *)&(us_count[0]);
> long long *ll_bb =3D (long long *)&(bb[0]);
>
> us_count [0] =3D inb (base_io_port + io_addr_us_count0);
>
> outb((base_io_port + io_addr_ram_addr_reg), dp_ram_lus_page);
>
> inb(base_io_port); /* need a 1us delay */
> inb(base_io_port);
>
> us_count [1] =3D inb (base_io_port + io_addr_us_count1);
>
> bb[0] =3D inb (base_io_port + io_addr_dp_ram + 0);
> bb[1] =3D inb (base_io_port + io_addr_dp_ram + 1);
> bb[2] =3D inb (base_io_port + io_addr_dp_ram + 2);
> bb[3] =3D inb (base_io_port + io_addr_dp_ram + 3);
> bb[4] =3D inb (base_io_port + io_addr_dp_ram + 4);
> bb[5] =3D inb (base_io_port + io_addr_dp_ram + 5);
> bb[6] =3D inb (base_io_port + io_addr_dp_ram + 6);
> bb[7] =3D inb (base_io_port + io_addr_dp_ram + 7);
>
> *lus =3D *ll_bb + *ll_us;
>
> return 0;
> }
>
> static int
> gt401attach(struct isa_device* devices)
> {
> int ii,jj;
>
> uprintf ("gt401attach\n");
>
> for (ii=3D0; ii<NGT401; ++ii)
> {
> gt401Unit[ii].inuse =3D 0;
> gt401Unit[ii].tagging_active =3D 0;
> gt401Unit[ii].sleep_address =3D (char *)&(gt401Unit[ii].inuse);
> gt401Unit[ii].cont_reg1 =3D 0;
> gt401Unit[ii].cont_reg2 =3D 0;
> for (jj=3D0; jj<8; ++jj)
> gt401Unit[ii].mux_control[jj] =3D 0;
> gt401Unit[ii].counts_8254[0] =3D 0;
> gt401Unit[ii].counts_8254[1] =3D 0;
> gt401Unit[ii].driver_index =3D 0;
> gt401Unit[ii].max_rbuf_count =3D 0;
> gt401Unit[ii].rbuf_count =3D 0;
> gt401Unit[ii].rbuf_first =3D 0;
> gt401Unit[ii].rbuf_last =3D MAX_GT401_RBUF - 1;
> for (jj=3D0; jj<MAX_GT401_RBUF; ++jj)
> {
> gt401Unit[ii].rbuf[jj].d_type =3D D_TYPE_NONE;
> gt401Unit[ii].rbuf[jj].overflow =3D 0;
> }
> }
> #if 1 /* debug */
> save_sleep_address =3D gt401Unit[0].sleep_address;
> #endif
> return 1;
> }
>
> static int
> gt401close (dev_t dev,
> int flags,
> int fmt,
> struct proc* p)
> {
> int unit =3D UNIT(dev);
>
> #if 1 /* debug */
> uprintf ("gt401close unit=3D%d\n",unit);
> #endif
>
> gt401Unit[unit].tagging_active =3D 0;
> gt401Unit[unit].inuse =3D 0;
> set_irq (unit,
> 0,
> -1,
> 1);
>
> return 0;
> }
> static int
> gt401ioctl (dev_t dev,
> int cmd,
> caddr_t data,
> int flag,
> struct proc* p)
> {
> int unit =3D UNIT(dev);
>
> if ((unit < 0) || (unit >=3D NGT401))
> return (ENODEV);
>
> if (!(devices[unit].id_alive))
> return (ENODEV);
>
> if (!gt401Unit[unit].inuse)
> return (ENODEV);
>
> switch (cmd)
> {
> case GT401_START_EVENTS:
> {
> int * count_x_10000_i;
> int max_counter =3D 0xffff;
> double period;
> double period_x_10000;
> double target_counts_d;
> int target_counts_i;
>
> #if 0
> stop_tt(unit);
> #endif
>
> count_x_10000_i =3D ((int *)data);
>
> #if 1 /* debug */
> uprintf("gt401ioctl: GT401_START_EVENTS arg=3D%d\n",*count_x_10000_i);
> #endif
>
> if (*count_x_10000_i < MIN_PERIOD_X_10000)
> {
> return (EINVAL);
> }
> if (*count_x_10000_i > MAX_PERIOD_X_10000)
> {
> return (EINVAL);
> }
> period_x_10000 =3D (double)(*count_x_10000_i);
> period =3D period_x_10000 / 10000.;
> target_counts_d =3D period * 10e6;
> target_counts_i =3D (int)target_counts_d;
>
> if (target_counts_i < max_counter)
> {
> gt401Unit[unit].counts_8254[0] =3D target_counts_i;
> gt401Unit[unit].counts_8254[1] =3D 0;
> }
> else
> {
> gt401Unit[unit].counts_8254[0] =3D target_counts_i / max_counter;
> ++gt401Unit[unit].counts_8254[0];
> gt401Unit[unit].counts_8254[1] =3D (target_counts_i
> / gt401Unit[unit].counts_8254[0]);
> }
> #if 1 /* debug */
> uprintf("gt401ioctl: 8254[0]=3D%d 8254[1]=3D%d\n",
> gt401Unit[unit].counts_8254[0],
> gt401Unit[unit].counts_8254[1]);
> #endif
> if (gt401Unit[unit].counts_8254[1] <=3D 0)
> { /* using one 8254 */
> mux_matrix_connect (unit,
> conn_TEN_MHZ,
> conn_CLK1);
> mux_matrix_connect (unit,
> conn_SW_HIGH,
> conn_GATE1);
> set_8254 (unit,
> 1,
> 3,
> gt401Unit[unit].counts_8254[0]);
> set_irq (unit,
> 1,
> conn_OUT1,
> 1);
> } /* using one 8254 */
> else
> { /* using two 8254's */
> mux_matrix_connect (unit,
> conn_TEN_MHZ,
> conn_CLK0);
> mux_matrix_connect (unit,
> conn_SW_HIGH,
> conn_GATE0);
> set_8254 (unit,
> 0,
> 3,
> gt401Unit[unit].counts_8254[0]);
> mux_matrix_connect (unit,
> conn_OUT0,
> conn_CLK1);
> mux_matrix_connect (unit,
> conn_SW_HIGH,
> conn_GATE1);
> set_8254 (unit,
> 1,
> 3,
> gt401Unit[unit].counts_8254[1]);
> set_irq (unit,
> 1,
> conn_OUT1,
> 1);
> } /* using two 8254's */
>
> #if 0 /* debug */
> uprintf("gt401ioctl: disable 8254 clock for debug.\n");
> mux_matrix_connect (unit,
> conn_SW_LOW,
> conn_GATE0);
> mux_matrix_connect (unit,
> conn_SW_LOW,
> conn_GATE1);
> #endif
> gt401Unit[unit].tagging_active =3D 1;
>
> #if 0 /* not yet */
> start_tt(unit);
> #endif
>
> }
> break;
> case GT401_STOP_EVENTS:
> gt401Unit[unit].tagging_active =3D 0;
> #if 1 /* debug */
> uprintf("gt401ioctl: GT401_STOP_EVENTS\n");
> #endif
> #if 0 /* not yet */
> stop_tt(unit);
> #endif
> set_irq (unit,
> 0,
> -1,
> 1);
> break;
> case GT401_GET_HIGH_WATER:
> {
> int * iarg =3D ((int *)data);
> *iarg =3D gt401Unit[unit].max_rbuf_count;
> }
> break;
> case GT401_CLEAR_HIGH_WATER:
> gt401Unit[unit].max_rbuf_count =3D 0;
> break;
> default:
> return (ENODEV);
> break;
> }
> return 0;
> }
>
> void
> gt401intr(int unit)
> {
> int base_io_port;
> int io_cont_reg2;
> long long btime_intr;
> int rbuf_index;
>
> unit =3D 0; /* debug */
> base_io_port =3D devices[0].id_iobase;
> get_lus(base_io_port,&btime_intr);
>
> if (gt401Unit[0].tagging_active =3D=3D 0)
> return;
>
> ++gt401Unit[0].driver_index;
>
> rbuf_index =3D gt401Unit[0].rbuf_last + 1;
> if (rbuf_index >=3D MAX_GT401_RBUF)
> rbuf_index =3D 0;
rbuf_index = (gt401Unit[0].rbuf_last + 1) % MAX_GT401_RBUF;
> if (gt401Unit[0].rbuf_count >=3D MAX_GT401_RBUF)
> {
> gt401Unit[0].rbuf_count =3D MAX_GT401_RBUF - 1;
> ++gt401Unit[0].rbuf_first;
> if(gt401Unit[0].rbuf_first >=3D MAX_GT401_RBUF)
> gt401Unit[0].rbuf_first =3D 0;
> gt401Unit[0].rbuf [gt401Unit[0].rbuf_first].overflow =3D 1;
> }
> gt401Unit[0].rbuf[rbuf_index].d_type =3D D_TYPE_TIMETAG;
> gt401Unit[0].rbuf[rbuf_index].dd.tt.driver_index =3D gt401Unit[0].drive=
> r_index;
> gt401Unit[0].rbuf[rbuf_index].dd.tt.driver_board_usec =3D btime_intr;
> ++gt401Unit[0].rbuf_count;
> gt401Unit[0].rbuf_last =3D rbuf_index;
> if (gt401Unit[0].max_rbuf_count < gt401Unit[0].rbuf_count)
> gt401Unit[0].max_rbuf_count =3D gt401Unit[0].rbuf_count;
>
> io_cont_reg2 =3D base_io_port + io_addr_cont_reg_2;
>
> gt401Unit[0].cont_reg2 &=3D ~(cont_reg2_intr_en_bit);
> outb (io_cont_reg2,
> gt401Unit[0].cont_reg2);
>
> send_cmd (unit, NULL, 0);
>
> if (gt401Unit[0].tagging_active !=3D 0)
> {
> gt401Unit[0].cont_reg2 |=3D cont_reg2_intr_en_bit;
> outb (io_cont_reg2,
> gt401Unit[0].cont_reg2);
> }
> #if 1 /* debug */
> if (gt401Unit[0].sleep_address !=3D save_sleep_address)
> {
> panic("gt401intr: sleep_address %x !=3D %x",
> gt401Unit[0].sleep_address,
> save_sleep_address);
> }
> #endif
> wakeup (gt401Unit[0].sleep_address);
> }
>
> static int
> gt401open (dev_t dev,
> int flags,
> int fmt,
> struct proc* p)
> {
> int unit =3D UNIT(dev);
> int jj;
>
> #if 1 /* debug */
> uprintf("gt401open unit=3D%d\n",unit);
> #endif
>
> if ((unit < 0) || (unit >=3D NGT401))
> return (ENXIO);
>
> if (!(devices[unit].id_alive))
> return (ENXIO);
>
> if (gt401Unit[unit].inuse)
> return (EBUSY);
>
> gt401Unit[unit].inuse =3D 1;
> gt401Unit[unit].tagging_active =3D 0;
> gt401Unit[unit].rbuf_count =3D 0;
> gt401Unit[unit].rbuf_first =3D 0;
> gt401Unit[unit].rbuf_last =3D MAX_GT401_RBUF - 1;
> for (jj=3D0; jj<MAX_GT401_RBUF; ++jj)
> {
> gt401Unit[unit].rbuf[jj].d_type =3D D_TYPE_NONE;
> gt401Unit[unit].rbuf[jj].overflow =3D 0;
> }
>
> #if 1 /* debug */
> {
> int addr =3D devices[unit].id_iobase;
> uprintf("gt401open unit=3D%d io_addr=3D0x%x\n",unit,addr);
> }
> #endif
>
> return 0;
> }
>
> static int
> gt401probe(struct isa_device* devices)
> {
> int addr =3D 0x100;
> int ii;
> long long time_check[9];
> long long time_diffs[8];
> int units =3D 0;
> long long duration_max;
> long long duration_min;
> long long min_max_range;
> long long min_max_range_check;
>
> for (ii=3D0; ii<NGT401; ++ii)
> {
> devices[ii].id_alive =3D 0;
> devices[ii].id_enabled =3D 0;
> }
>
> /* check for gt401 at addr by reading it's time */
> for (ii=3D0; ii<9; ++ii)
> {
> get_lus (addr,&(time_check[ii]));
> tsleep (&ii, PZERO, "gt401", 10);
> }
>
> for (ii=3D1; ii<9; ++ii)
> {
> time_diffs[ii-1] =3D time_check[ii] - time_check[ii-1];
> }
> duration_max =3D duration_min =3D time_diffs[0];
> for (ii=3D0; ii<8; ++ii)
> {
> if (duration_max < time_diffs[ii])
> duration_max =3D time_diffs[ii];
> if (duration_min > time_diffs[ii])
> duration_min =3D time_diffs[ii];
> }
> min_max_range_check =3D duration_min / 2;
> min_max_range =3D duration_max - duration_min;
>
> #if 1 /* debug */
> uprintf("gt401probe addr 0x%x min %d max %d check %d range %d\n",
> addr,
> (int)duration_min,
> (int)duration_max,
> (int)min_max_range_check,
> (int)min_max_range);
> #endif
>
> if (duration_min < 5000)
> {
> uprintf("gt401probe time diff too small\n");
> return 0;
> }
> if (min_max_range > min_max_range_check)
> {
> uprintf("gt401probe time diff too variable\n");
> return 0;
> }
>
> devices[0].id_unit =3D 0;
> devices[0].id_iobase =3D addr;
> devices[0].id_driver =3D >401driver;
> devices[0].id_irq =3D 0;
> devices[0].id_intr =3D gt401intr;
> devices[0].id_drq =3D -1;
> #if 0 /* debug */
> devices[0].id_ri_flags =3D RI_FAST;
You do not want to do this with your current architecture; you can
never call wakeup() from inside a fast interrupt handler.
> #endif
>
> devices[0].id_alive =3D 1;
> devices[0].id_enabled =3D 1;
>
> ++units;
>
> return units;
> }
>
> static int
> gt401read (dev_t dev,
> struct uio* uio,
> int flag)
> {
> int left_to_move =3D 0;
> int status;
> int unit =3D UNIT(dev);
> int i_timeout =3D hz / 4;
>
> if ((unit < 0) || (unit >=3D NGT401))
> return (ENODEV);
> if (!(devices[0].id_alive))
> return (ENODEV);
> if (!gt401Unit[0].inuse)
> return (ENODEV);
>
> disable_intr();
This is very bad; don't do this. Add the driver to one of the
'standard' interrupt masks and then use splfoo(), or create your own
interrupt mask.
> for (;;)
> {
> if (gt401Unit[0].rbuf_count > 0)
> break;
> enable_intr();
... because there is a race window here.
> status =3D tsleep (gt401Unit[0].sleep_address,
> (PSWP | PCATCH),
> "gt401",
> i_timeout);
> if (!((status =3D=3D 0)
> || (status =3D=3D EWOULDBLOCK)))
> {
> return (status);
> }
> disable_intr();
> }
>
> left_to_move =3D uio->uio_resid / sizeof(struct gt401_read_s);
>
> while (left_to_move > 0)
> {
> if (gt401Unit[0].rbuf_count <=3D 0)
> break;
>
> status =3D uiomove((caddr_t)&(gt401Unit[0].rbuf[gt401Unit[0].rbuf_f=
> irst]),
> sizeof(struct gt401_read_s),
> uio);
> if (status)
> {
> enable_intr();
> return (EFAULT);
> }
>
> --left_to_move;
>
> --gt401Unit[0].rbuf_count;
> ++gt401Unit[0].rbuf_first;
> if(gt401Unit[0].rbuf_first >=3D MAX_GT401_RBUF)
> gt401Unit[0].rbuf_first =3D 0;
gt401Unit[0].rbuf_first = (gt401Unit[0].rbuf_first + 1) % MAX_GT401_RBUF;
> if (gt401Unit[0].rbuf_count <=3D 0)
> break;
> }
>
> enable_intr();
> return 0;
> }
Actually, you can simplify this drastically; there's no need to lock the
ringbuffer unless you are particularly concerned about the overflow
case. Disabling interrupts for a long time like you do here may cause
loss of timer interrupts, as well as the race above.
static int
gt401read (dev_t dev,
struct uio* uio,
int flag)
{
int left_to_move = 0;
int status;
int unit = UNIT(dev);
int i_timeout = hz / 4;
int s, ofs;
if ((unit < 0) || (unit >= NGT401))
return (ENODEV);
if (!(devices[0].id_alive))
return (ENODEV);
if (!gt401Unit[0].inuse)
return (ENODEV);
s = splfoo();
while (gt401Unit[0].rbuf_count == 0) {
status = tsleep(gt401Unit[0].sleep_address,
PRIBIO | PCATCH,
"gt401",
i_timeout);
if (!((status == 0) || (status == EWOULDBLOCK))) {
splx(s);
return(status);
}
}
splx(s);
left_to_move = min(gt401Unit[0].rbuf_count,
(uio->uio_resid / sizeof(struct gt401_read_s));
ofs = gt401Unit[0].rbuf_first;
for (; left_to_move > 0; left_to_move --) {
if (uiomove((caddr_t)>401Unit[0].rbuf[ofs],
sizeof(struct gt401_read_s, uio)
return(EFAULT);
ofs = (ofs + 1) % GT401_MAX_RBUF;
gt401Unit[0].rbuf_count--;
}
gt401Unit[0].rbuf_first = ofs;
return(0);
}
> static int
> gt401select (dev_t dev,
> int rw,
> struct proc* p)
> {
> return 0;
> }
>
> /*
> * =
>
> */
> #ifdef GT401_MODULE
>
> #include <sys/exec.h>
> #include <sys/sysent.h>
> #include <sys/sysproto.h>
> #include <sys/lkm.h>
>
> MOD_DEV(gt401, LM_DT_CHAR, CDEV_MAJOR, >401_cdevsw);
>
> int =
>
> gt401_load(struct lkm_table* lkmtp, int cmd)
> {
> int units;
> int irq =3D 11;
> int istat;
>
> uprintf("Gt401 driver loading, capable of %d board(s)\n", NGT401);
>
> units =3D gt401probe (&devices[0]);
> if (units <=3D 0)
> {
> uprintf("gt401 driver: probe failed\n");
> return (1);
> }
>
> gt401attach (&devices[0]);
>
> istat =3D setupIntr (&devices[0],
> irq,
> gt401intr,
> 0,
> NULL);
> if (istat !=3D irq)
> {
> uprintf ("gt401 driver: INT %d register failed\n",irq);
> return (1);
> }
>
> return (0);
> }
>
> int
> gt401_unload(struct lkm_table* lkmtp, int cmd)
> {
> int unit;
>
> uprintf("Gt401 driver unloading...\n");
>
> for (unit=3D0; unit<NGT401; ++unit)
> {
> if (devices[unit].id_alive =3D=3D 1)
> {
> /** disable interrupts on board */
>
> if (devices[unit].id_irq !=3D 0)
> {
> uprintf ("removeINTR 0x%x\n",(ffs(devices[unit].id_irq) - 1));
> removeIntr(ffs(devices[unit].id_irq) - 1);
> }
> }
> }
>
> return (0);
> }
>
> /** XXX: /usr/include/lkm.h fails to define this: */
> int gt401_stat(struct lkm_table* lkmtp, int cmd);
> int
> gt401_stat(struct lkm_table* lkmtp, int cmd)
> {
> return (0);
> }
>
> int
> gt401_mod(struct lkm_table* lkmtp, int cmd, int ver)
> {
> DISPATCH(lkmtp, cmd, ver, gt401_load, gt401_unload, gt401_stat);
> }
>
> #endif /* GT401_MODULE */
>
> static int
> mux_matrix_connect (int unit,
> u_short src,
> u_short dst)
> {
> int base_io_port;
> int err;
> u_short mux_addr_reg;
> u_char mux_addr_reg_val;
> u_short mux_data_reg;
> u_char src_val;
>
> base_io_port =3D devices[unit].id_iobase;
>
> err =3D 0;
>
> mux_addr_reg =3D base_io_port + io_addr_mux_addr_reg;
> mux_data_reg =3D base_io_port + io_addr_mux_data_reg;
>
> // verify that dst is valid
> switch (dst)
> {
> case conn_IO_CHAN0:
> case conn_IO_CHAN1:
> case conn_IO_CHAN2:
> case conn_IO_CHAN3:
> case conn_EXT_CHAN0:
> case conn_EXT_CHAN1:
> case conn_EXT_CHAN2:
> case conn_EXT_CHAN3:
> case conn_CLK0:
> case conn_CLK1:
> case conn_CLK2:
> case conn_GATE0:
> case conn_GATE1:
> case conn_GATE2:
> break;
> default:
> err =3D err_connect_dst;
> return err;
> }
>
> // verify that src is valid
> switch (dst)
> {
> case conn_IO_CHAN0:
> case conn_IO_CHAN1:
> case conn_IO_CHAN2:
> case conn_IO_CHAN3:
> switch (src)
> {
> case conn_EXT_CHAN0:
> src_val =3D 0;
> break;
> case conn_EXT_CHAN1:
> src_val =3D 1;
> break;
> case conn_EXT_CHAN2:
> src_val =3D 2;
> break;
> case conn_EXT_CHAN3:
> src_val =3D 3;
> break;
> case conn_OUT0:
> src_val =3D 4;
> break;
> case conn_OUT1:
> src_val =3D 5;
> break;
> case conn_OUT2:
> src_val =3D 6;
> break;
> case conn_SW_LOW:
> src_val =3D 7;
> break;
> case conn_SW_HIGH:
> src_val =3D 7;
> break;
> default:
> err =3D err_connect_src;
> return err;
> }
> break;
> case conn_EXT_CHAN0:
> if (src !=3D conn_IO_CHAN0)
> {
> err =3D err_connect_src;
> return err;
> }
> break;
> case conn_EXT_CHAN1:
> if (src !=3D conn_IO_CHAN1)
> {
> err =3D err_connect_src;
> return err;
> }
> break;
> case conn_EXT_CHAN2:
> if (src !=3D conn_IO_CHAN2)
> {
> err =3D err_connect_src;
> return err;
> }
> break;
> case conn_EXT_CHAN3:
> if (src !=3D conn_IO_CHAN3)
> {
> err =3D err_connect_src;
> return err;
> }
> break;
> case conn_CLK0:
> switch (src)
> {
> case conn_IO_CHAN0:
> src_val =3D 0;
> break;
> case conn_IO_CHAN1:
> src_val =3D 1;
> break;
> case conn_IO_CHAN2:
> src_val =3D 2;
> break;
> case conn_IO_CHAN3:
> src_val =3D 3;
> break;
> case conn_OUT2:
> src_val =3D 4;
> break;
> case conn_TEN_MHZ:
> src_val =3D 5;
> break;
> case conn_GATED_TEN_MHZ:
> src_val =3D 6;
> break;
> case conn_EXT_CLK2:
> src_val =3D 7;
> break;
> default:
> err =3D err_connect_dst;
> return err;
> }
> break;
> case conn_CLK1:
> switch (src)
> {
> case conn_IO_CHAN0:
> src_val =3D 0;
> break;
> case conn_IO_CHAN1:
> src_val =3D 1;
> break;
> case conn_IO_CHAN2:
> src_val =3D 2;
> break;
> case conn_IO_CHAN3:
> src_val =3D 3;
> break;
> case conn_OUT0:
> src_val =3D 4;
> break;
> case conn_TEN_MHZ:
> src_val =3D 5;
> break;
> case conn_GATED_TEN_MHZ:
> src_val =3D 6;
> break;
> case conn_EXT_CLK2:
> src_val =3D 7;
> break;
> default:
> err =3D err_connect_dst;
> return err;
> }
> break;
> case conn_CLK2:
> switch (src)
> {
> case conn_IO_CHAN0:
> src_val =3D 0;
> break;
> case conn_IO_CHAN1:
> src_val =3D 1;
> break;
> case conn_IO_CHAN2:
> src_val =3D 2;
> break;
> case conn_IO_CHAN3:
> src_val =3D 3;
> break;
> case conn_OUT1:
> src_val =3D 4;
> break;
> case conn_TEN_MHZ:
> src_val =3D 5;
> break;
> case conn_GATED_TEN_MHZ:
> src_val =3D 6;
> break;
> case conn_EXT_CLK2:
> src_val =3D 7;
> break;
> default:
> err =3D err_connect_dst;
> return err;
> }
> break;
> case conn_GATE0:
> switch (src)
> {
> case conn_IO_CHAN0:
> src_val =3D 0;
> break;
> case conn_IO_CHAN1:
> src_val =3D 1;
> break;
> case conn_IO_CHAN2:
> src_val =3D 2;
> break;
> case conn_IO_CHAN3:
> src_val =3D 3;
> break;
> case conn_OUT1:
> src_val =3D 4;
> break;
> case conn_OUT2:
> src_val =3D 5;
> break;
> case conn_SW_LOW:
> src_val =3D 6;
> break;
> case conn_SW_HIGH:
> src_val =3D 6;
> break;
> case conn_EXT_GATE0:
> src_val =3D 7;
> break;
> default:
> err =3D err_connect_dst;
> return err;
> }
> break;
> case conn_GATE1:
> switch (src)
> {
> case conn_IO_CHAN0:
> src_val =3D 0;
> break;
> case conn_IO_CHAN1:
> src_val =3D 1;
> break;
> case conn_IO_CHAN2:
> src_val =3D 2;
> break;
> case conn_IO_CHAN3:
> src_val =3D 3;
> break;
> case conn_OUT0:
> src_val =3D 5;
> break;
> case conn_OUT2:
> src_val =3D 4;
> break;
> case conn_SW_LOW:
> src_val =3D 6;
> break;
> case conn_SW_HIGH:
> src_val =3D 6;
> break;
> case conn_EXT_GATE1:
> src_val =3D 7;
> break;
> default:
> err =3D err_connect_dst;
> return err;
> }
> break;
> case conn_GATE2:
> switch (src)
> {
> case conn_IO_CHAN0:
> src_val =3D 0;
> break;
> case conn_IO_CHAN1:
> src_val =3D 1;
> break;
> case conn_IO_CHAN2:
> src_val =3D 2;
> break;
> case conn_IO_CHAN3:
> src_val =3D 3;
> break;
> case conn_OUT0:
> src_val =3D 4;
> break;
> case conn_OUT1:
> src_val =3D 5;
> break;
> case conn_SW_LOW:
> src_val =3D 6;
> break;
> case conn_SW_HIGH:
> src_val =3D 6;
> break;
> case conn_EXT_GATE2:
> src_val =3D 7;
> break;
> default:
> err =3D err_connect_dst;
> return err;
> }
> break;
> }
>
> // handle sw set gate and chan
> switch (src)
> {
> case conn_SW_LOW:
> switch (dst)
> {
> case conn_IO_CHAN0:
> mux_addr_reg_val =3D 6;
> outb (mux_addr_reg, mux_addr_reg_val);
> gt401Unit[unit].mux_control[mux_addr_reg_val] &=3D (~1);
> outb(mux_data_reg, gt401Unit[unit].mux_control[mux_addr_reg_val]);
> break;
> case conn_IO_CHAN1:
> mux_addr_reg_val =3D 6;
> outb (mux_addr_reg, mux_addr_reg_val);
> gt401Unit[unit].mux_control[mux_addr_reg_val] &=3D (~2);
> outb(mux_data_reg, gt401Unit[unit].mux_control[mux_addr_reg_val]);
> break;
> case conn_IO_CHAN2:
> mux_addr_reg_val =3D 6;
> outb (mux_addr_reg, mux_addr_reg_val);
> gt401Unit[unit].mux_control[mux_addr_reg_val] &=3D (~4);
> outb(mux_data_reg, gt401Unit[unit].mux_control[mux_addr_reg_val]);
> break;
> case conn_IO_CHAN3:
> mux_addr_reg_val =3D 6;
> outb (mux_addr_reg, mux_addr_reg_val);
> gt401Unit[unit].mux_control[mux_addr_reg_val] &=3D (~8);
> outb(mux_data_reg, gt401Unit[unit].mux_control[mux_addr_reg_val]);
> break;
> case conn_GATE0:
> mux_addr_reg_val =3D 3;
> outb (mux_addr_reg, mux_addr_reg_val);
> gt401Unit[unit].mux_control[mux_addr_reg_val] &=3D (~1);
> outb(mux_data_reg, gt401Unit[unit].mux_control[mux_addr_reg_val]);
> break;
> case conn_GATE1:
> mux_addr_reg_val =3D 3;
> outb (mux_addr_reg, mux_addr_reg_val);
> gt401Unit[unit].mux_control[mux_addr_reg_val] &=3D (~2);
> outb(mux_data_reg, gt401Unit[unit].mux_control[mux_addr_reg_val]);
> break;
> case conn_GATE2:
> mux_addr_reg_val =3D 3;
> outb (mux_addr_reg, mux_addr_reg_val);
> gt401Unit[unit].mux_control[mux_addr_reg_val] &=3D (~4);
> outb(mux_data_reg, gt401Unit[unit].mux_control[mux_addr_reg_val]);
> break;
> }
> break;
> case conn_SW_HIGH:
> switch (dst)
> {
> case conn_IO_CHAN0:
> mux_addr_reg_val =3D 6;
> outb (mux_addr_reg, mux_addr_reg_val);
> gt401Unit[unit].mux_control[mux_addr_reg_val] |=3D 1;
> outb(mux_data_reg, gt401Unit[unit].mux_control[mux_addr_reg_val]);
> break;
> case conn_IO_CHAN1:
> mux_addr_reg_val =3D 6;
> outb (mux_addr_reg, mux_addr_reg_val);
> gt401Unit[unit].mux_control[mux_addr_reg_val] |=3D 2;
> outb(mux_data_reg, gt401Unit[unit].mux_control[mux_addr_reg_val]);
> break;
> case conn_IO_CHAN2:
> mux_addr_reg_val =3D 6;
> outb (mux_addr_reg, mux_addr_reg_val);
> gt401Unit[unit].mux_control[mux_addr_reg_val] |=3D 4;
> outb(mux_data_reg, gt401Unit[unit].mux_control[mux_addr_reg_val]);
> break;
> case conn_IO_CHAN3:
> mux_addr_reg_val =3D 6;
> outb (mux_addr_reg, mux_addr_reg_val);
> gt401Unit[unit].mux_control[mux_addr_reg_val] |=3D 8;
> outb(mux_data_reg, gt401Unit[unit].mux_control[mux_addr_reg_val]);
> break;
> case conn_GATE0:
> mux_addr_reg_val =3D 3;
> outb (mux_addr_reg, mux_addr_reg_val);
> gt401Unit[unit].mux_control[mux_addr_reg_val] |=3D 1;
> outb(mux_data_reg, gt401Unit[unit].mux_control[mux_addr_reg_val]);
> break;
> case conn_GATE1:
> mux_addr_reg_val =3D 3;
> outb (mux_addr_reg, mux_addr_reg_val);
> gt401Unit[unit].mux_control[mux_addr_reg_val] |=3D 2;
> outb(mux_data_reg, gt401Unit[unit].mux_control[mux_addr_reg_val]);
> break;
> case conn_GATE2:
> mux_addr_reg_val =3D 3;
> outb (mux_addr_reg, mux_addr_reg_val);
> gt401Unit[unit].mux_control[mux_addr_reg_val] |=3D 4;
> outb(mux_data_reg, gt401Unit[unit].mux_control[mux_addr_reg_val]);
> break;
> }
> break;
> }
>
> // make the connection
>
> switch (dst)
> {
> case conn_IO_CHAN0:
> mux_addr_reg_val =3D 4;
> outb (mux_addr_reg, mux_addr_reg_val);
> gt401Unit[unit].mux_control[mux_addr_reg_val] &=3D ~7;
> gt401Unit[unit].mux_control[mux_addr_reg_val] |=3D src_val;
> outb(mux_data_reg, gt401Unit[unit].mux_control[mux_addr_reg_val]);
>
> mux_addr_reg_val =3D 7;
> outb (mux_addr_reg, mux_addr_reg_val);
> gt401Unit[unit].mux_control[mux_addr_reg_val] &=3D ~1;
> outb(mux_data_reg, gt401Unit[unit].mux_control[mux_addr_reg_val]);
> break;
> case conn_IO_CHAN1:
> mux_addr_reg_val =3D 4;
> outb (mux_addr_reg, mux_addr_reg_val);
> gt401Unit[unit].mux_control[mux_addr_reg_val] &=3D ~0x38;
> gt401Unit[unit].mux_control[mux_addr_reg_val] |=3D (src_val << 3);
> outb(mux_data_reg, gt401Unit[unit].mux_control[mux_addr_reg_val]);
>
> mux_addr_reg_val =3D 7;
> outb (mux_addr_reg, mux_addr_reg_val);
> gt401Unit[unit].mux_control[mux_addr_reg_val] &=3D ~2;
> outb(mux_data_reg, gt401Unit[unit].mux_control[mux_addr_reg_val]);
> break;
> case conn_IO_CHAN2:
> mux_addr_reg_val =3D 5;
> outb (mux_addr_reg, mux_addr_reg_val);
> gt401Unit[unit].mux_control[mux_addr_reg_val] &=3D ~7;
> gt401Unit[unit].mux_control[mux_addr_reg_val] |=3D src_val;
> outb(mux_data_reg, gt401Unit[unit].mux_control[mux_addr_reg_val]);
>
> mux_addr_reg_val =3D 7;
> outb (mux_addr_reg, mux_addr_reg_val);
> gt401Unit[unit].mux_control[mux_addr_reg_val] &=3D ~4;
> outb(mux_data_reg, gt401Unit[unit].mux_control[mux_addr_reg_val]);
> break;
> case conn_IO_CHAN3:
> mux_addr_reg_val =3D 5;
> outb (mux_addr_reg, mux_addr_reg_val);
> gt401Unit[unit].mux_control[mux_addr_reg_val] &=3D ~0x38;
> gt401Unit[unit].mux_control[mux_addr_reg_val] |=3D (src_val << 3);
> outb(mux_data_reg, gt401Unit[unit].mux_control[mux_addr_reg_val]);
>
> mux_addr_reg_val =3D 7;
> outb (mux_addr_reg, mux_addr_reg_val);
> gt401Unit[unit].mux_control[mux_addr_reg_val] &=3D ~8;
> outb(mux_data_reg, gt401Unit[unit].mux_control[mux_addr_reg_val]);
> break;
>
> case conn_EXT_CHAN0:
> mux_addr_reg_val =3D 7;
> outb (mux_addr_reg, mux_addr_reg_val);
> gt401Unit[unit].mux_control[mux_addr_reg_val] |=3D 1;
> outb(mux_data_reg, gt401Unit[unit].mux_control[mux_addr_reg_val]);
> break;
> case conn_EXT_CHAN1:
> mux_addr_reg_val =3D 7;
> outb (mux_addr_reg, mux_addr_reg_val);
> gt401Unit[unit].mux_control[mux_addr_reg_val] |=3D 2;
> outb(mux_data_reg, gt401Unit[unit].mux_control[mux_addr_reg_val]);
> break;
> case conn_EXT_CHAN2:
> mux_addr_reg_val =3D 7;
> outb (mux_addr_reg, mux_addr_reg_val);
> gt401Unit[unit].mux_control[mux_addr_reg_val] |=3D 4;
> outb(mux_data_reg, gt401Unit[unit].mux_control[mux_addr_reg_val]);
> break;
> case conn_EXT_CHAN3:
> mux_addr_reg_val =3D 7;
> outb (mux_addr_reg, mux_addr_reg_val);
> gt401Unit[unit].mux_control[mux_addr_reg_val] |=3D 8;
> outb(mux_data_reg, gt401Unit[unit].mux_control[mux_addr_reg_val]);
> break;
>
> case conn_CLK0:
> mux_addr_reg_val =3D 0;
> outb (mux_addr_reg, mux_addr_reg_val);
> gt401Unit[unit].mux_control[mux_addr_reg_val] &=3D (~7);
> gt401Unit[unit].mux_control[mux_addr_reg_val] |=3D src_val;
> outb(mux_data_reg, gt401Unit[unit].mux_control[mux_addr_reg_val]);
> break;
> case conn_CLK1:
> mux_addr_reg_val =3D 1;
> outb (mux_addr_reg, mux_addr_reg_val);
> gt401Unit[unit].mux_control[mux_addr_reg_val] &=3D (~7);
> gt401Unit[unit].mux_control[mux_addr_reg_val] |=3D src_val;
> outb(mux_data_reg, gt401Unit[unit].mux_control[mux_addr_reg_val]);
> break;
> case conn_CLK2:
> mux_addr_reg_val =3D 2;
> outb (mux_addr_reg, mux_addr_reg_val);
> gt401Unit[unit].mux_control[mux_addr_reg_val] &=3D (~7);
> gt401Unit[unit].mux_control[mux_addr_reg_val] |=3D src_val;
> outb(mux_data_reg, gt401Unit[unit].mux_control[mux_addr_reg_val]);
> break;
> case conn_GATE0:
> mux_addr_reg_val =3D 0;
> outb (mux_addr_reg, mux_addr_reg_val);
> gt401Unit[unit].mux_control[mux_addr_reg_val] &=3D (~0x38);
> gt401Unit[unit].mux_control[mux_addr_reg_val] |=3D (src_val << 3);
> outb(mux_data_reg, gt401Unit[unit].mux_control[mux_addr_reg_val]);
> break;
> case conn_GATE1:
> mux_addr_reg_val =3D 1;
> outb (mux_addr_reg, mux_addr_reg_val);
> gt401Unit[unit].mux_control[mux_addr_reg_val] &=3D (~0x38);
> gt401Unit[unit].mux_control[mux_addr_reg_val] |=3D (src_val << 3);
> outb(mux_data_reg, gt401Unit[unit].mux_control[mux_addr_reg_val]);
> break;
> case conn_GATE2:
> mux_addr_reg_val =3D 2;
> outb (mux_addr_reg, mux_addr_reg_val);
> gt401Unit[unit].mux_control[mux_addr_reg_val] &=3D (~0x38);
> gt401Unit[unit].mux_control[mux_addr_reg_val] |=3D (src_val << 3);
> outb(mux_data_reg, gt401Unit[unit].mux_control[mux_addr_reg_val]);
> break;
> }
>
> return err;
> }
>
> static int
> pulse_out (int unit,
> int enable,
> int src)
> {
> int base_io_port;
> u_short cont_reg1;
> int err;
> u_char src_code;
>
> base_io_port =3D devices[unit].id_iobase;
> err =3D err_success;
>
> cont_reg1 =3D base_io_port + io_addr_cont_reg_1;
> if (enable =3D=3D 0)
> { /* disable pulse output */
> gt401Unit[unit].cont_reg1 &=3D (~cont_reg1_pulse_en);
> outb (cont_reg1, gt401Unit[unit].cont_reg1);
> return err;
> }
>
> // enable pulse output
> switch (src)
> {
> case conn_IO_CHAN0:
> src_code =3D 0;
> break;
> case conn_IO_CHAN1:
> src_code =3D 1;
> break;
> case conn_IO_CHAN2:
> src_code =3D 2;
> break;
> case conn_IO_CHAN3:
> src_code =3D 3;
> break;
> case conn_SW_LOW:
> case conn_SW_HIGH:
> src_code =3D 4;
> break;
> case conn_OUT0:
> src_code =3D 5;
> break;
> case conn_OUT1:
> src_code =3D 6;
> break;
> case conn_OUT2:
> src_code =3D 7;
> break;
> default:
> err =3D err_connect_src;
> return err;
> }
>
> gt401Unit[unit].cont_reg1 &=3D cont_reg1_src_mask;
> gt401Unit[unit].cont_reg1 |=3D src_code;
>
> switch (src)
> {
> case conn_SW_LOW:
> gt401Unit[unit].cont_reg1 &=3D (~cont_reg1_sw_pulse);
> break;
> case conn_SW_HIGH:
> gt401Unit[unit].cont_reg1 |=3D cont_reg1_sw_pulse;
> break;
> }
>
> outb (cont_reg1,
> gt401Unit[unit].cont_reg1);
>
> tsleep (&err, PZERO, "gt401", 100);
>
> gt401Unit[unit].cont_reg1 |=3D cont_reg1_pulse_en; // then enable pulse=
> out
>
> outb (cont_reg1,
> gt401Unit[unit].cont_reg1);
>
> return err;
> }
>
> static int
> set_irq (int unit,
> int enable,
> int src,
> int edge)
> {
> int base_io_port;
> int err;
> int io_cont_reg2;
> int src_code;
>
> base_io_port =3D devices[unit].id_iobase;
> err =3D err_success;
>
> io_cont_reg2 =3D base_io_port + io_addr_cont_reg_2;
>
> if (enable =3D=3D 0)
> { /* turn off interrupts */
> gt401Unit[unit].cont_reg2 &=3D ~(cont_reg2_intr_en_bit);
> #if 0 /* debug */
> printf ("outb (%x,%x)\n",
> io_cont_reg2,
> gt401Unit[unit].cont_reg2);
> #endif
> outb (io_cont_reg2,
> gt401Unit[unit].cont_reg2);
> return err;
> } /* turn off interrupts */
>
> /* turn on interrupts */
> switch (src)
> {
> case conn_IO_CHAN0:
> src_code =3D cont_reg2_irq_src_chan0;
> break;
> case conn_IO_CHAN1:
> src_code =3D cont_reg2_irq_src_chan1;
> break;
> case conn_IO_CHAN2:
> src_code =3D cont_reg2_irq_src_chan2;
> break;
> case conn_IO_CHAN3:
> src_code =3D cont_reg2_irq_src_chan3;
> break;
> case conn_OUT0:
> src_code =3D cont_reg2_irq_src_out0;
> break;
> case conn_OUT1:
> src_code =3D cont_reg2_irq_src_out1;
> break;
> case conn_OUT2:
> src_code =3D cont_reg2_irq_src_out2;
> break;
> default:
> err =3D err_irq_src;
> return err;
> }
> gt401Unit[unit].cont_reg2 &=3D ~(cont_reg2_irq_src_mask);
> gt401Unit[unit].cont_reg2 |=3D src_code;
>
> if (edge =3D=3D 0)
> gt401Unit[unit].cont_reg2 &=3D ~(cont_reg2_intr_edge_bit);
> else
> gt401Unit[unit].cont_reg2 |=3D cont_reg2_intr_edge_bit;
>
> gt401Unit[unit].cont_reg2 &=3D ~(cont_reg2_intr_en_bit);
> #if 0 /* debug */
> printf ("outb (%x,%x)\n",
> io_cont_reg2,
> gt401Unit[unit].cont_reg2);
> #endif
> outb (io_cont_reg2,
> gt401Unit[unit].cont_reg2);
>
> gt401Unit[unit].cont_reg2 |=3D cont_reg2_intr_en_bit;
> #if 0 /* debug */
> printf ("outb (%x,%x)\n",
> io_cont_reg2,
> gt401Unit[unit].cont_reg2);
> #endif
> outb (io_cont_reg2,
> gt401Unit[unit].cont_reg2);
>
> return err;
> }
>
> /*
> * Register the appropriate INTerrupt.
> */
> static int
> setupIntr(struct isa_device* device,
> int irq, inthand2_t* hand, int unit, u_int* maskp)
> {
> u_int mask;
> u_int flags;
>
> mask =3D 1ul << irq;
> flags =3D device->id_ri_flags;
>
> if (maskp)
> INTRMASK(*maskp, mask);
>
> if (register_intr(irq, 0, flags, hand, maskp, unit) =3D=3D 0) {
> device->id_irq =3D mask;
> INTREN(mask);
> return (irq);
> }
>
> if (maskp)
> INTRUNMASK(*maskp, mask);
>
> return (-1);
> }
>
>
> /*
> * Unregister the appropriate INTerrupt.
> */
> static int
> removeIntr(int irq)
> {
> if (unregister_intr(irq, intr_handler[irq])) {
> uprintf("\tINT #%d failed to unregister\n", irq);
> return (EPERM);
> }
> else {
> INTRDIS(1 << irq);
> uprintf("\tINT #%d unregistered\n", irq);
> return (0);
> }
> }
>
> static int
> send_cmd (int unit, u_char *cmd_buf, u_int size)
> {
> int base_io_port;
> u_short cmd_ready_reg;
> u_short dual_port_bank_index;
> u_short dual_port_bank_reg;
> u_short dual_port_data_reg;
> int err;
> int ii;
> int jj;
> u_short status_reg;
> u_char status_val;
> int ready;
> int ready_loop_max =3D 5000;
>
> err =3D err_success;
>
> base_io_port =3D devices[unit].id_iobase;
>
> // Wait for command ready bit
> status_reg =3D base_io_port + io_addr_status_reg;
> ready =3D 0;
> for (ii=3D0; ii<cmd_poll_sleep_loop; ++ii)
> {
> for (jj=3D0; jj<cmd_poll_inner_loop; ++jj)
> {
> if (jj > ready_loop_max)
> break;
> status_val =3D inb(status_reg);
> if ((status_val & status_reg_ready_for_cmd) !=3D 0)
> {
> ready =3D 1;
> break;
> }
> }
> if (ready)
> break;
> }
> if (!ready)
> {
> err =3D err_timeout;
> return err;
> }
> if (size =3D=3D 0)
> {
> return err;
> }
> if (size > cmd_buf_sz)
> {
> err =3D err_cmd_sz;
> return err;
> }
>
> // place command bytes into dual port ram
> dual_port_bank_reg =3D base_io_port + io_addr_ram_addr_reg;
> dual_port_bank_index =3D dp_ram_command_first_page;
> for (ii=3D0; ii<size; )
> {
> dual_port_data_reg =3D base_io_port + io_addr_dp_ram;
> outb(dual_port_bank_reg, dual_port_bank_index);
>
> for (jj=3D0; jj<8; ++jj)
> { // 8 bytes in each bank
> outb(dual_port_data_reg, cmd_buf[ii]);
> ++ii;
> if (ii >=3D size)
> break;
> ++dual_port_data_reg;
> }
> if (ii >=3D size)
> break;
> ++dual_port_bank_index;
> }
>
> // signal command
> cmd_ready_reg =3D base_io_port + io_addr_cmd_ready;
> outb(cmd_ready_reg, 0);
>
> return err;
> }
>
> static int
> set_8254 (int unit,
> u_short counter,
> u_short mode,
> u_short initial_count)
> {
> u_short addr54;
> int base_io_port;
> u_char control_byte;
> int err;
> u_char ic_hi;
> u_char ic_lo;
> u_short i8254_data_reg;
> u_short mux_addr_reg;
>
> err =3D err_success;
>
> base_io_port =3D devices[unit].id_iobase;
>
> switch (counter)
> {
> case 0:
> addr54 =3D mux_54_ctr_0;
> break;
> case 1:
> addr54 =3D mux_54_ctr_1;
> break;
> case 2:
> addr54 =3D mux_54_ctr_2;
> break;
> default:
> err =3D err_invalid_8254_ctr;
> return err;
> }
>
> mux_addr_reg =3D base_io_port + io_addr_mux_addr_reg;
> i8254_data_reg =3D base_io_port + io_addr_8254_data_reg;
>
> control_byte =3D 0;
> control_byte |=3D ((counter & 3) << 6);
> control_byte |=3D (3 << 4);
> control_byte |=3D ((mode & 7) << 1);
> // BCD bit is 0, meaning counter it 16 bit unsigned binary
>
> outb(mux_addr_reg, mux_54_cont); // map in 8254 control register
> outb(i8254_data_reg, control_byte);
> outb(mux_addr_reg, addr54); // map in 8254 counter register.
>
> ic_lo =3D initial_count & 0xff;
> ic_hi =3D (initial_count >> 8) & 0xff;
>
> outb(i8254_data_reg, ic_lo);
> outb(i8254_data_reg, ic_hi);
>
> return err;
> }
>
> static int start_tt (int unit)
> {
> u_char cmd_buf[8] =3D {0};
> int istat;
>
> cmd_buf[0] =3D cmd_clr_err;
> send_cmd(unit,cmd_buf,1);
> istat =3D get_status(unit);
> printf ("start_tt after clr_err stat=3D%d\n",istat);
>
> cmd_buf[0] =3D cmd_tt_size;
> cmd_buf[1] =3D 12;
> cmd_buf[2] =3D 0; /* no wrap */
> send_cmd(unit, cmd_buf, 3);
> istat =3D get_status(unit);
> printf ("start_tt tt_size stat=3D%d\n",istat);
>
> cmd_buf[0] =3D cmd_tt;
> cmd_buf[1] =3D tt_edge_pos; /* chan=3D0 << 6 | edge */
> send_cmd(unit, cmd_buf, 2);
> istat =3D get_status(unit);
> printf ("start_tt tt stat=3D%d\n",istat);
>
> return 0;
> }
>
> static int stop_tt (int unit)
> {
> u_char cmd_buf[8] =3D {0};
> int istat;
>
> cmd_buf[0] =3D cmd_clr_err;
> send_cmd(unit,cmd_buf,1);
> istat =3D get_status(unit);
> printf ("stop_tt stat after cmd_clr_err=3D%d\n",istat);
>
> cmd_buf[0] =3D cmd_chan_off;
> cmd_buf[1] =3D 0xc0;
> send_cmd(unit, cmd_buf, 2);
> istat =3D get_status(unit);
> printf ("stop_tt stat after cmd_chan_off=3D%d\n",istat);
>
> #if 0
> cmd_buf[0] =3D cmd_clr_tt;
> cmd_buf[1] =3D 0; /* clear time tag buffer and time tag counter */
> send_cmd(unit, cmd_buf, 2);
> istat =3D get_status(unit);
> printf ("stop_tt stat after cmd_clr_tt=3D%d\n",istat);
> #endif
>
> return 0;
> }
>
> static int get_tt_count (int unit)
> {
> return 0;
> }
>
> static int get_tt (int unit, long long *tt)
> {
> int base_io_port;
> int ram_addr_reg;
> int next_tt;
>
> send_cmd(unit,NULL,0);
> base_io_port =3D devices[unit].id_iobase;
>
> ram_addr_reg =3D base_io_port + io_addr_ram_addr_reg;
> outb (ram_addr_reg, dp_ram_status_page);
>
> {
> int ii;
> printf ("status page : ");
> for (ii=3D0; ii<8; ++ii)
> {
> next_tt =3D inb(base_io_port + 8 + ii);
> printf (" 0x%x");
> }
> printf ("\n");
> }
>
> {
> int ii;
> printf ("tag buf :");
> outb (ram_addr_reg, 156);
> for (ii=3D0; ii<8; ++ii)
> {
> next_tt =3D inb(base_io_port + 8 + ii);
> printf (" 0x%x");
> }
> outb (ram_addr_reg, 157);
> for (ii=3D0; ii<4; ++ii)
> {
> next_tt =3D inb(base_io_port + 8 + ii);
> printf (" 0x%x");
> }
> printf ("\n");
> }
>
> return 0;
> }
>
> static int get_status(int unit)
> {
> int base_io_port;
> int ram_addr_reg;
> int status_reg;
> int istat;
>
> base_io_port =3D devices[unit].id_iobase;
> ram_addr_reg =3D base_io_port + io_addr_ram_addr_reg;
>
> send_cmd(unit,NULL,0);
>
> outb (ram_addr_reg, dp_ram_status_page);
>
> status_reg =3D base_io_port + err_reg;
> istat =3D inb(status_reg) & 0xff;
>
> return istat;
> }
>
>
> --==_Exmh_18363059200
> Content-Type: text/plain ; name="log_read_counts_980726.c"; charset=us-ascii
> Content-Description: log_read_counts_980726.c
> Content-Transfer-Encoding: quoted-printable
> Content-Disposition: attachment; filename="log_read_counts_980726.c"
>
> #if 0
> cc -o test04 test04.c
>
> Experiment with /dev/gt401 not doing time tags
> Run continuously
> #endif
>
> #include <sys/types.h>
> #include <sys/rtprio.h>
> #include <stdio.h>
>
> #include <fcntl.h>
> #include "gt401.h"
>
> #define DEV_PATH "/dev/gt401"
> int fd =3D -1;
>
> int arg_ioctl =3D 0;
>
> int read_count =3D 0;
>
> #define MAX_TTAG_BUF (4*1024)
>
> main (int argc, char **argv)
> {
> int istat;
> int ii;
> gt401_read * ttag;
> gt401_read ttag_buf[MAX_TTAG_BUF], last_ttag;
> int log_mod;
> double period_d;
> double freq_d;
> int first_flag =3D 1;
> int read_req =3D (sizeof(gt401_read) * MAX_TTAG_BUF);
> int read_data_count;
> int max_read_data_count =3D 0;
>
> long long sample_period =3D -1;
> long long sample_period_hi;
> long long sample_period_low;
> int read_dropped =3D 0;
> int driver_dropped =3D 0;
>
> long long index_diff_driver;
> long long index_diff_read_error;
> long long calc_usec_diff_driver;
> long long calc_index_diff_driver;
> long long index_diff_driver_error;
>
> struct rtprio rtp;
> int rtp_flag =3D 0;
>
> #if 1
> rtp_flag =3D 1;
> rtp.type =3D RTP_PRIO_REALTIME;
> rtp.prio =3D 0;
> istat =3D rtprio (RTP_SET,
> 0,
> &rtp);
> if (istat !=3D 0)
> {
> perror("rtprio");
> exit (1);
> }
> fprintf (stderr,"rtprio\n");
> #else
> fprintf (stderr, "No rtprio\n");
> #endif
>
> fd =3D open (DEV_PATH, O_RDONLY, 0);
> if (fd < 0)
> {
> fprintf(stderr,"open of %s failed\n",DEV_PATH);
> exit (__LINE__);
> }
>
> arg_ioctl =3D 20;
>
> period_d =3D ((double)arg_ioctl) / 10000.0;
> freq_d =3D 1.0 / period_d;
> log_mod =3D (int)(freq_d * 30.0);
>
> sample_period =3D (long long)(period_d * 1e6);
> sample_period_low =3D sample_period - (sample_period / 8);
> sample_period_hi =3D sample_period + (sample_period / 8);
>
> fprintf (stderr,"periodX10000=3D%d period=3D%f freq=3D%f\n",arg_ioctl,p=
> eriod_d,freq_d);
> fprintf (stderr,"sizeof(gt401_read) =3D %d\n",sizeof(gt401_read));
>
> for (ii=3D1; ii<argc; ++ii)
> {
> printf ("# %s\n",argv[ii]); /* gnuplot comment line */
> }
> printf ("# period=3D%f freq=3D%f",
> period_d, freq_d);
> if (rtp_flag)
> printf(" RTPRIO");
> else
> printf(" NO RTPRIO");
> printf ("\n");
>
> istat =3D ioctl(fd,GT401_START_EVENTS,&arg_ioctl);
>
> for (;;)
> {
> istat =3D read (fd,(void *)&(ttag_buf[0]),read_req);
> if (istat <=3D 0)
> {
> fprintf (stderr,"read fail istat=3D%d\n",istat);
> perror("read fail");
> exit (__LINE__);
> }
> read_data_count =3D istat / sizeof(gt401_read);
> printf ("%d\n",read_data_count);
> fflush(stdout);
> } /* for (;;) */
>
> istat =3D ioctl(fd,GT401_STOP_EVENTS,&arg_ioctl);
>
> return (0);
> }
>
> --==_Exmh_18363059200
> Content-Type: text/plain; name="log_read_counts_980726.c"; charset=us-ascii
> Content-Description: log_read_counts_980726.c
> Content-Transfer-Encoding: quoted-printable
> Content-Disposition: attachment; filename="log_read_counts_980726.c"
>
> #if 0
> cc -o test04 test04.c
>
> Experiment with /dev/gt401 not doing time tags
> Run continuously
> #endif
>
> #include <sys/types.h>
> #include <sys/rtprio.h>
> #include <stdio.h>
>
> #include <fcntl.h>
> #include "gt401.h"
>
> #define DEV_PATH "/dev/gt401"
> int fd =3D -1;
>
> int arg_ioctl =3D 0;
>
> int read_count =3D 0;
>
> #define MAX_TTAG_BUF (4*1024)
>
> main (int argc, char **argv)
> {
> int istat;
> int ii;
> gt401_read * ttag;
> gt401_read ttag_buf[MAX_TTAG_BUF], last_ttag;
> int log_mod;
> double period_d;
> double freq_d;
> int first_flag =3D 1;
> int read_req =3D (sizeof(gt401_read) * MAX_TTAG_BUF);
> int read_data_count;
> int max_read_data_count =3D 0;
>
> long long sample_period =3D -1;
> long long sample_period_hi;
> long long sample_period_low;
> int read_dropped =3D 0;
> int driver_dropped =3D 0;
>
> long long index_diff_driver;
> long long index_diff_read_error;
> long long calc_usec_diff_driver;
> long long calc_index_diff_driver;
> long long index_diff_driver_error;
>
> struct rtprio rtp;
> int rtp_flag =3D 0;
>
> #if 1
> rtp_flag =3D 1;
> rtp.type =3D RTP_PRIO_REALTIME;
> rtp.prio =3D 0;
> istat =3D rtprio (RTP_SET,
> 0,
> &rtp);
> if (istat !=3D 0)
> {
> perror("rtprio");
> exit (1);
> }
> fprintf (stderr,"rtprio\n");
> #else
> fprintf (stderr, "No rtprio\n");
> #endif
>
> fd =3D open (DEV_PATH, O_RDONLY, 0);
> if (fd < 0)
> {
> fprintf(stderr,"open of %s failed\n",DEV_PATH);
> exit (__LINE__);
> }
>
> arg_ioctl =3D 20;
>
> period_d =3D ((double)arg_ioctl) / 10000.0;
> freq_d =3D 1.0 / period_d;
> log_mod =3D (int)(freq_d * 30.0);
>
> sample_period =3D (long long)(period_d * 1e6);
> sample_period_low =3D sample_period - (sample_period / 8);
> sample_period_hi =3D sample_period + (sample_period / 8);
>
> fprintf (stderr,"periodX10000=3D%d period=3D%f freq=3D%f\n",arg_ioctl,p=
> eriod_d,freq_d);
> fprintf (stderr,"sizeof(gt401_read) =3D %d\n",sizeof(gt401_read));
>
> for (ii=3D1; ii<argc; ++ii)
> {
> printf ("# %s\n",argv[ii]); /* gnuplot comment line */
> }
> printf ("# period=3D%f freq=3D%f",
> period_d, freq_d);
> if (rtp_flag)
> printf(" RTPRIO");
> else
> printf(" NO RTPRIO");
> printf ("\n");
>
> istat =3D ioctl(fd,GT401_START_EVENTS,&arg_ioctl);
>
> for (;;)
> {
> istat =3D read (fd,(void *)&(ttag_buf[0]),read_req);
> if (istat <=3D 0)
> {
> fprintf (stderr,"read fail istat=3D%d\n",istat);
> perror("read fail");
> exit (__LINE__);
> }
> read_data_count =3D istat / sizeof(gt401_read);
> printf ("%d\n",read_data_count);
> fflush(stdout);
> } /* for (;;) */
>
> istat =3D ioctl(fd,GT401_STOP_EVENTS,&arg_ioctl);
>
> return (0);
> }
>
> --==_Exmh_18363059200--
>
>
>
> To Unsubscribe: send mail to majordomo@FreeBSD.org
> with "unsubscribe freebsd-hackers" in the body of the message
>
--
\\ Sometimes you're ahead, \\ Mike Smith
\\ sometimes you're behind. \\ mike@smith.net.au
\\ The race is long, and in the \\ msmith@freebsd.org
\\ end it's only with yourself. \\ msmith@cdrom.com
To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-hackers" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199807312322.QAA01183>
