Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / net / i4b / driver / i4b_trace.c
CommitLineData
984263bc
MD
1/*
2 * Copyright (c) 1997, 2001 Hellmuth Michaelis. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
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.
12 *
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
23 * SUCH DAMAGE.
24 *
25 *---------------------------------------------------------------------------
26 *
27 * i4btrc - device driver for trace data read device
28 * ---------------------------------------------------
29 *
30 * last edit-date: [Sat Aug 11 18:07:15 2001]
31 *
32 * $FreeBSD: src/sys/i4b/driver/i4b_trace.c,v 1.9.2.3 2001/08/12 16:22:48 hm Exp $
33 *
34 * NOTE: the code assumes that SPLI4B >= splimp !
35 *
36 *---------------------------------------------------------------------------*/
37
38#include "i4btrc.h"
39
40#if NI4BTRC > 0
41
42#include <sys/param.h>
43#include <sys/systm.h>
44
45#if defined(__FreeBSD__) && __FreeBSD__ >= 3
46#include <sys/ioccom.h>
47#else
48#include <sys/ioctl.h>
49#endif
50
51#include <sys/conf.h>
52#include <sys/uio.h>
53#include <sys/kernel.h>
54#include <sys/mbuf.h>
55#include <sys/socket.h>
56#include <net/if.h>
57#include <sys/tty.h>
58
59#ifdef __FreeBSD__
60
61#ifdef DEVFS
62#include <sys/devfsext.h>
63#endif
64
65#include <machine/i4b_trace.h>
66#include <machine/i4b_ioctl.h>
67
68#else
69
70#include <i4b/i4b_trace.h>
71#include <i4b/i4b_ioctl.h>
72
73#endif
74
75#include <i4b/include/i4b_mbuf.h>
76#include <i4b/include/i4b_global.h>
77#include <i4b/include/i4b_l3l4.h>
78
79#ifndef __FreeBSD__
80#define memcpy(d,s,l) bcopy(s,d,l)
81#endif
82
83static struct ifqueue trace_queue[NI4BTRC];
84static int device_state[NI4BTRC];
85#define ST_IDLE 0x00
86#define ST_ISOPEN 0x01
87#define ST_WAITDATA 0x02
88
89#if defined(__FreeBSD__) && __FreeBSD__ == 3
90#ifdef DEVFS
91static void *devfs_token[NI4BTRC];
92#endif
93#endif
94
95static int analyzemode = 0;
96static int rxunit = -1;
97static int txunit = -1;
98static int outunit = -1;
99
100#ifndef __FreeBSD__
101
102#define PDEVSTATIC /* - not static - */
103void i4btrcattach __P((void));
104int i4btrcopen __P((dev_t dev, int flag, int fmt, struct proc *p));
105int i4btrcclose __P((dev_t dev, int flag, int fmt, struct proc *p));
106int i4btrcread __P((dev_t dev, struct uio * uio, int ioflag));
107
108#ifdef __bsdi__
109int i4btrcioctl __P((dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p));
110#else
111int i4btrcioctl __P((dev_t dev, int cmd, caddr_t data, int flag, struct proc *p));
112#endif
113
114#endif
115
116#if BSD > 199306 && defined(__FreeBSD__)
117#define PDEVSTATIC static
118static d_open_t i4btrcopen;
119static d_close_t i4btrcclose;
120static d_read_t i4btrcread;
121static d_ioctl_t i4btrcioctl;
122
123#ifdef OS_USES_POLL
124static d_poll_t i4btrcpoll;
125#define POLLFIELD i4btrcpoll
126#else
127#define POLLFIELD noselect
128#endif
129
130#define CDEV_MAJOR 59
131
132static struct cdevsw i4btrc_cdevsw = {
133 /* open */ i4btrcopen,
134 /* close */ i4btrcclose,
135 /* read */ i4btrcread,
136 /* write */ nowrite,
137 /* ioctl */ i4btrcioctl,
138 /* poll */ POLLFIELD,
139 /* mmap */ nommap,
140 /* strategy */ nostrategy,
141 /* name */ "i4btrc",
142 /* maj */ CDEV_MAJOR,
143 /* dump */ nodump,
144 /* psize */ nopsize,
145 /* flags */ 0,
146 /* bmaj */ -1
147};
148
149/*---------------------------------------------------------------------------*
150 * interface init routine
151 *---------------------------------------------------------------------------*/
152static
153void i4btrcinit(void *unused)
154{
155 cdevsw_add(&i4btrc_cdevsw);
156}
157
158SYSINIT(i4btrcdev, SI_SUB_DRIVERS,
159 SI_ORDER_MIDDLE+CDEV_MAJOR, &i4btrcinit, NULL);
160
161static void i4btrcattach(void *);
162PSEUDO_SET(i4btrcattach, i4b_trace);
163
164#endif /* BSD > 199306 && defined(__FreeBSD__) */
165
166#ifdef __bsdi__
167#include <sys/device.h>
168int i4btrcmatch(struct device *parent, struct cfdata *cf, void *aux);
169void dummy_i4btrcattach(struct device*, struct device *, void *);
170
171#define CDEV_MAJOR 60
172
173static struct cfdriver i4btrccd =
174 { NULL, "i4btrc", i4btrcmatch, dummy_i4btrcattach, DV_DULL,
175 sizeof(struct cfdriver) };
176struct devsw i4btrcsw =
177 { &i4btrccd,
178 i4btrcopen, i4btrcclose, i4btrcread, nowrite,
179 i4btrcioctl, seltrue, nommap, nostrat,
180 nodump, nopsize, 0, nostop
181};
182
183int
184i4btrcmatch(struct device *parent, struct cfdata *cf, void *aux)
185{
186 printf("i4btrcmatch: aux=0x%x\n", aux);
187 return 1;
188}
189void
190dummy_i4btrcattach(struct device *parent, struct device *self, void *aux)
191{
192 printf("dummy_i4btrcattach: aux=0x%x\n", aux);
193}
194#endif /* __bsdi__ */
195
196int get_trace_data_from_l1(i4b_trace_hdr_t *hdr, int len, char *buf);
197
198/*---------------------------------------------------------------------------*
199 * interface attach routine
200 *---------------------------------------------------------------------------*/
201PDEVSTATIC void
202#ifdef __FreeBSD__
203i4btrcattach(void *dummy)
204#else
205i4btrcattach()
206#endif
207{
208 int i;
209
210 printf("i4btrc: %d ISDN trace device(s) attached\n", NI4BTRC);
211
212 for(i=0; i < NI4BTRC; i++)
213 {
214
215#if defined(__FreeBSD__)
216 make_dev(&i4btrc_cdevsw, i,
217 UID_ROOT, GID_WHEEL, 0600, "i4btrc%d", i);
218#endif
219 trace_queue[i].ifq_maxlen = IFQ_MAXLEN;
220
221#if __FreeBSD__ > 4
222 mtx_init(&trace_queue[i].ifq_mtx, "i4b_trace", MTX_DEF);
223#endif
224 device_state[i] = ST_IDLE;
225 }
226}
227
228/*---------------------------------------------------------------------------*
229 * get_trace_data_from_l1()
230 * ------------------------
231 * is called from layer 1, adds timestamp to trace data and puts
232 * it into a queue, from which it can be read from the i4btrc
233 * device. The unit number in the trace header selects the minor
234 * device's queue the data is put into.
235 *---------------------------------------------------------------------------*/
236int
237get_trace_data_from_l1(i4b_trace_hdr_t *hdr, int len, char *buf)
238{
239 struct mbuf *m;
240 int x;
241 int unit;
242 int trunc = 0;
243 int totlen = len + sizeof(i4b_trace_hdr_t);
244
245 /*
246 * for telephony (or better non-HDLC HSCX mode) we get
247 * (MCLBYTE + sizeof(i4b_trace_hdr_t)) length packets
248 * to put into the queue to userland. because of this
249 * we detect this situation, strip the length to MCLBYTES
250 * max size, and infor the userland program of this fact
251 * by putting the no of truncated bytes into hdr->trunc.
252 */
253
254 if(totlen > MCLBYTES)
255 {
256 trunc = 1;
257 hdr->trunc = totlen - MCLBYTES;
258 totlen = MCLBYTES;
259 }
260 else
261 {
262 hdr->trunc = 0;
263 }
264
265 /* set length of trace record */
266
267 hdr->length = totlen;
268
269 /* check valid unit no */
270
271 if((unit = hdr->unit) > NI4BTRC)
272 {
273 printf("i4b_trace: get_trace_data_from_l1 - unit > NI4BTRC!\n");
274 return(0);
275 }
276
277 /* get mbuf */
278
279 if(!(m = i4b_Bgetmbuf(totlen)))
280 {
281 printf("i4b_trace: get_trace_data_from_l1 - i4b_getmbuf() failed!\n");
282 return(0);
283 }
284
285 /* check if we are in analyzemode */
286
287 if(analyzemode && (unit == rxunit || unit == txunit))
288 {
289 if(unit == rxunit)
290 hdr->dir = FROM_NT;
291 else
292 hdr->dir = FROM_TE;
293 unit = outunit;
294 }
295
296 IF_LOCK(&trace_queue[unit]);
297 if(_IF_QFULL(&trace_queue[unit]))
298 {
299 struct mbuf *m1;
300
301 x = SPLI4B();
302 _IF_DEQUEUE(&trace_queue[unit], m1);
303 splx(x);
304
305 i4b_Bfreembuf(m1);
306 }
307
308 /* copy trace header */
309 memcpy(m->m_data, hdr, sizeof(i4b_trace_hdr_t));
310
311 /* copy trace data */
312 if(trunc)
313 memcpy(&m->m_data[sizeof(i4b_trace_hdr_t)], buf, totlen-sizeof(i4b_trace_hdr_t));
314 else
315 memcpy(&m->m_data[sizeof(i4b_trace_hdr_t)], buf, len);
316
317 x = SPLI4B();
318
319 _IF_ENQUEUE(&trace_queue[unit], m);
320 IF_UNLOCK(&trace_queue[unit]);
321
322 if(device_state[unit] & ST_WAITDATA)
323 {
324 device_state[unit] &= ~ST_WAITDATA;
325 wakeup((caddr_t) &trace_queue[unit]);
326 }
327
328 splx(x);
329
330 return(1);
331}
332
333/*---------------------------------------------------------------------------*
334 * open trace device
335 *---------------------------------------------------------------------------*/
336PDEVSTATIC int
337i4btrcopen(dev_t dev, int flag, int fmt, struct proc *p)
338{
339 int x;
340 int unit = minor(dev);
341
342 if(unit >= NI4BTRC)
343 return(ENXIO);
344
345 if(device_state[unit] & ST_ISOPEN)
346 return(EBUSY);
347
348 if(analyzemode && (unit == outunit || unit == rxunit || unit == txunit))
349 return(EBUSY);
350
351 x = SPLI4B();
352
353 device_state[unit] = ST_ISOPEN;
354
355 splx(x);
356
357 return(0);
358}
359
360/*---------------------------------------------------------------------------*
361 * close trace device
362 *---------------------------------------------------------------------------*/
363PDEVSTATIC int
364i4btrcclose(dev_t dev, int flag, int fmt, struct proc *p)
365{
366 int unit = minor(dev);
367 int i, x;
368 int cno = -1;
369
370 for(i=0; i < nctrl; i++)
371 {
372 if((ctrl_desc[i].ctrl_type == CTRL_PASSIVE) &&
373 (ctrl_desc[i].unit == unit))
374 {
375 cno = i;
376 break;
377 }
378 }
379
380 if(analyzemode && (unit == outunit))
381 {
382 analyzemode = 0;
383 outunit = -1;
384
385 if(cno >= 0)
386 {
387 (*ctrl_desc[cno].N_MGMT_COMMAND)(rxunit, CMR_SETTRACE, TRACE_OFF);
388 (*ctrl_desc[cno].N_MGMT_COMMAND)(txunit, CMR_SETTRACE, TRACE_OFF);
389 }
390 rxunit = -1;
391 txunit = -1;
392 }
393
394 if(cno >= 0)
395 {
396 (*ctrl_desc[cno].N_MGMT_COMMAND)(ctrl_desc[cno].unit, CMR_SETTRACE, TRACE_OFF);
397 }
398
399 x = SPLI4B();
400 device_state[unit] = ST_IDLE;
401 splx(x);
402
403 return(0);
404}
405
406/*---------------------------------------------------------------------------*
407 * read from trace device
408 *---------------------------------------------------------------------------*/
409PDEVSTATIC int
410i4btrcread(dev_t dev, struct uio * uio, int ioflag)
411{
412 struct mbuf *m;
413 int x;
414 int error = 0;
415 int unit = minor(dev);
416
417 if(!(device_state[unit] & ST_ISOPEN))
418 return(EIO);
419
420 x = SPLI4B();
421
422 IF_LOCK(&trace_queue[unit]);
423 while(IF_QEMPTY(&trace_queue[unit]) && (device_state[unit] & ST_ISOPEN))
424 {
425 device_state[unit] |= ST_WAITDATA;
426
427#if defined (__FreeBSD__) && __FreeBSD__ > 4
428 if((error = msleep((caddr_t) &trace_queue[unit],
429 &trace_queue[unit].ifq_mtx,
430 TTIPRI | PCATCH,
431 "bitrc", 0 )) != 0)
432#else
433 if((error = tsleep((caddr_t) &trace_queue[unit],
434 TTIPRI | PCATCH,
435 "bitrc", 0 )) != 0)
436#endif
437 {
438 device_state[unit] &= ~ST_WAITDATA;
439 IF_UNLOCK(&trace_queue[unit]);
440 splx(x);
441 return(error);
442 }
443 }
444
445 _IF_DEQUEUE(&trace_queue[unit], m);
446 IF_UNLOCK(&trace_queue[unit]);
447
448 if(m && m->m_len)
449 error = uiomove(m->m_data, m->m_len, uio);
450 else
451 error = EIO;
452
453 if(m)
454 i4b_Bfreembuf(m);
455
456 splx(x);
457
458 return(error);
459}
460
461#if defined(__FreeBSD__) && defined(OS_USES_POLL)
462/*---------------------------------------------------------------------------*
463 * poll device
464 *---------------------------------------------------------------------------*/
465PDEVSTATIC int
466i4btrcpoll(dev_t dev, int events, struct proc *p)
467{
468 return(ENODEV);
469}
470#endif
471
472/*---------------------------------------------------------------------------*
473 * device driver ioctl routine
474 *---------------------------------------------------------------------------*/
475PDEVSTATIC int
476#if defined (__FreeBSD_version) && __FreeBSD_version >= 300003
477i4btrcioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
478#elif defined(__bsdi__)
479i4btrcioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
480#else
481i4btrcioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
482#endif
483{
484 int error = 0;
485 int unit = minor(dev);
486 i4b_trace_setupa_t *tsa;
487 int i;
488 int cno = -1;
489
490 /* find the first passive controller matching our unit no */
491
492 for(i=0; i < nctrl; i++)
493 {
494 if((ctrl_desc[i].ctrl_type == CTRL_PASSIVE) &&
495 (ctrl_desc[i].unit == unit))
496 {
497 cno = i;
498 break;
499 }
500 }
501
502 switch(cmd)
503 {
504 case I4B_TRC_SET:
505 if(cno < 0)
506 return ENOTTY;
507 (*ctrl_desc[cno].N_MGMT_COMMAND)(ctrl_desc[cno].unit, CMR_SETTRACE, (void *)*(unsigned int *)data);
508 break;
509
510 case I4B_TRC_SETA:
511 tsa = (i4b_trace_setupa_t *)data;
512
513 if(tsa->rxunit >= 0 && tsa->rxunit < NI4BTRC)
514 rxunit = tsa->rxunit;
515 else
516 error = EINVAL;
517
518 if(tsa->txunit >= 0 && tsa->txunit < NI4BTRC)
519 txunit = tsa->txunit;
520 else
521 error = EINVAL;
522
523 if(error)
524 {
525 outunit = -1;
526 rxunit = -1;
527 txunit = -1;
528 }
529 else
530 {
531 if(cno < 0)
532 return ENOTTY;
533
534 outunit = unit;
535 analyzemode = 1;
536 (*ctrl_desc[cno].N_MGMT_COMMAND)(rxunit, CMR_SETTRACE, (int *)(tsa->rxflags & (TRACE_I | TRACE_D_RX | TRACE_B_RX)));
537 (*ctrl_desc[cno].N_MGMT_COMMAND)(txunit, CMR_SETTRACE, (int *)(tsa->txflags & (TRACE_I | TRACE_D_RX | TRACE_B_RX)));
538 }
539 break;
540
541 case I4B_TRC_RESETA:
542 analyzemode = 0;
543 outunit = -1;
544 rxunit = -1;
545 txunit = -1;
546 break;
547
548 default:
549 error = ENOTTY;
550 break;
551 }
552 return(error);
553}
554
555#endif /* NI4BTRC > 0 */