1 /* 2 * Datakit driver 3 * SCCSID[] = "@(#)dk.c 2.1 DKHOST 84/07/03" 4 */ 5 6 #include "datakit.h" 7 #if NDATAKIT>0 8 9 #include "param.h" 10 #include "../machine/pte.h" 11 #include "signal.h" 12 #include "errno.h" 13 #include "conf.h" 14 #include "user.h" 15 #include "ioctl.h" 16 #include "tty.h" 17 #include "vnode.h" 18 #include "file.h" 19 #include "systm.h" 20 #include "proc.h" 21 #include "mbuf.h" 22 #include "buf.h" 23 #include "uio.h" 24 #include "kernel.h" 25 #include "dkit.h" 26 #include "dkcmc.h" 27 #include "dk.h" 28 #include "dkdev.h" 29 #include "syslog.h" 30 31 extern int dkdebug ; 32 33 #define DKBUFUSE 5 /* max buffers /channel */ 34 35 36 int dk_nchan = NDATAKIT; 37 struct dkdev dkdev[NDATAKIT]; 38 struct dksetupreq *dkreq[NDATAKIT]; 39 40 41 42 43 #ifdef MONITOR 44 int dummy ; 45 int *DKP2 = &dummy ; 46 #define M_ON(a) *DKP2 |= (a) 47 #define M_OFF(a) *DKP2 &= ~(a) 48 49 #define Mread 0400 50 #define Mrslp 01000 51 #define Mrcpy 02000 52 #define Mwrite 04000 53 #define Mwcpy 010000 54 55 #else 56 #define M_ON(a) 57 #define M_OFF(a) 58 #endif 59 60 61 62 /*ARGSUSED*/ 63 dkioctl(dev, cmd, data, flag) 64 register caddr_t data; 65 { 66 register struct dkdev *tp; 67 register chanstat ; 68 int chan, sp_chan; 69 int s, error = 0; 70 register short *pp ; 71 struct dkdev *tsp; 72 extern dkidone() ; 73 struct diocdial dialreq; 74 extern int commchan; 75 76 chan = dev = minor(dev); 77 tp = &dkdev[chan]; 78 pp = (short *) data; 79 switch(cmd) { 80 case DIOCEXCL: 81 tp->d_state |= DKXCLUDE ; 82 break ; 83 case DIOCNXCL: 84 tp->d_state &= ~DKXCLUDE ; 85 break ; 86 case DIOCSETK: 87 dkdebug = pp[0] ; 88 break; 89 case DIOCQQABO: 90 pp[0] = tp->d_rresid; 91 pp[1] = tp->d_rdone; 92 pp[2] = tp->d_rctl; 93 break ; 94 case DIOCRMODE: 95 if (pp[0] & DKR_TIME) 96 tp->d_rmode = (DKR_TIME | DKR_BLOCK); 97 else tp->d_rmode = pp[0] ; 98 break ; 99 case DIOCXCTL: 100 tp->d_xctl = pp[0] ; 101 break ; 102 case DIOCFLUSH: 103 dk_cmd(chan, DKC_XINIT|DKC_FLUSH); 104 break; 105 case KIOCINIT: 106 dk_cmd(chan, DKC_XINIT); 107 break; 108 case DIOCXWIN: 109 return dk_winsize(chan, (struct diocxwin *)data); 110 case DIOCRESET: 111 if (chan != 1 && chan != pp[0]) return EACCES; 112 if (pp[0] > 1 && pp[0] < commchan) return EINVAL; 113 if (pp[0] < 0 || pp[0] >= dk_nchan) return EINVAL; 114 if (pp[0] == 0) return -dk_close(0); 115 else dk_reset(pp[0]); 116 break; 117 case DIOCCTYPE: 118 if (tp->d_ctype == NULL) { 119 struct mbuf *m; 120 121 MGET(m, M_WAIT, DKMT_CTYPE); 122 if (m == NULL) 123 return ENOBUFS; 124 tp->d_ctype = mtod(m, struct diocctype *); 125 } 126 return bcopy(data, (caddr_t) tp->d_ctype, sizeof (struct diocctype)); 127 case DIOCINFO: 128 ((struct diocinfo *)data)->dioc_nchan = dk_nchan; 129 ((struct diocinfo *)data)->dioc_channum = chan; 130 ((struct diocinfo *)data)->dioc_commchan = commchan; 131 break; 132 case DIOCSTAT: 133 if (*((int *)data) < 0 || *((int *)data) >= dk_nchan) 134 return EINVAL; 135 *((int *)data) = dk_status(*((int *)data)); 136 break; 137 case FIONBIO: 138 if (*(int *)data) 139 tp->dc_state |= DK_NDELAY; 140 else 141 tp->dc_state &= ~DK_NDELAY; 142 break; 143 case FIOASYNC: 144 if (*(int *)data) 145 tp->dc_state |= DK_ASYNC; 146 else 147 tp->dc_state &= ~DK_ASYNC; 148 break; 149 case TIOCGPGRP: 150 *(int *)data = tp->d_pgrp; 151 break; 152 case TIOCSPGRP: 153 tp->d_pgrp = *(int *)data; 154 break; 155 156 /* splice chan to file descriptor */ 157 case DKIOCSPL: 158 error = copyin(*(caddr_t *)data, (caddr_t) tp->d_param, 159 3*sizeof (short)); 160 if (error) return error; 161 if ((error = dkgetdev(tp->d_param[0], &sp_chan)) <= 0) 162 return error ; 163 if (sp_chan == chan) 164 return EINVAL ; 165 tsp = &dkdev[sp_chan] ; 166 tp->dc_state |= DKSETUP ; 167 tsp->dc_state |= DKSETUP ; 168 if (dk_splice(chan, sp_chan, dkidone, (caddr_t) tp, 169 (caddr_t) tsp)) { 170 tp->dc_state &= ~DKSETUP ; 171 tsp->dc_state &= ~DKSETUP ; 172 return EIO ; 173 } 174 s = spl5() ; 175 error = 0; 176 while (error == 0 && tp->dc_state & DKSETUP) 177 error = tsleep((caddr_t)tp, TTOPRI, ttopen, 0); 178 while (error == 0 && tsp->dc_state & DKSETUP) 179 error = tsleep((caddr_t)tsp, TTOPRI, ttopen, 0); 180 splx(s) ; 181 if (error) 182 return (error); 183 if ((dk_status(chan) & DK_RESET) || (dk_status(sp_chan) & DK_RESET)) 184 return EIO ; 185 if (tp->d_error || tsp->d_error) 186 return EIO ; 187 error = copyout((caddr_t) tp->d_param, *(caddr_t *)data, 188 3*sizeof (short)); 189 if (error) return error; 190 break ; 191 192 case DIOCSWAIT: 193 error = dksplwait(chan); 194 break ; 195 196 default: 197 if ((cmd & DKIOCMASK) != DKIOCVAL) { 198 return ENOTTY ; 199 } 200 if (cmd == DKIODIAL) { 201 error = copyin(*(caddr_t *)data, (caddr_t) &dialreq, 202 sizeof (struct diocdial)); 203 if (error) return error; 204 if (error = dkiodial(chan, dialreq.dialstring)) 205 return error; 206 tp->dc_state |= DKSETUP ; 207 chanstat = dk_setup(minor(dev), (int) DKIOCREQ, 0, 208 0, 0, (int) u.u_uid, dkidone, (caddr_t)tp) ; 209 } 210 else { 211 error = copyin(*(caddr_t *)data, (caddr_t) tp->d_param, 212 3*sizeof (short)); 213 if (error) return error; 214 tp->dc_state |= DKSETUP ; 215 chanstat = dk_setup(minor(dev), cmd, 0, 0, 0, 216 (int) u.u_uid, dkidone, (caddr_t)tp) ; 217 } 218 if (chanstat) { 219 tp->dc_state &= ~DKSETUP ; 220 return (chanstat < 0 ? ECONNREFUSED : chanstat); 221 } 222 s = spl5() ; 223 error = 0; 224 while (error == 0 && tp->dc_state & DKSETUP) 225 error = tsleep((caddr_t)(tp), TTOPRI, ttyout, 0) ; 226 splx(s) ; 227 if (error) 228 return error; 229 error = copyout((caddr_t) tp->d_param, *(caddr_t *)data, 230 3*sizeof (short)); 231 if (error) return error; 232 if (dk_status(minor(dev)) & DK_RESET) 233 return ENETRESET ; 234 if (tp->d_error) 235 return EIO ; 236 break ; 237 } 238 return error; 239 } 240 241 #define DS_SIZE 64 242 static 243 dkiodial(chan, user_ds) 244 register char *user_ds; 245 { 246 register caddr_t ds; 247 register n; 248 register struct mbuf *mb; 249 int u_count; 250 251 mb = m_get(M_WAIT, DKMT_DATA); 252 if (mb == NULL) return ENOBUFS; 253 ds = mtod(mb, caddr_t); 254 for (u_count = 0; u_count < MLEN - 6; u_count++) { 255 *ds = *user_ds; 256 if (*ds == '\n' || *ds == '\0') break; 257 ds++; 258 user_ds++; 259 } 260 *ds = '\n'; 261 u_count++; 262 263 /* add uid in char decimal */ 264 265 ds++; 266 u_count++; 267 for (n = u.u_uid; n /= 10; ds++) u_count++; 268 for (n = u.u_uid;; ds--) { 269 *ds = n % 10 + '0'; 270 if ((n /= 10) == 0) break; 271 } 272 273 mb->m_len = u_count; 274 if (dk_xmit(chan, mb, 1, 0, (int (*)()) 0, (caddr_t) 0) == 0) { 275 return(EIO); 276 } 277 else return(0); 278 } 279 /* 280 * End action for ioctl completion 281 */ 282 /*ARGSUSED*/ 283 dkidone(tp, chan, err, p0, p1, p2) 284 register struct dkdev *tp ; 285 short chan, p0, p1, p2 ; 286 { 287 tp->d_error = err ; 288 tp->d_param[0] = p0 ; 289 tp->d_param[1] = p1 ; 290 tp->d_param[2] = p2 ; 291 tp->dc_state &= ~DKSETUP ; 292 wakeup((caddr_t)tp) ; 293 } 294 295 296 297 298 /*ARGSUSED*/ 299 dkopen(dev, flag) 300 { 301 register struct dkdev *tp; 302 register chan; 303 register struct nameidata *ndp = &u.u_nd; /* XXX */ 304 struct proc *p = u.u_procp; /* XXX */ 305 struct vnode *vp; 306 struct file *fp; 307 int m, error; 308 309 #ifdef lint 310 (void) dk_xint(0, 0); 311 #endif 312 dev = minor(dev); 313 if (dev == 1) { 314 return 0; /* Maintenance channel */ 315 } 316 317 chan = dev; 318 if (chan >= dk_nchan) { 319 /* debug */ log(LOG_ERR, "dkopen bad: chan>=NDKCHANS : %d\n",chan); 320 return ENXIO; 321 } 322 323 tp = &dkdev[chan]; 324 if ((tp->d_state & DKOPEN) == 0) 325 tp->dc_state = 0 ; 326 if (tp->d_state&DKXCLUDE && u.u_procp->p_ruid!=0) { 327 return EBUSY; 328 } 329 330 if ((m = dk_open(chan, (int (*)()) NULL)) < 0) 331 return -m; 332 333 334 /* 335 * Channel 0 is reserved for maintenance. 336 * An open on channel 0 is interpreted as a request 337 * for an unused channel. 338 */ 339 if (chan==0) { 340 char dname[30]; 341 342 chan = m ; 343 tp = &dkdev[chan] ; 344 tp->dc_state = 0 ; 345 /* 346 * throw away vnode for dk0. (/dev/dk/dial) 347 * Build standard name of new one, and ask namei for it. 348 */ 349 fp = u.u_ofile[-1 - p->p_dupfd]; 350 351 dksnamer(dname, chan); 352 /* log(LOG_ERR, "dname=%s chan=%d\n", dname, chan); */ 353 ndp->ni_nameiop = FOLLOW | LOOKUP | LOCKLEAF; 354 ndp->ni_segflg = UIO_SYSSPACE; 355 ndp->ni_dirp = dname; 356 if (error = namei(ndp)) { 357 (void) dk_close(chan) ; 358 return (error); 359 } 360 361 /* Give back old one */ 362 vp = (struct vnode *) fp->f_data; 363 VOP_LOCK(vp); 364 vput(vp); 365 366 vp = ndp->ni_vp; 367 fp->f_data = (caddr_t) vp; 368 VOP_UNLOCK(vp); 369 } 370 if ((tp->d_state & DKOPEN) == 0) { 371 tp->d_state |= DKOPEN ; 372 tp->dc_state = 0; 373 tp->d_rmode = 0 ; 374 tp->d_xctl = 0 ; 375 tp->d_pgrp = 0; 376 } 377 tp->d_prot |= DpURP; 378 return 0; 379 } 380 381 /* Policy decision here -- standard name of dk file known to this routine */ 382 dksnamer(s, n) register char *s; 383 { 384 register char *p = "/dev/dk/dk"; 385 386 while (*s++ = *p++) 387 ; 388 s--; 389 *s++ = '0' + (n/100); n %= 100; 390 *s++ = '0' + (n/10); n %= 10; 391 *s++ = '0' + n; 392 *s = '\0'; 393 } 394 395 /* 396 * Close a channel: 397 */ 398 399 /*ARGSUSED*/ 400 dkclose(dev, flag) 401 dev_t dev; 402 int flag; 403 { 404 register struct dkdev *tp; 405 extern wakeup() ; 406 extern brelse() ; 407 short s, chan ; 408 int i, cl = 0; 409 410 chan = minor(dev); 411 tp = &dkdev[chan]; 412 if (chan == 1) { 413 return 0; /* Maintenance channel */ 414 } 415 s = spl5() ; 416 if (u.u_signal[SIGKILL] != SIG_IGN) { /* detect close from exit() */ 417 while (tp->d_bufct) { 418 tp->d_state |= DKWAIT ; 419 if (tsleep((caddr_t)(&tp->d_state), TTOPRI, ttyout, 0)) 420 break; 421 } 422 } 423 else if (tp->d_bufct) 424 /* Hmm -- buffers queued. Let's wait 15 seconds max */ 425 for (i = 0; tp->d_bufct && i < 15; i++) { 426 tp->d_state |= DKWAIT ; 427 if (tsleep((caddr_t)(&tp->d_state), TTOPRI, ttyout, hz)) 428 break; 429 } 430 splx(s) ; 431 tp->dc_state = 0; 432 tp->d_rmode = 0; 433 tp->d_prot &= ~DpURP; 434 if(!tp->d_prot){ 435 cl = dk_close(chan); 436 (void) dk_takedown(chan); 437 tp->d_state = 0; 438 } 439 return -cl; 440 } 441 442 dkread(dev, uio) 443 dev_t dev ; 444 struct uio *uio; 445 { 446 register struct dkdev *tp ; 447 int err; 448 449 M_ON(Mread) ; 450 tp = &dkdev[minor(dev)] ; 451 err = dkuread(minor(dev), uio) ; 452 tp->d_rresid = uio->uio_resid ; 453 M_OFF(Mread) ; 454 return err; 455 } 456 457 458 dkwrite(dev, uio) 459 struct uio *uio; 460 dev_t dev ; 461 { 462 int err; 463 464 M_ON(Mwrite) ; 465 err = dkuwrite(minor(dev), uio) ; 466 M_OFF(Mwrite) ; 467 return err; 468 } 469 470 #endif 471