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