From owner-freebsd-hackers Fri Jul 31 14:41:56 1998 Return-Path: Received: (from majordom@localhost) by hub.freebsd.org (8.8.8/8.8.8) id OAA05600 for freebsd-hackers-outgoing; Fri, 31 Jul 1998 14:41:56 -0700 (PDT) (envelope-from owner-freebsd-hackers@FreeBSD.ORG) Received: from timingpdc.timing.com (timingpdc.timing.com [208.203.137.194]) by hub.freebsd.org (8.8.8/8.8.8) with ESMTP id OAA05585 for ; Fri, 31 Jul 1998 14:41:30 -0700 (PDT) (envelope-from chanders@timing.com) Received: from count.timing.com ([208.203.137.222]) by timingpdc.timing.com (Post.Office MTA v3.1.2 release (PO205-101c) ID# 103-49575U100L2S100) with ESMTP id AAA317; Fri, 31 Jul 1998 15:33:07 -0600 Received: from count.timing.com (localhost.timing.com [127.0.0.1]) by count.timing.com (8.8.7/8.8.7) with ESMTP id PAA04940; Fri, 31 Jul 1998 15:31:37 -0600 (MDT) (envelope-from chanders@count.timing.com) Message-Id: <199807312131.PAA04940@count.timing.com> X-Mailer: exmh version 2.0zeta 7/24/97 To: Mike Smith Cc: freebsd-hackers@FreeBSD.ORG Subject: Re: Using FreeBSD for data acquisition? (long) In-reply-to: Your message of "Fri, 31 Jul 1998 13:55:30 PDT." <199807312055.NAA00498@dingo.cdrom.com> Mime-Version: 1.0 Content-Type: multipart/mixed ; boundary="==_Exmh_18363059200" Date: Fri, 31 Jul 1998 15:31:37 -0600 From: chanders@timing.com (Craig Anderson) Sender: owner-freebsd-hackers@FreeBSD.ORG Precedence: bulk X-Loop: FreeBSD.ORG This is a multipart MIME message. --==_Exmh_18363059200 Content-Type: text/plain; charset=us-ascii I've attached all the source. Thanks again. > > > > My company is considering using FreeBSD for a data acquisition > > application. We want to know if an upper bound be placed on the > > latency of an application reading data from a data acquisition > > board? FreeBSD is being considered first and then commercial RTOS's > > will be tried. > > No, there is no upper bound. Your response time will vary depending on > a large number of factors, eg. swap activity, other driver activity, > hardware errors, etc. > > > A test project is being done. The project uses an ISA data > > acquisition board. The board interrupts 500 times a second, an 8 > > byte data block is read from the board on each interrupt. > > > > There is a driver lkm for the board: a) driver buffers 4k data > > blocks. b) driver interrupt function reads 1 data block, stores > > data block in buffer, wakes the reader. c) driver read function > > waits for at least 1 data block, returns minimum of requested data > > blocks and available data blocks. > > > > A test application: a) Loops forever requesting 4096 data blocks. > > b) Saves the number of data blocks returned on each read to a file. > > > > Because the interrupts/data blocks arrive at 500 HZ, I am interpreting > > the number of data blocks returned on a read as a measure of read > > latency of the application. If the read returns 50 data blocks, it > > has been .1 second since the last read. (50/500 = .1) > > > > Below are code fragments from the test application. The rtprio() > > call is to put the process into RTP_PRIO_REALTIME. Should this > > make a difference? Is the code correct? > > You haven't included enough code to be certain that your device driver > is working properly. I suspect that it might not be. > > > At the end of the message is histogram data for a test run of about > > 15 hours. I plot the data with gnuplot, using a logscale for y. > > Note that the longest read is 480 (480/500 = .960 seconds). Note > > that the most common read is 50 (50/500 = .100 seconds). > > This would tend to indicate a possible problem with the interaction > between your interrupt handler and the read handler, but it's > impossible to tell without seeing the code. > > > I'd like comments from FreeBSD hackers out there. Can an upper > > bound be put on the read latency? An upper bound of about .100 seconds > > is probably acceptable. Why is a read latency of .100 seconds (50 > > data blocks) so common? Should RTP_PRIO_REALTIME help? Does FreeBSD > > 3 have realtime features that will help? Is there a problem with > > the code or a better approach? > > In a soft-realtime project I was working on last year, we used the > rtprio facility to expedite the data handling process. We were able to > meet a hardware-mandated 100msec delay with light loading under some > circumstances, but this was not sustainable if disk I/O was being > performed (we were saving incoming data at >1MB/sec). > > There are enhanced realtime facilities in FreeBSD 3.0 which would help > in some cases, however it's not clear from your message what your real > goals are. > > > --==_Exmh_18363059200 Content-Type: text/plain ; name="gt401.h"; charset=us-ascii Content-Description: gt401.h Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="gt401.h" #if !defined(gt401_h) # define gt401_h #include /* 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 --==_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 #include #include #include #include #include #include #include #include #include #include #include #include #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=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; 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 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; #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(); for (;;) { if (gt401Unit[0].rbuf_count > 0) break; enable_intr(); 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; if (gt401Unit[0].rbuf_count <=3D 0) break; } enable_intr(); return 0; } static int gt401select (dev_t dev, int rw, struct proc* p) { return 0; } /* * = */ #ifdef GT401_MODULE #include #include #include #include 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; unitid_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 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=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 #include #include #include #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 #include #include #include #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