BSD 4_1_snap development
[unix-history] / sys / dev / mx1.c
CommitLineData
01395141
C
1/* mx1.c 4.6 81/03/11 */
2
3#include "../h/param.h"
4#include "../h/systm.h"
5#include "../h/dir.h"
6#include "../h/user.h"
7#include "../h/reg.h"
8#include "../h/proc.h"
9#include "../h/tty.h"
10#include "../h/inode.h"
11#include "../h/mx.h"
12#include "../h/file.h"
13#include "../h/conf.h"
14
15/*
16 * Multiplexor: clist version
17 *
18 * installation:
19 * requires a line in cdevsw -
20 * mxopen, mxclose, mxread, mxwrite, mxioctl, 0,
21 *
22 * also requires a line in linesw -
23 * mxopen, mxclose, mcread, mcwrite, mxioctl, nulldev, nulldev,
24 *
25 * The linesw entry for mpx should be the last one in the table.
26 * 'nldisp' (number of line disciplines) should not include the
27 * mpx line. This is to prevent mpx from being enabled by an ioctl.
28 */
29struct chan chans[NCHANS];
30struct schan schans[NPORTS];
31struct group *groups[NGROUPS];
32int mpxline;
33struct chan *xcp();
34dev_t mpxdev = -1;
35
36
37char mcdebugs[NDEBUGS];
38
39
40/*
41 * Allocate a channel, set c_index to index.
42 */
43struct chan *
44challoc(index, isport)
45{
46register s,i;
47register struct chan *cp;
48
49 s = spl6();
50 for(i=0;i<((isport)?NPORTS:NCHANS);i++) {
51 cp = (isport)? (struct chan *)(schans+i): chans+i;
52 if(cp->c_group == NULL) {
53 cp->c_index = index;
54 cp->c_pgrp = 0;
55 cp->c_flags = 0;
56 splx(s);
57 return(cp);
58 }
59 }
60 splx(s);
61 return(NULL);
62}
63
64
65
66/*
67 * Allocate a group table cell.
68 */
69gpalloc()
70{
71 register i;
72
73 for (i=NGROUPS-1; i>=0; i--)
74 if (groups[i]==NULL) {
75 groups[i]++;
76 return(i);
77 }
78 u.u_error = ENXIO;
79 return(i);
80}
81
82
83/*
84 * Add a channel to the group in
85 * inode ip.
86 */
87struct chan *
88addch(ip, isport)
89struct inode *ip;
90{
91register struct chan *cp;
92register struct group *gp;
93register i;
94
95 plock(ip);
96 gp = &ip->i_un.i_group;
97 for(i=0;i<NINDEX;i++) {
98 cp = (struct chan *)gp->g_chans[i];
99 if (cp == NULL) {
100 if ((cp=challoc(i, isport)) != NULL) {
101 gp->g_chans[i] = cp;
102 cp->c_group = gp;
103 }
104 break;
105 }
106 cp = NULL;
107 }
108 prele(ip);
109 return(cp);
110}
111
112/*
113 * Mpxchan system call.
114 */
115
116mpxchan()
117{
118 extern mxopen(), mcread(), sdata(), scontrol();
119 struct inode *ip, *gip;
120 struct tty *tp;
121 struct file *fp, *chfp, *gfp;
122 struct chan *cp;
123 struct group *gp, *ngp;
124 struct mx_args vec;
125 struct a {
126 int cmd;
127 int *argvec;
128 } *uap;
129 dev_t dev;
130 register int i;
131
132 /*
133 * Common setup code.
134 */
135
136 uap = (struct a *)u.u_ap;
137 (void) copyin((caddr_t)uap->argvec, (caddr_t)&vec, sizeof vec);
138 gp = NULL; gfp = NULL; cp = NULL;
139
140 switch(uap->cmd) {
141
142 case NPGRP:
143 if (vec.m_arg[1] < 0)
144 break;
145 case CHAN:
146 case JOIN:
147 case EXTR:
148 case ATTACH:
149 case DETACH:
150 case CSIG:
151 gfp = getf(vec.m_arg[1]);
152 if (gfp==NULL)
153 return;
154 gip = gfp->f_inode;
155 gp = &gip->i_un.i_group;
156 if (gp->g_inode != gip) {
157 u.u_error = ENXIO;
158 return;
159 }
160 }
161
162 switch(uap->cmd) {
163
164 /*
165 * Create an MPX file.
166 */
167
168 case MPX:
169 case MPXN:
170 if (mpxdev < 0) {
171 for (i=0; linesw[i].l_open; i++) {
172 if (linesw[i].l_read==mcread) {
173 mpxline = i;
174 for (i=0; cdevsw[i].d_open; i++) {
175 if (cdevsw[i].d_open==mxopen) {
176 mpxdev = (dev_t)(i<<8);
177 }
178 }
179 }
180 }
181 if (mpxdev < 0) {
182 u.u_error = ENXIO;
183 return;
184 }
185 }
186 if (uap->cmd==MPXN) {
187 if ((ip=ialloc(pipedev))==NULL)
188 return;
189 ip->i_mode = ((vec.m_arg[1]&0777)+IFMPC) & ~u.u_cmask;
190 ip->i_flag = IACC|IUPD|ICHG;
191 } else {
192 u.u_dirp = vec.m_name;
193 ip = namei(uchar,1);
194 if (ip != NULL) {
195 i = ip->i_mode&IFMT;
196 u.u_error = EEXIST;
197 if (i==IFMPC || i==IFMPB) {
198 i = minor(ip->i_un.i_rdev);
199 gp = groups[i];
200 if (gp && gp->g_inode==ip)
201 u.u_error = EBUSY;
202 }
203 iput(ip);
204 return;
205 }
206 if (u.u_error)
207 return;
208 ip = maknode((vec.m_arg[1]&0777)+IFMPC);
209 if (ip == NULL)
210 return;
211 }
212 if ((i=gpalloc()) < 0) {
213 iput(ip);
214 return;
215 }
216 if ((fp=falloc()) == NULL) {
217 iput(ip);
218 groups[i] = NULL;
219 return;
220 }
221 ip->i_un.i_rdev = (daddr_t)(mpxdev+i);
222 ip->i_count++;
223 prele(ip);
224
225 gp = &ip->i_un.i_group;
226 groups[i] = gp;
227 gp->g_inode = ip;
228 gp->g_state = INUSE|ISGRP;
229 gp->g_group = NULL;
230 gp->g_file = fp;
231 gp->g_index = 0;
232 gp->g_rotmask = 1;
233 gp->g_rot = 0;
234 gp->g_datq = 0;
235 for(i=0;i<NINDEX;)
236 gp->g_chans[i++] = NULL;
237
238 fp->f_flag = FREAD|FWRITE|FMP;
239 fp->f_inode = ip;
240 fp->f_un.f_chan = NULL;
241 return;
242
243 /*
244 * join file descriptor (arg 0) to group (arg 1)
245 * return channel number
246 */
247
248 case JOIN:
249 if ((fp=getf(vec.m_arg[0]))==NULL)
250 return;
251 ip = fp->f_inode;
252 switch (ip->i_mode & IFMT) {
253
254 case IFMPC:
255 if ((fp->f_flag&FMP) != FMP) {
256 u.u_error = ENXIO;
257 return;
258 }
259 ngp = &ip->i_un.i_group;
260 if (mtree(ngp, gp) == NULL)
261 return;
262 fp->f_count++;
263 u.u_r.r_val1 = cpx((struct chan *)ngp);
264 return;
265
266 case IFCHR:
267 dev = (dev_t)ip->i_un.i_rdev;
268 tp = cdevsw[major(dev)].d_ttys;
269 if (tp==NULL) {
270 u.u_error = ENXIO;
271 return;
272 }
273 tp = &tp[minor(dev)];
274 if (tp->t_chan) {
275 u.u_error = ENXIO;
276 return;
277 }
278 if ((cp=addch(gip, 1))==NULL) {
279 u.u_error = ENXIO;
280 return;
281 }
282 tp->t_chan = cp;
283 cp->c_fy = fp;
284 fp->f_count++;
285 cp->c_ttyp = tp;
286 cp->c_line = tp->t_line;
287 cp->c_flags = XGRP+PORT;
288 u.u_r.r_val1 = cpx(cp);
289 return;
290
291 default:
292 u.u_error = ENXIO;
293 return;
294
295 }
296
297 /*
298 * Attach channel (arg 0) to group (arg 1).
299 */
300
301 case ATTACH:
302 cp = xcp(gp, vec.m_arg[0]);
303 if (cp==NULL || cp->c_flags&ISGRP) {
304 u.u_error = ENXIO;
305 return;
306 }
307 u.u_r.r_val1 = cpx(cp);
308 wakeup((caddr_t)cp);
309 return;
310
311 case DETACH:
312 cp = xcp(gp, vec.m_arg[0]);
313 if (cp==NULL) {
314 u.u_error = ENXIO;
315 return;
316 }
317 (void) detach(cp);
318 return;
319
320 /*
321 * Extract channel (arg 0) from group (arg 1).
322 */
323
324 case EXTR:
325 cp = xcp(gp, vec.m_arg[0]);
326 if (cp==NULL) {
327 u.u_error = ENXIO;
328 return;
329 }
330 if (cp->c_flags & ISGRP) {
331 (void) mxfalloc(((struct group *)cp)->g_file);
332 return;
333 }
334 if ((fp=cp->c_fy) != NULL) {
335 (void) mxfalloc(fp);
336 return;
337 }
338 if ((fp=falloc()) == NULL)
339 return;
340 fp->f_inode = gip;
341 gip->i_count++;
342 fp->f_un.f_chan = cp;
343 fp->f_flag = (vec.m_arg[2]) ?
344 (FREAD|FWRITE|FMPY) : (FREAD|FWRITE|FMPX);
345 cp->c_fy = fp;
346 return;
347
348 /*
349 * Make new chan on group (arg 1).
350 */
351
352 case CHAN:
353 if((gfp->f_flag&FMP)==FMP)cp = addch(gip, 0);
354 if(cp == NULL){
355 u.u_error = ENXIO;
356 return;
357 }
358 cp->c_flags = XGRP;
359 cp->c_fy = NULL;
360 cp->c_ttyp = cp->c_ottyp = (struct tty *)cp;
361 cp->c_line = cp->c_oline = mpxline;
362 u.u_r.r_val1 = cpx(cp);
363 return;
364
365 /*
366 * Connect fd (arg 0) to channel fd (arg 1).
367 * (arg 2 < 0) => fd to chan only
368 * (arg 2 > 0) => chan to fd only
369 * (arg 2 == 0) => both directions
370 */
371
372 case CONNECT:
373 if ((fp=getf(vec.m_arg[0]))==NULL)
374 return;
375 if ((chfp=getf(vec.m_arg[1]))==NULL)
376 return;
377 ip = fp->f_inode;
378 i = ip->i_mode&IFMT;
379 if (i!=IFCHR) {
380 u.u_error = ENXIO;
381 return;
382 }
383 dev = (dev_t)ip->i_un.i_rdev;
384 tp = cdevsw[major(dev)].d_ttys;
385 if (tp==NULL) {
386 u.u_error = ENXIO;
387 return;
388 }
389 tp = &tp[minor(dev)];
390 if (!(chfp->f_flag&FMPY)) {
391 u.u_error = ENXIO;
392 return;
393 }
394 cp = chfp->f_un.f_chan;
395 if (cp==NULL || cp->c_flags&PORT) {
396 u.u_error = ENXIO;
397 return;
398 }
399 i = vec.m_arg[2];
400 if (i>=0) {
401 cp->c_ottyp = tp;
402 cp->c_oline = tp->t_line;
403 }
404 if (i<=0) {
405 tp->t_chan = cp;
406 cp->c_ttyp = tp;
407 cp->c_line = tp->t_line;
408 }
409 u.u_r.r_val1 = 0;
410 return;
411
412 case NPGRP: {
413 register struct proc *pp;
414
415 if (gp != NULL) {
416 cp = xcp(gp, vec.m_arg[0]);
417 if (cp==NULL) {
418 u.u_error = ENXIO;
419 return;
420 }
421 }
422 pp = u.u_procp;
423 pp->p_pgrp = pp->p_pid;
424 if (vec.m_arg[2])
425 pp->p_pgrp = vec.m_arg[2];
426 if (gp != NULL)
427 cp->c_pgrp = pp->p_pgrp;
428 u.u_r.r_val1 = pp->p_pgrp;
429 return;
430 }
431
432 case CSIG:
433 cp = xcp(gp, vec.m_arg[0]);
434 if (cp==NULL) {
435 u.u_error = ENXIO;
436 return;
437 }
438 gsignal(cp->c_pgrp, vec.m_arg[2]);
439 u.u_r.r_val1 = vec.m_arg[2];
440 return;
441
442 case DEBUG:
443 i = vec.m_arg[0];
444 if (i<0 || i>NDEBUGS)
445 return;
446 mcdebugs[i] = vec.m_arg[1];
447 if (i==ALL)
448 for(i=0;i<NDEBUGS;i++)
449 mcdebugs[i] = vec.m_arg[1];
450 return;
451
452 default:
453 u.u_error = ENXIO;
454 return;
455 }
456
457}
458detach(cp)
459register struct chan *cp;
460{
461 register struct group *master,*sub;
462 register index;
463
464 if (cp==NULL)
465 return(0);
466 if (cp->c_flags&ISGRP) {
467 sub = (struct group *)cp;
468 master = sub->g_group; index = sub->g_index;
469 closef(sub->g_file);
470 if (master != NULL)
471 master->g_chans[index] = NULL;
472 return(0);
473 } else if (cp->c_flags&PORT && cp->c_ttyp != NULL) {
474 closef(cp->c_fy);
475 chdrain(cp);
476 chfree(cp);
477 return(0);
478 }
479 if (cp->c_flags & WCLOSE) {
480 if (cp->c_fy) {
481 if (cp->c_fy->f_count)
482 return(1);
483 chdrain(cp);
484 chfree(cp);
485 return(0);
486 }
487 }
488 cp->c_flags |= WCLOSE;
489 chwake(cp);
490 return(1);
491}
492
493
494mxfalloc(fp)
495register struct file *fp;
496{
497register i;
498
499 if (fp==NULL) {
500 u.u_error = ENXIO;
501 return(-1);
502 }
503 i = ufalloc();
504 if (i < 0)
505 return(i);
506 u.u_ofile[i] = fp;
507 fp->f_count++;
508 u.u_r.r_val1 = i;
509 return(i);
510}
511
512/*
513 * Grow a branch on a tree.
514 */
515
516mtree(sub,master)
517register struct group *sub, *master;
518{
519 register i;
520 int mtresiz, stresiz;
521
522 if ((mtresiz=mup(master,sub)) == NULL) {
523 u.u_error = ENXIO;
524 return(NULL);
525 }
526 if ((stresiz=mdown(sub,master)) <= 0) {
527 u.u_error = ENXIO;
528 return(NULL);
529 }
530 if (sub->g_group != NULL) {
531 u.u_error = ENXIO;
532 return(NULL);
533 }
534 if (stresiz+mtresiz > NLEVELS) {
535 u.u_error = ENXIO;
536 return(NULL);
537 }
538 for (i=0;i<NINDEX;i++) {
539 if (master->g_chans[i] != NULL)
540 continue;
541 master->g_chans[i] = (struct chan *)sub;
542 sub->g_group = master;
543 sub->g_index = i;
544 return(1);
545 }
546 u.u_error = ENXIO;
547 return(NULL);
548}
549
550mup(master,sub)
551struct group *master, *sub;
552{
553 register struct group *top;
554 register int depth;
555
556 depth = 1; top = master;
557 while (top->g_group) {
558 depth++;
559 top = top->g_group;
560 }
561 if(top == sub)
562 return(NULL);
563 return(depth);
564}
565
566
567mdown(sub,master)
568struct group *sub, *master;
569{
570 register int maxdepth, i, depth;
571
572 if(sub == (struct group *)NULL || (sub->g_state&ISGRP) == 0)
573 return(0);
574 if(sub == master)
575 return(-1);
576 maxdepth = 0;
577 for(i=0; i<NINDEX; i++) {
578 if((depth=mdown((struct group *)sub->g_chans[i],master)) == -1)
579 return(-1);
580 maxdepth = (depth>maxdepth) ? depth: maxdepth;
581 }
582 return(maxdepth+1);
583}