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