5832 EOF wireless usb (aka UWB)
[unleashed.git] / usr / src / uts / common / io / tirdwr.c
blobe42a17aeaf741184480b3beff881b0bbaa63236b
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
20 * CDDL HEADER END
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
31 #pragma ident "%Z%%M% %I% %E% SMI" /* from S5R4 1.4 */
34 * Transport Interface Library read/write module - issue 1
37 #include <sys/types.h>
38 #include <sys/param.h>
39 #include <sys/stream.h>
40 #include <sys/stropts.h>
41 #include <sys/tihdr.h>
42 #include <sys/debug.h>
43 #include <sys/errno.h>
44 #include <sys/kmem.h>
45 #include <sys/tirdwr.h>
46 #include <sys/conf.h>
47 #include <sys/modctl.h>
48 #include <sys/ddi.h>
49 #include <sys/sunddi.h>
51 #define ORDREL 002
52 #define DISCON 004
53 #define FATAL 010
54 #define WAITACK 020
55 #define TIRDWR_ID 4
58 * Per-Stream private data structure.
60 struct trw_trw {
61 queue_t *trw_rdq;
62 uint_t trw_flags;
66 * stream data structure definitions
68 static int tirdwropen(queue_t *q, dev_t *dev,
69 int flag, int sflag, cred_t *cr);
71 static int tirdwrclose(queue_t *q, int flag, cred_t *cr);
73 static int check_strhead(queue_t *q);
76 * To save instructions, since STREAMS ignores the return value
77 * from these functions, they are defined as void here. Kind of icky, but...
79 static void tirdwrrput(queue_t *q, mblk_t *mp);
80 static void tirdwrwput(queue_t *q, mblk_t *mp);
82 static struct module_info tirdwr_info = {
83 TIRDWR_ID,
84 "tirdwr",
86 INFPSZ,
87 4096,
88 1024
91 static struct qinit tirdwrrinit = {
92 (int (*)())tirdwrrput,
93 (int (*)())NULL,
94 tirdwropen,
95 tirdwrclose,
96 nulldev,
97 &tirdwr_info,
98 NULL
101 static struct qinit tirdwrwinit = {
102 (int (*)())tirdwrwput,
103 (int (*)())NULL,
104 tirdwropen,
105 tirdwrclose,
106 nulldev,
107 &tirdwr_info,
108 NULL
111 static struct streamtab trwinfo = {
112 &tirdwrrinit,
113 &tirdwrwinit,
114 NULL,
115 NULL
118 static struct fmodsw fsw = {
119 "tirdwr",
120 &trwinfo,
121 D_NEW|D_MTQPAIR|D_MP
124 static struct modlstrmod modlstrmod = {
125 &mod_strmodops, "xport interface rd/wr str mod", &fsw
128 static struct modlinkage modlinkage = {
129 MODREV_1, &modlstrmod, NULL
133 _init(void)
135 return (mod_install(&modlinkage));
139 _fini(void)
141 return (mod_remove(&modlinkage));
145 _info(struct modinfo *modinfop)
147 return (mod_info(&modlinkage, modinfop));
150 static void send_fatal(queue_t *q, mblk_t *mp);
151 static void strip_strhead(queue_t *q);
155 * tirdwropen - open routine gets called when the
156 * module gets pushed onto the stream.
158 /*ARGSUSED*/
159 static int
160 tirdwropen(
161 queue_t *q,
162 dev_t *dev,
163 int flag,
164 int sflag,
165 cred_t *cr)
167 struct trw_trw *trwptr;
169 /* check if already open */
170 if (q->q_ptr) {
171 return (0);
175 * Allocate a new trw_trw struct.
177 trwptr = kmem_alloc(sizeof (struct trw_trw), KM_SLEEP);
179 /* initialize data structure */
180 trwptr->trw_flags = 0;
181 trwptr->trw_rdq = q;
182 q->q_ptr = (caddr_t)trwptr;
183 WR(q)->q_ptr = (caddr_t)trwptr;
184 qprocson(q);
186 freezestr(q);
188 (void) strqset(WR(q), QMAXPSZ, 0, (uintptr_t)WR(q)->q_next->q_maxpsz);
189 (void) strqset(q, QMAXPSZ, 0, (uintptr_t)q->q_next->q_maxpsz);
191 if (!check_strhead(q)) {
192 unfreezestr(q);
193 qprocsoff(q);
194 kmem_free(trwptr, sizeof (struct trw_trw));
195 return (EPROTO);
197 strip_strhead(q);
198 unfreezestr(q);
200 return (0);
204 * tirdwrclose - This routine gets called when the module
205 * gets popped off of the stream.
208 /*ARGSUSED1*/
209 static int
210 tirdwrclose(queue_t *q, int flag, cred_t *cr)
212 struct trw_trw *trwptr;
213 mblk_t *mp;
214 union T_primitives *pptr;
216 qprocsoff(q);
217 trwptr = (struct trw_trw *)q->q_ptr;
219 ASSERT(trwptr != NULL);
222 * Send up a T_DISCON_IND if necessary.
224 if ((trwptr->trw_flags & ORDREL) && !(trwptr->trw_flags & FATAL))
225 if (mp = allocb(sizeof (struct T_discon_req), BPRI_LO)) {
226 pptr = (union T_primitives *)mp->b_rptr;
227 mp->b_wptr = mp->b_rptr + sizeof (struct T_ordrel_req);
228 pptr->type = T_ORDREL_REQ;
229 mp->b_datap->db_type = M_PROTO;
230 putnext(WR(q), mp);
233 kmem_free(trwptr, sizeof (struct trw_trw));
235 return (0);
239 * tirdwrrput - Module read queue put procedure.
240 * This is called from the module or
241 * driver downstream.
244 static void
245 tirdwrrput(queue_t *q, mblk_t *mp)
247 union T_primitives *pptr;
248 struct trw_trw *trwptr;
249 mblk_t *tmp;
251 trwptr = (struct trw_trw *)q->q_ptr;
253 ASSERT(trwptr != NULL);
255 if ((trwptr->trw_flags & FATAL) && !(trwptr->trw_flags & WAITACK)) {
256 freemsg(mp);
257 return;
260 switch (mp->b_datap->db_type) {
262 default:
263 putnext(q, mp);
264 break;
266 case M_DATA:
267 putnext(q, mp);
268 break;
270 case M_PCPROTO:
271 case M_PROTO:
272 /* is there enough data to check type */
273 if ((mp->b_wptr - mp->b_rptr) < sizeof (t_scalar_t)) {
274 /* malformed message */
275 freemsg(mp);
276 break;
278 pptr = (union T_primitives *)mp->b_rptr;
280 switch (pptr->type) {
282 case T_EXDATA_IND:
283 send_fatal(q, mp);
284 break;
285 case T_DATA_IND:
286 if (msgdsize(mp) == 0) {
287 freemsg(mp);
288 break;
291 tmp = (mblk_t *)unlinkb(mp);
292 freemsg(mp);
293 putnext(q, tmp);
294 break;
296 case T_ORDREL_IND:
297 trwptr->trw_flags |= ORDREL;
298 mp->b_datap->db_type = M_DATA;
299 mp->b_wptr = mp->b_rptr;
300 putnext(q, mp);
301 break;
303 case T_DISCON_IND:
304 trwptr->trw_flags |= DISCON;
305 trwptr->trw_flags &= ~ORDREL;
306 if (msgdsize(mp) != 0) {
307 tmp = (mblk_t *)unlinkb(mp);
308 putnext(q, tmp);
310 mp->b_datap->db_type = M_HANGUP;
311 mp->b_wptr = mp->b_rptr;
312 putnext(q, mp);
313 break;
315 default:
316 send_fatal(q, mp);
317 break;
324 * tirdwrwput - Module write queue put procedure.
325 * This is called from the module or
326 * stream head upstream.
328 static void
329 tirdwrwput(queue_t *q, mblk_t *mp)
331 struct trw_trw *trwptr;
333 trwptr = (struct trw_trw *)q->q_ptr;
335 ASSERT(trwptr != NULL);
337 if (trwptr->trw_flags & FATAL) {
338 freemsg(mp);
339 return;
342 switch (mp->b_datap->db_type) {
343 default:
344 putnext(q, mp);
345 break;
347 case M_DATA:
348 putnext(q, mp);
349 break;
351 case M_PROTO:
352 case M_PCPROTO:
353 send_fatal(q, mp);
354 break;
359 static void
360 send_fatal(queue_t *q, mblk_t *mp)
362 struct trw_trw *trwptr;
364 trwptr = (struct trw_trw *)q->q_ptr;
366 trwptr->trw_flags |= FATAL;
367 mp->b_datap->db_type = M_ERROR;
368 *mp->b_datap->db_base = EPROTO;
369 mp->b_rptr = mp->b_datap->db_base;
370 mp->b_wptr = mp->b_datap->db_base + sizeof (char);
371 freemsg(unlinkb(mp));
372 if (q->q_flag&QREADR)
373 putnext(q, mp);
374 else
375 qreply(q, mp);
378 static int
379 check_strhead(queue_t *q)
381 mblk_t *mp;
382 union T_primitives *pptr;
384 for (mp = q->q_next->q_first; mp != NULL; mp = mp->b_next) {
386 switch (mp->b_datap->db_type) {
387 case M_PROTO:
388 pptr = (union T_primitives *)mp->b_rptr;
389 if ((mp->b_wptr - mp->b_rptr) < sizeof (t_scalar_t))
390 return (0);
391 switch (pptr->type) {
393 case T_EXDATA_IND:
394 return (0);
395 case T_DATA_IND:
396 if (mp->b_cont &&
397 (mp->b_cont->b_datap->db_type != M_DATA))
398 return (0);
399 break;
400 default:
401 return (0);
403 break;
405 case M_PCPROTO:
406 return (0);
408 case M_DATA:
409 case M_SIG:
410 break;
411 default:
412 return (0);
415 return (1);
418 static void
419 strip_strhead(queue_t *q)
421 mblk_t *mp;
422 mblk_t *emp;
423 mblk_t *tmp;
424 union T_primitives *pptr;
426 q = q->q_next;
427 /*CSTYLED*/
428 for (mp = q->q_first; mp != NULL; ) {
430 switch (mp->b_datap->db_type) {
431 case M_PROTO:
432 pptr = (union T_primitives *)mp->b_rptr;
433 switch (pptr->type) {
435 case T_DATA_IND:
436 if (msgdsize(mp) == 0) {
437 strip0:
438 tmp = mp->b_next;
439 rmvq(q, mp);
440 freemsg(mp);
441 mp = tmp;
442 break;
444 emp = mp->b_next;
445 rmvq(q, mp);
446 tmp = (mblk_t *)unlinkb(mp);
447 freeb(mp);
448 (void) insq(q, emp, tmp);
449 mp = emp;
450 break;
452 break;
454 case M_DATA:
455 if (msgdsize(mp) == 0)
456 goto strip0;
457 mp = mp->b_next;
458 break;
460 case M_SIG:
461 mp = mp->b_next;
462 break;