2 * Copyright (c) 1997, 2002 Hellmuth Michaelis. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 /*---------------------------------------------------------------------------
28 * i4btrc - device driver for trace data read device
29 * ---------------------------------------------------
30 * last edit-date: [Sun Mar 17 09:52:51 2002]
32 * NOTE: the code assumes that SPLI4B >= splimp !
34 *---------------------------------------------------------------------------*/
36 #include <sys/cdefs.h>
37 __FBSDID("$FreeBSD$");
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/ioccom.h>
46 #include <sys/kernel.h>
48 #include <sys/socket.h>
52 #include <machine/i4b_trace.h>
53 #include <machine/i4b_ioctl.h>
55 #include <i4b/include/i4b_mbuf.h>
56 #include <i4b/include/i4b_global.h>
57 #include <i4b/include/i4b_l3l4.h>
59 static struct ifqueue trace_queue[NI4BTRC];
61 static int device_state[NI4BTRC];
63 #define ST_ISOPEN 0x01
64 #define ST_WAITDATA 0x02
66 static int analyzemode = 0;
67 static int rxunit = -1;
68 static int txunit = -1;
69 static int outunit = -1;
71 static d_open_t i4btrcopen;
72 static d_close_t i4btrcclose;
73 static d_read_t i4btrcread;
74 static d_ioctl_t i4btrcioctl;
75 static d_poll_t i4btrcpoll;
78 static struct cdevsw i4btrc_cdevsw = {
79 .d_version = D_VERSION,
80 .d_flags = D_NEEDGIANT,
82 .d_close = i4btrcclose,
84 .d_ioctl = i4btrcioctl,
89 static void i4btrcattach(void *);
90 PSEUDO_SET(i4btrcattach, i4b_trace);
92 int get_trace_data_from_l1(i4b_trace_hdr_t *hdr, int len, char *buf);
94 /*---------------------------------------------------------------------------*
95 * interface attach routine
96 *---------------------------------------------------------------------------*/
98 i4btrcattach(void *dummy)
102 printf("i4btrc: %d ISDN trace device(s) attached\n", NI4BTRC);
104 for(i=0; i < NI4BTRC; i++)
106 make_dev(&i4btrc_cdevsw, i,
107 UID_ROOT, GID_WHEEL, 0600, "i4btrc%d", i);
108 trace_queue[i].ifq_maxlen = IFQ_MAXLEN;
110 if(!mtx_initialized(&trace_queue[i].ifq_mtx))
111 mtx_init(&trace_queue[i].ifq_mtx, "i4b_trace", NULL, MTX_DEF);
113 device_state[i] = ST_IDLE;
117 /*---------------------------------------------------------------------------*
118 * get_trace_data_from_l1()
119 * ------------------------
120 * is called from layer 1, adds timestamp to trace data and puts
121 * it into a queue, from which it can be read from the i4btrc
122 * device. The unit number in the trace header selects the minor
123 * device's queue the data is put into.
124 *---------------------------------------------------------------------------*/
126 get_trace_data_from_l1(i4b_trace_hdr_t *hdr, int len, char *buf)
132 int totlen = len + sizeof(i4b_trace_hdr_t);
135 * for telephony (or better non-HDLC HSCX mode) we get
136 * (MCLBYTE + sizeof(i4b_trace_hdr_t)) length packets
137 * to put into the queue to userland. because of this
138 * we detect this situation, strip the length to MCLBYTES
139 * max size, and infor the userland program of this fact
140 * by putting the no of truncated bytes into hdr->trunc.
143 if(totlen > MCLBYTES)
146 hdr->trunc = totlen - MCLBYTES;
154 /* set length of trace record */
156 hdr->length = totlen;
158 /* check valid unit no */
160 if((unit = hdr->unit) >= NI4BTRC)
162 printf("i4b_trace: get_trace_data_from_l1 - unit > NI4BTRC!\n");
168 if(!(m = i4b_Bgetmbuf(totlen)))
170 printf("i4b_trace: get_trace_data_from_l1 - i4b_getmbuf() failed!\n");
174 /* check if we are in analyzemode */
176 if(analyzemode && (unit == rxunit || unit == txunit))
185 IF_LOCK(&trace_queue[unit]);
187 if(_IF_QFULL(&trace_queue[unit]))
192 _IF_DEQUEUE(&trace_queue[unit], m1);
198 /* copy trace header */
199 memcpy(m->m_data, hdr, sizeof(i4b_trace_hdr_t));
201 /* copy trace data */
203 memcpy(&m->m_data[sizeof(i4b_trace_hdr_t)], buf, totlen-sizeof(i4b_trace_hdr_t));
205 memcpy(&m->m_data[sizeof(i4b_trace_hdr_t)], buf, len);
209 _IF_ENQUEUE(&trace_queue[unit], m);
210 IF_UNLOCK(&trace_queue[unit]);
212 if(device_state[unit] & ST_WAITDATA)
214 device_state[unit] &= ~ST_WAITDATA;
215 wakeup( &trace_queue[unit]);
223 /*---------------------------------------------------------------------------*
225 *---------------------------------------------------------------------------*/
227 i4btrcopen(struct cdev *dev, int flag, int fmt, struct thread *td)
230 int unit = minor(dev);
235 if(device_state[unit] & ST_ISOPEN)
238 if(analyzemode && (unit == outunit || unit == rxunit || unit == txunit))
243 device_state[unit] = ST_ISOPEN;
250 /*---------------------------------------------------------------------------*
252 *---------------------------------------------------------------------------*/
254 i4btrcclose(struct cdev *dev, int flag, int fmt, struct thread *td)
256 int unit = minor(dev);
260 for(i=0; i < nctrl; i++)
262 if((ctrl_desc[i].ctrl_type == CTRL_PASSIVE) &&
263 (ctrl_desc[i].unit == unit))
270 if(analyzemode && (unit == outunit))
277 (*ctrl_desc[cno].N_MGMT_COMMAND)(rxunit, CMR_SETTRACE, TRACE_OFF);
278 (*ctrl_desc[cno].N_MGMT_COMMAND)(txunit, CMR_SETTRACE, TRACE_OFF);
286 (*ctrl_desc[cno].N_MGMT_COMMAND)(ctrl_desc[cno].unit, CMR_SETTRACE, TRACE_OFF);
290 device_state[unit] = ST_IDLE;
296 /*---------------------------------------------------------------------------*
297 * read from trace device
298 *---------------------------------------------------------------------------*/
300 i4btrcread(struct cdev *dev, struct uio * uio, int ioflag)
305 int unit = minor(dev);
307 if(!(device_state[unit] & ST_ISOPEN))
312 IF_LOCK(&trace_queue[unit]);
314 while(IF_QEMPTY(&trace_queue[unit]) && (device_state[unit] & ST_ISOPEN))
316 device_state[unit] |= ST_WAITDATA;
318 if((error = msleep( &trace_queue[unit],
319 &trace_queue[unit].ifq_mtx,
323 device_state[unit] &= ~ST_WAITDATA;
324 IF_UNLOCK(&trace_queue[unit]);
330 _IF_DEQUEUE(&trace_queue[unit], m);
331 IF_UNLOCK(&trace_queue[unit]);
334 error = uiomove(m->m_data, m->m_len, uio);
346 /*---------------------------------------------------------------------------*
348 *---------------------------------------------------------------------------*/
350 i4btrcpoll(struct cdev *dev, int events, struct thread *td)
355 /*---------------------------------------------------------------------------*
356 * device driver ioctl routine
357 *---------------------------------------------------------------------------*/
359 i4btrcioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
362 int unit = minor(dev);
363 i4b_trace_setupa_t *tsa;
367 /* find the first passive controller matching our unit no */
369 for(i=0; i < nctrl; i++)
371 if((ctrl_desc[i].ctrl_type == CTRL_PASSIVE) &&
372 (ctrl_desc[i].unit == unit))
384 (*ctrl_desc[cno].N_MGMT_COMMAND)(ctrl_desc[cno].unit, CMR_SETTRACE, (void *)*(unsigned int *)data);
388 tsa = (i4b_trace_setupa_t *)data;
390 if(tsa->rxunit >= 0 && tsa->rxunit < NI4BTRC)
391 rxunit = tsa->rxunit;
395 if(tsa->txunit >= 0 && tsa->txunit < NI4BTRC)
396 txunit = tsa->txunit;
413 (*ctrl_desc[cno].N_MGMT_COMMAND)(rxunit, CMR_SETTRACE, (int *)(tsa->rxflags & (TRACE_I | TRACE_D_RX | TRACE_B_RX)));
414 (*ctrl_desc[cno].N_MGMT_COMMAND)(txunit, CMR_SETTRACE, (int *)(tsa->txflags & (TRACE_I | TRACE_D_RX | TRACE_B_RX)));