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>