Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / net / i4b / driver / i4b_trace.c
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
83 static struct ifqueue trace_queue[NI4BTRC];
84 static 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
91 static void *devfs_token[NI4BTRC];
92 #endif
93 #endif
94
95 static int analyzemode = 0;
96 static int rxunit = -1;
97 static int txunit = -1;
98 static int outunit = -1;
99
100 #ifndef __FreeBSD__
101
102 #define PDEVSTATIC      /* - not static - */
103 void i4btrcattach __P((void));
104 int i4btrcopen __P((dev_t dev, int flag, int fmt, struct proc *p));
105 int i4btrcclose __P((dev_t dev, int flag, int fmt, struct proc *p));
106 int i4btrcread __P((dev_t dev, struct uio * uio, int ioflag));
107
108 #ifdef __bsdi__
109 int i4btrcioctl __P((dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p));
110 #else
111 int 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
118 static d_open_t i4btrcopen;
119 static d_close_t i4btrcclose;
120 static d_read_t i4btrcread;
121 static d_ioctl_t i4btrcioctl;
122
123 #ifdef OS_USES_POLL
124 static d_poll_t i4btrcpoll;
125 #define POLLFIELD i4btrcpoll
126 #else
127 #define POLLFIELD noselect
128 #endif
129
130 #define CDEV_MAJOR 59
131
132 static 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  *---------------------------------------------------------------------------*/
152 static
153 void i4btrcinit(void *unused)
154 {
155         cdevsw_add(&i4btrc_cdevsw);
156 }
157
158 SYSINIT(i4btrcdev, SI_SUB_DRIVERS,
159         SI_ORDER_MIDDLE+CDEV_MAJOR, &i4btrcinit, NULL);
160
161 static void i4btrcattach(void *);
162 PSEUDO_SET(i4btrcattach, i4b_trace);
163
164 #endif /* BSD > 199306 && defined(__FreeBSD__) */
165
166 #ifdef __bsdi__
167 #include <sys/device.h>
168 int i4btrcmatch(struct device *parent, struct cfdata *cf, void *aux);
169 void dummy_i4btrcattach(struct device*, struct device *, void *);
170
171 #define CDEV_MAJOR 60
172
173 static struct cfdriver i4btrccd =
174         { NULL, "i4btrc", i4btrcmatch, dummy_i4btrcattach, DV_DULL,
175           sizeof(struct cfdriver) };
176 struct devsw i4btrcsw = 
177         { &i4btrccd,
178           i4btrcopen,   i4btrcclose,    i4btrcread,     nowrite,
179           i4btrcioctl,  seltrue,        nommap,         nostrat,
180           nodump,       nopsize,        0,              nostop
181 };
182
183 int
184 i4btrcmatch(struct device *parent, struct cfdata *cf, void *aux)
185 {
186         printf("i4btrcmatch: aux=0x%x\n", aux);
187         return 1;
188 }
189 void
190 dummy_i4btrcattach(struct device *parent, struct device *self, void *aux)
191 {
192         printf("dummy_i4btrcattach: aux=0x%x\n", aux);
193 }
194 #endif /* __bsdi__ */
195
196 int get_trace_data_from_l1(i4b_trace_hdr_t *hdr, int len, char *buf);
197
198 /*---------------------------------------------------------------------------*
199  *      interface attach routine
200  *---------------------------------------------------------------------------*/
201 PDEVSTATIC void
202 #ifdef __FreeBSD__
203 i4btrcattach(void *dummy)
204 #else
205 i4btrcattach()
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  *---------------------------------------------------------------------------*/
236 int
237 get_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  *---------------------------------------------------------------------------*/
336 PDEVSTATIC int
337 i4btrcopen(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  *---------------------------------------------------------------------------*/
363 PDEVSTATIC int
364 i4btrcclose(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  *---------------------------------------------------------------------------*/
409 PDEVSTATIC int
410 i4btrcread(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  *---------------------------------------------------------------------------*/
465 PDEVSTATIC int
466 i4btrcpoll(dev_t dev, int events, struct proc *p)
467 {
468         return(ENODEV);
469 }
470 #endif
471
472 /*---------------------------------------------------------------------------*
473  *      device driver ioctl routine
474  *---------------------------------------------------------------------------*/
475 PDEVSTATIC int
476 #if defined (__FreeBSD_version) && __FreeBSD_version >= 300003
477 i4btrcioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
478 #elif defined(__bsdi__)
479 i4btrcioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
480 #else
481 i4btrcioctl(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 */