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 "inode.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; 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 u.u_error = copyin(*(caddr_t *)data, (caddr_t) tp->d_param, 159 3*sizeof (short)); 160 if (u.u_error) return u.u_error; 161 if ((sp_chan = dkgetdev(tp->d_param[0])) <= 0) 162 return u.u_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 while (tp->dc_state & DKSETUP) 176 sleep((caddr_t) tp, TTOPRI); 177 while (tsp->dc_state & DKSETUP) 178 sleep((caddr_t) tsp, TTOPRI); 179 splx(s) ; 180 if ((dk_status(chan) & DK_RESET) || (dk_status(sp_chan) & DK_RESET)) 181 return EIO ; 182 if (tp->d_error || tsp->d_error) 183 return EIO ; 184 u.u_error = copyout((caddr_t) tp->d_param, *(caddr_t *)data, 185 3*sizeof (short)); 186 if (u.u_error) return u.u_error; 187 break ; 188 189 case DIOCSWAIT: 190 (void) dksplwait(chan) ; 191 break ; 192 193 default: 194 if ((cmd & DKIOCMASK) != DKIOCVAL) { 195 return ENOTTY ; 196 } 197 if (cmd == DKIODIAL) { 198 u.u_error = copyin(*(caddr_t *)data, (caddr_t) &dialreq, 199 sizeof (struct diocdial)); 200 if (u.u_error) return u.u_error; 201 if (u.u_error = dkiodial(chan, dialreq.dialstring)) 202 return u.u_error; 203 tp->dc_state |= DKSETUP ; 204 chanstat = dk_setup(minor(dev), (int) DKIOCREQ, 0, 205 0, 0, (int) u.u_uid, dkidone, (caddr_t)tp) ; 206 } 207 else { 208 u.u_error = copyin(*(caddr_t *)data, (caddr_t) tp->d_param, 209 3*sizeof (short)); 210 if (u.u_error) return u.u_error; 211 tp->dc_state |= DKSETUP ; 212 chanstat = dk_setup(minor(dev), cmd, 0, 0, 0, 213 (int) u.u_uid, dkidone, (caddr_t)tp) ; 214 } 215 if (chanstat) { 216 tp->dc_state &= ~DKSETUP ; 217 return (chanstat < 0 ? ECONNREFUSED : chanstat); 218 } 219 s = spl5() ; 220 while (tp->dc_state & DKSETUP) 221 sleep((caddr_t)(tp), TTOPRI) ; 222 splx(s) ; 223 u.u_error = copyout((caddr_t) tp->d_param, *(caddr_t *)data, 224 3*sizeof (short)); 225 if (u.u_error) return u.u_error; 226 if (dk_status(minor(dev)) & DK_RESET) 227 return ENETRESET ; 228 if (tp->d_error) 229 return EIO ; 230 break ; 231 } 232 return 0; 233 } 234 235 #define DS_SIZE 64 236 static 237 dkiodial(chan, user_ds) 238 register char *user_ds; 239 { 240 register caddr_t ds; 241 register n; 242 register struct mbuf *mb; 243 int u_count; 244 245 mb = m_get(M_WAIT, DKMT_DATA); 246 if (mb == NULL) return ENOBUFS; 247 ds = mtod(mb, caddr_t); 248 for (u_count = 0; u_count < MLEN - 6; u_count++) { 249 *ds = *user_ds; 250 if (*ds == '\n' || *ds == '\0') break; 251 ds++; 252 user_ds++; 253 } 254 *ds = '\n'; 255 u_count++; 256 257 /* add uid in char decimal */ 258 259 ds++; 260 u_count++; 261 for (n = u.u_uid; n /= 10; ds++) u_count++; 262 for (n = u.u_uid;; ds--) { 263 *ds = n % 10 + '0'; 264 if ((n /= 10) == 0) break; 265 } 266 267 mb->m_len = u_count; 268 if (dk_xmit(chan, mb, 1, 0, (int (*)()) 0, (caddr_t) 0) == 0) { 269 return(EIO); 270 } 271 else return(0); 272 } 273 /* 274 * End action for ioctl completion 275 */ 276 /*ARGSUSED*/ 277 dkidone(tp, chan, err, p0, p1, p2) 278 register struct dkdev *tp ; 279 short chan, p0, p1, p2 ; 280 { 281 tp->d_error = err ; 282 tp->d_param[0] = p0 ; 283 tp->d_param[1] = p1 ; 284 tp->d_param[2] = p2 ; 285 tp->dc_state &= ~DKSETUP ; 286 wakeup((caddr_t)tp) ; 287 } 288 289 290 291 292 /*ARGSUSED*/ 293 dkopen(dev, flag) 294 { 295 register struct dkdev *tp; 296 register chan; 297 register struct nameidata *ndp = &u.u_nd; 298 struct inode *ip; 299 struct file *fp; 300 int m; 301 302 #ifdef lint 303 (void) dk_xint(0, 0); 304 #endif 305 dev = minor(dev); 306 if (dev == 1) { 307 return 0; /* Maintenance channel */ 308 } 309 310 chan = dev; 311 if (chan >= dk_nchan) { 312 /* debug */ log(LOG_ERR, "dkopen bad: chan>=NDKCHANS : %d\n",chan); 313 return ENXIO; 314 } 315 316 tp = &dkdev[chan]; 317 if ((tp->d_state & DKOPEN) == 0) 318 tp->dc_state = 0 ; 319 if (tp->d_state&DKXCLUDE && u.u_ruid!=0) { 320 return EBUSY; 321 } 322 323 if ((m = dk_open(chan, (int (*)()) NULL)) < 0) 324 return -m; 325 326 327 /* 328 * Channel 0 is reserved for maintenance. 329 * An open on channel 0 is interpreted as a request 330 * for an unused channel. 331 */ 332 if (chan==0) { 333 char dname[30]; 334 335 chan = m ; 336 tp = &dkdev[chan] ; 337 tp->dc_state = 0 ; 338 /* 339 * throw away inode for dk0. (/dev/dk/dial) 340 * Build standard name of new one, and ask namei for it. 341 */ 342 fp = u.u_ofile[u.u_r.r_val1]; 343 344 dksnamer(dname, chan); 345 /* log(LOG_ERR, "dname=%s chan=%d\n", dname, chan); */ 346 u.u_error = 0; 347 ndp->ni_nameiop = FOLLOW | LOOKUP; 348 ndp->ni_segflg = UIO_SYSSPACE; 349 ndp->ni_dirp = dname; 350 ip = namei(ndp); 351 352 if (ip == NULL) { 353 (void) dk_close(chan) ; 354 return ENOENT ; 355 } 356 357 /* Give back old one */ 358 ilock((struct inode *) fp->f_data); 359 iput((struct inode *) fp->f_data); 360 361 fp->f_data = (caddr_t) ip; 362 iunlock(ip); 363 } 364 if ((tp->d_state & DKOPEN) == 0) { 365 tp->d_state |= DKOPEN ; 366 tp->dc_state = 0; 367 tp->d_rmode = 0 ; 368 tp->d_xctl = 0 ; 369 tp->d_pgrp = 0; 370 } 371 tp->d_prot |= DpURP; 372 return 0; 373 } 374 375 /* Policy decision here -- standard name of dk file known to this routine */ 376 dksnamer(s, n) register char *s; 377 { 378 register char *p = "/dev/dk/dk"; 379 380 while (*s++ = *p++) 381 ; 382 s--; 383 *s++ = '0' + (n/100); n %= 100; 384 *s++ = '0' + (n/10); n %= 10; 385 *s++ = '0' + n; 386 *s = '\0'; 387 } 388 389 /* 390 * Close a channel: 391 */ 392 393 /*ARGSUSED*/ 394 dkclose(dev, flag) 395 dev_t dev; 396 int flag; 397 { 398 register struct dkdev *tp; 399 extern wakeup() ; 400 extern brelse() ; 401 short s, chan ; 402 int i, cl = 0; 403 404 chan = minor(dev); 405 tp = &dkdev[chan]; 406 if (chan == 1) { 407 return 0; /* Maintenance channel */ 408 } 409 s = spl5() ; 410 if (u.u_signal[SIGKILL] != SIG_IGN) { /* detect close from exit() */ 411 while (tp->d_bufct) { 412 tp->d_state |= DKWAIT ; 413 sleep((caddr_t)(&tp->d_state), TTOPRI) ; 414 } 415 } 416 else if (tp->d_bufct) 417 /* Hmm -- buffers queued. Let's wait 15 seconds max */ 418 for (i = 0; tp->d_bufct && i < 15; i++) { 419 tp->d_state |= DKWAIT ; 420 timeout(wakeup, (caddr_t) &tp->d_state, hz); 421 sleep((caddr_t)(&tp->d_state), TTOPRI) ; 422 } 423 splx(s) ; 424 tp->dc_state = 0; 425 tp->d_rmode = 0; 426 tp->d_prot &= ~DpURP; 427 if(!tp->d_prot){ 428 cl = dk_close(chan); 429 (void) dk_takedown(chan); 430 tp->d_state = 0; 431 } 432 return -cl; 433 } 434 435 dkread(dev, uio) 436 dev_t dev ; 437 struct uio *uio; 438 { 439 register struct dkdev *tp ; 440 int err; 441 442 M_ON(Mread) ; 443 tp = &dkdev[minor(dev)] ; 444 err = dkuread(minor(dev), uio) ; 445 tp->d_rresid = uio->uio_resid ; 446 M_OFF(Mread) ; 447 return err; 448 } 449 450 451 dkwrite(dev, uio) 452 struct uio *uio; 453 dev_t dev ; 454 { 455 int err; 456 457 M_ON(Mwrite) ; 458 err = dkuwrite(minor(dev), uio) ; 459 M_OFF(Mwrite) ; 460 return err; 461 } 462 463 #endif 464