83fb2d6080d33cfd5ec0787bf31a335d8bb1d701
[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.17 2006/12/22 23:44:55 swildner Exp $
34  *
35  *---------------------------------------------------------------------------*/
36
37 #include "use_i4btrc.h"
38
39 #if NI4BTRC > 0
40
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/conf.h>
44 #include <sys/uio.h>
45 #include <sys/kernel.h>
46 #include <sys/mbuf.h>
47 #include <sys/socket.h>
48 #include <net/if.h>
49 #include <sys/tty.h>
50 #include <sys/thread2.h>
51
52 #include <net/i4b/include/machine/i4b_trace.h>
53 #include <net/i4b/include/machine/i4b_ioctl.h>
54
55 #include "../include/i4b_mbuf.h"
56 #include "../include/i4b_global.h"
57 #include "../include/i4b_l3l4.h"
58
59 static struct ifqueue trace_queue[NI4BTRC];
60 static int device_state[NI4BTRC];
61 #define ST_IDLE         0x00
62 #define ST_ISOPEN       0x01
63 #define ST_WAITDATA     0x02
64
65 static int analyzemode = 0;
66 static int rxunit = -1;
67 static int txunit = -1;
68 static int outunit = -1;
69
70 #define PDEVSTATIC static
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
76 static d_poll_t i4btrcpoll;
77 #define POLLFIELD i4btrcpoll
78
79 #define CDEV_MAJOR 59
80
81 static struct dev_ops i4btrc_ops = {
82         { "i4btrc", CDEV_MAJOR, 0 },
83         .d_open =       i4btrcopen,
84         .d_close =      i4btrcclose,
85         .d_read =       i4btrcread,
86         .d_ioctl =      i4btrcioctl,
87         .d_poll =       POLLFIELD,
88 };
89
90 /*---------------------------------------------------------------------------*
91  *      interface init routine
92  *---------------------------------------------------------------------------*/
93 static void
94 i4btrcinit(void *unused)
95 {
96         dev_ops_add(&i4btrc_ops, 0, 0);
97 }
98
99 SYSINIT(i4btrcdev, SI_SUB_DRIVERS,
100         SI_ORDER_MIDDLE+CDEV_MAJOR, &i4btrcinit, NULL);
101
102 static void i4btrcattach(void *);
103 PSEUDO_SET(i4btrcattach, i4b_trace);
104
105 int get_trace_data_from_l1(i4b_trace_hdr_t *hdr, int len, char *buf);
106
107 /*---------------------------------------------------------------------------*
108  *      interface attach routine
109  *---------------------------------------------------------------------------*/
110 PDEVSTATIC void
111 i4btrcattach(void *dummy)
112 {
113         int i;
114
115         kprintf("i4btrc: %d ISDN trace device(s) attached\n", NI4BTRC);
116         
117         for(i=0; i < NI4BTRC; i++)
118         {
119
120                 make_dev(&i4btrc_ops, i,
121                                      UID_ROOT, GID_WHEEL, 0600, "i4btrc%d", i);
122                 trace_queue[i].ifq_maxlen = IFQ_MAXLEN;
123
124                 device_state[i] = ST_IDLE;
125         }
126 }
127
128 /*---------------------------------------------------------------------------*
129  *      get_trace_data_from_l1()
130  *      ------------------------
131  *      is called from layer 1, adds timestamp to trace data and puts
132  *      it into a queue, from which it can be read from the i4btrc
133  *      device. The unit number in the trace header selects the minor
134  *      device's queue the data is put into.
135  *---------------------------------------------------------------------------*/
136 int
137 get_trace_data_from_l1(i4b_trace_hdr_t *hdr, int len, char *buf)
138 {
139         struct mbuf *m;
140         int unit;
141         int trunc = 0;
142         int totlen = len + sizeof(i4b_trace_hdr_t);
143
144         /*
145          * for telephony (or better non-HDLC HSCX mode) we get 
146          * (MCLBYTE + sizeof(i4b_trace_hdr_t)) length packets
147          * to put into the queue to userland. because of this
148          * we detect this situation, strip the length to MCLBYTES
149          * max size, and infor the userland program of this fact
150          * by putting the no of truncated bytes into hdr->trunc.
151          */
152          
153         if(totlen > MCLBYTES)
154         {
155                 trunc = 1;
156                 hdr->trunc = totlen - MCLBYTES;
157                 totlen = MCLBYTES;
158         }
159         else
160         {
161                 hdr->trunc = 0;
162         }
163
164         /* set length of trace record */
165         
166         hdr->length = totlen;
167         
168         /* check valid unit no */
169         
170         if((unit = hdr->unit) > NI4BTRC)
171         {
172                 kprintf("i4b_trace: get_trace_data_from_l1 - unit > NI4BTRC!\n"); 
173                 return(0);
174         }
175
176         /* get mbuf */
177         
178         if(!(m = i4b_Bgetmbuf(totlen)))
179         {
180                 kprintf("i4b_trace: get_trace_data_from_l1 - i4b_getmbuf() failed!\n");
181                 return(0);
182         }
183
184         /* check if we are in analyzemode */
185         
186         if(analyzemode && (unit == rxunit || unit == txunit))
187         {
188                 if(unit == rxunit)
189                         hdr->dir = FROM_NT;
190                 else
191                         hdr->dir = FROM_TE;
192                 unit = outunit;                 
193         }
194
195         if(IF_QFULL(&trace_queue[unit]))
196         {
197                 struct mbuf *m1;
198
199                 crit_enter();
200                 IF_DEQUEUE(&trace_queue[unit], m1);
201                 crit_exit();
202
203                 i4b_Bfreembuf(m1);
204         }
205         
206         /* copy trace header */
207         memcpy(m->m_data, hdr, sizeof(i4b_trace_hdr_t));
208
209         /* copy trace data */
210         if(trunc)
211                 memcpy(&m->m_data[sizeof(i4b_trace_hdr_t)], buf, totlen-sizeof(i4b_trace_hdr_t));
212         else
213                 memcpy(&m->m_data[sizeof(i4b_trace_hdr_t)], buf, len);
214
215         crit_enter();
216         
217         IF_ENQUEUE(&trace_queue[unit], m);
218         
219         if(device_state[unit] & ST_WAITDATA)
220         {
221                 device_state[unit] &= ~ST_WAITDATA;
222                 wakeup((caddr_t) &trace_queue[unit]);
223         }
224
225         crit_exit();
226         
227         return(1);
228 }
229
230 /*---------------------------------------------------------------------------*
231  *      open trace device
232  *---------------------------------------------------------------------------*/
233 PDEVSTATIC int
234 i4btrcopen(struct dev_open_args *ap)
235 {
236         cdev_t dev = ap->a_head.a_dev;
237         int unit = minor(dev);
238
239         if(unit >= NI4BTRC)
240                 return(ENXIO);
241
242         if(device_state[unit] & ST_ISOPEN)
243                 return(EBUSY);
244
245         if(analyzemode && (unit == outunit || unit == rxunit || unit == txunit))
246                 return(EBUSY);
247
248         crit_enter();
249         
250         device_state[unit] = ST_ISOPEN;         
251
252         crit_exit();
253         
254         return(0);
255 }
256
257 /*---------------------------------------------------------------------------*
258  *      close trace device
259  *---------------------------------------------------------------------------*/
260 PDEVSTATIC int
261 i4btrcclose(struct dev_close_args *ap)
262 {
263         cdev_t dev = ap->a_head.a_dev;
264         int unit = minor(dev);
265         int i;
266         int cno = -1;
267
268         for(i=0; i < nctrl; i++)
269         {
270                 if((ctrl_desc[i].ctrl_type == CTRL_PASSIVE) &&
271                         (ctrl_desc[i].unit == unit))
272                 {
273                         cno = i;
274                         break;
275                 }
276         }
277
278         if(analyzemode && (unit == outunit))
279         {
280                 analyzemode = 0;                
281                 outunit = -1;
282                 
283                 if(cno >= 0)
284                 {
285                         (*ctrl_desc[cno].N_MGMT_COMMAND)(rxunit, CMR_SETTRACE, TRACE_OFF);
286                         (*ctrl_desc[cno].N_MGMT_COMMAND)(txunit, CMR_SETTRACE, TRACE_OFF);
287                 }
288                 rxunit = -1;
289                 txunit = -1;
290         }
291         
292         if(cno >= 0)
293         {
294                         (*ctrl_desc[cno].N_MGMT_COMMAND)(ctrl_desc[cno].unit, CMR_SETTRACE, TRACE_OFF);
295         }
296
297         crit_enter();
298         device_state[unit] = ST_IDLE;
299         crit_exit();
300         
301         return(0);
302 }
303
304 /*---------------------------------------------------------------------------*
305  *      read from trace device
306  *---------------------------------------------------------------------------*/
307 PDEVSTATIC int
308 i4btrcread(struct dev_read_args *ap)
309 {
310         cdev_t dev = ap->a_head.a_dev;
311         struct uio *uio = ap->a_uio;
312         struct mbuf *m;
313         int error = 0;
314         int unit = minor(dev);
315         
316         if(!(device_state[unit] & ST_ISOPEN))
317                 return(EIO);
318
319         crit_enter();
320         
321         while(IF_QEMPTY(&trace_queue[unit]) && (device_state[unit] & ST_ISOPEN))
322         {
323                 device_state[unit] |= ST_WAITDATA;
324                 
325                 if((error = tsleep((caddr_t) &trace_queue[unit],
326                                         PCATCH, "bitrc", 0 )) != 0)
327                 {
328                         device_state[unit] &= ~ST_WAITDATA;
329                         crit_exit();
330                         return(error);
331                 }
332         }
333
334         IF_DEQUEUE(&trace_queue[unit], m);
335
336         if(m && m->m_len)
337                 error = uiomove(m->m_data, m->m_len, uio);
338         else
339                 error = EIO;
340                 
341         if(m)
342                 i4b_Bfreembuf(m);
343
344         crit_exit();
345         
346         return(error);
347 }
348
349 /*---------------------------------------------------------------------------*
350  *      poll device
351  *---------------------------------------------------------------------------*/
352 PDEVSTATIC int
353 i4btrcpoll(struct dev_poll_args *ap)
354 {
355         return(ENODEV);
356 }
357
358 /*---------------------------------------------------------------------------*
359  *      device driver ioctl routine
360  *---------------------------------------------------------------------------*/
361 PDEVSTATIC int
362 i4btrcioctl(struct dev_ioctl_args *ap)
363 {
364         cdev_t dev = ap->a_head.a_dev;
365         int error = 0;
366         int unit = minor(dev);
367         i4b_trace_setupa_t *tsa;
368         int i;
369         int cno = -1;
370
371         /* find the first passive controller matching our unit no */
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         switch(ap->a_cmd)
384         {
385                 case I4B_TRC_SET:
386                         if(cno < 0)
387                                 return ENOTTY;
388                         (*ctrl_desc[cno].N_MGMT_COMMAND)(ctrl_desc[cno].unit, CMR_SETTRACE, (void *)*(unsigned int *)ap->a_data);
389                         break;
390
391                 case I4B_TRC_SETA:
392                         tsa = (i4b_trace_setupa_t *)ap->a_data;
393
394                         if(tsa->rxunit >= 0 && tsa->rxunit < NI4BTRC)
395                                 rxunit = tsa->rxunit;
396                         else
397                                 error = EINVAL;
398
399                         if(tsa->txunit >= 0 && tsa->txunit < NI4BTRC)
400                                 txunit = tsa->txunit;
401                         else
402                                 error = EINVAL;
403
404                         if(error)
405                         {
406                                 outunit = -1;
407                                 rxunit = -1;
408                                 txunit = -1;
409                         }
410                         else
411                         {
412                                 if(cno < 0)
413                                         return ENOTTY;
414                                         
415                                 outunit = unit;
416                                 analyzemode = 1;
417                                 (*ctrl_desc[cno].N_MGMT_COMMAND)(rxunit, CMR_SETTRACE, (int *)(tsa->rxflags & (TRACE_I | TRACE_D_RX | TRACE_B_RX)));
418                                 (*ctrl_desc[cno].N_MGMT_COMMAND)(txunit, CMR_SETTRACE, (int *)(tsa->txflags & (TRACE_I | TRACE_D_RX | TRACE_B_RX)));
419                         }
420                         break;
421
422                 case I4B_TRC_RESETA:
423                         analyzemode = 0;                
424                         outunit = -1;
425                         rxunit = -1;
426                         txunit = -1;
427                         break;
428                         
429                 default:
430                         error = ENOTTY;
431                         break;
432         }
433         return(error);
434 }
435
436 #endif /* NI4BTRC > 0 */