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