/contrib/ntp/kernel/tty_chu_STREAMS.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 603 lines · 351 code · 84 blank · 168 comment · 42 complexity · 0f96bc6b93a77f6e4ad496b0efd25020 MD5 · raw file

  1. /*
  2. * CHU STREAMS module for SunOS
  3. *
  4. * Version 2.6
  5. *
  6. * Copyright 1991-1994, Nick Sayer
  7. *
  8. * Special thanks to Greg Onufer for his debug assists.
  9. * Special thanks to Matthias Urlichs for the 4.1.x loadable driver support
  10. * code.
  11. * Special wet-noodle whippings to Sun for not properly documenting
  12. * ANYTHING that makes this stuff at all possible.
  13. *
  14. * Should be PUSHed directly on top of a serial I/O channel.
  15. * Provides complete chucode structures to user space.
  16. *
  17. * COMPILATION:
  18. *
  19. *
  20. * To make a SunOS 4.1.x compatable loadable module (from the ntp kernel
  21. * directory):
  22. *
  23. * % cc -c -I../include -DLOADABLE tty_chu_STREAMS.c
  24. *
  25. * The resulting .o file is the loadable module. Modload it
  26. * thusly:
  27. *
  28. * % modload tty_chu_STREAMS.o -entry _chuinit
  29. *
  30. * When none of the instances are pushed in a STREAM, you can
  31. * modunload the driver in the usual manner if you wish.
  32. *
  33. * As an alternative to loading it dynamically you can compile it
  34. * directly into the kernel by hacking str_conf.c. See the README
  35. * file for more details on doing it the old fashioned way.
  36. *
  37. *
  38. * To make a Solaris 2.x compatable module (from the ntp kernel
  39. * directory):
  40. *
  41. * % {gcc,cc} -c -I../include -DSOLARIS2 tty_chu_STREAMS.c
  42. * % ld -r -o /usr/kernel/strmod/chu tty_chu_STREAMS.o
  43. * % chmod 755 /usr/kernel/strmod/chu
  44. *
  45. * The OS will load it for you automagically when it is first pushed.
  46. *
  47. * If you get syntax errors from <sys/timer.h> (really references
  48. * to types that weren't typedef'd in gcc's version of types.h),
  49. * add -D_SYS_TIMER_H to blot out the miscreants.
  50. *
  51. * Under Solaris 2.2 and previous, do not attempt to modunload the
  52. * module unless you're SURE it's not in use. I haven't tried it, but
  53. * I've been told it won't do the right thing. Under Solaris 2.3 (and
  54. * presumably future revs) an attempt to unload the module when it's in
  55. * use will properly refuse with a "busy" message.
  56. *
  57. *
  58. * HISTORY:
  59. *
  60. * v2.6 - Mutexed the per-instance chucode just to be safe.
  61. * v2.5 - Fixed show-stopper bug in Solaris 2.x - qprocson().
  62. * v2.4 - Added dynamic allocation support for Solaris 2.x.
  63. * v2.3 - Added support for Solaris 2.x.
  64. * v2.2 - Added SERVICE IMMEDIATE hack.
  65. * v2.1 - Added 'sixth byte' heuristics.
  66. * v2.0 - first version with an actual version number.
  67. * Added support for new CHU 'second 31' data format.
  68. * Deleted PEDANTIC and ANAL_RETENTIVE.
  69. *
  70. */
  71. #ifdef SOLARIS2
  72. # ifndef NCHU
  73. # define NCHU 1
  74. # endif
  75. # define _KERNEL
  76. #elif defined(LOADABLE)
  77. # ifndef NCHU
  78. # define NCHU 3
  79. # define KERNEL
  80. # endif
  81. #else
  82. # include "chu.h"
  83. #endif
  84. #if NCHU > 0
  85. /*
  86. * Number of microseconds we allow between
  87. * character arrivals. The speed is 300 baud
  88. * so this should be somewhat more than 30 msec
  89. */
  90. #define CHUMAXUSEC (60*1000) /* 60 msec */
  91. #include <sys/types.h>
  92. #include <sys/stream.h>
  93. #include <sys/param.h>
  94. #include <sys/time.h>
  95. #include <sys/errno.h>
  96. #include <sys/user.h>
  97. #include <syslog.h>
  98. #include <sys/tty.h>
  99. #include <sys/chudefs.h>
  100. #ifdef SOLARIS2
  101. #include <sys/ksynch.h>
  102. #include <sys/kmem.h>
  103. #include <sys/cmn_err.h>
  104. #include <sys/conf.h>
  105. #include <sys/strtty.h>
  106. #include <sys/modctl.h>
  107. #include <sys/ddi.h>
  108. #include <sys/sunddi.h>
  109. #endif
  110. #ifdef LOADABLE
  111. #include <sys/kernel.h>
  112. #include <sys/conf.h>
  113. #include <sys/buf.h>
  114. #include <sundev/mbvar.h>
  115. #include <sun/autoconf.h>
  116. #include <sun/vddrv.h>
  117. #endif
  118. static struct module_info rminfo = { 0, "chu", 0, INFPSZ, 0, 0 };
  119. static struct module_info wminfo = { 0, "chu", 0, INFPSZ, 0, 0 };
  120. static int chuopen(), churput(), chuwput(), chuclose();
  121. static struct qinit rinit = { churput, NULL, chuopen, chuclose, NULL,
  122. &rminfo, NULL };
  123. static struct qinit winit = { chuwput, NULL, NULL, NULL, NULL,
  124. &wminfo, NULL };
  125. struct streamtab chuinfo = { &rinit, &winit, NULL, NULL };
  126. /*
  127. * Here's our private data type and structs
  128. */
  129. struct priv_data
  130. {
  131. #ifdef SOLARIS2
  132. kmutex_t chucode_mutex;
  133. #else
  134. char in_use;
  135. #endif
  136. struct chucode chu_struct;
  137. };
  138. #ifndef SOLARIS2
  139. struct priv_data our_priv_data[NCHU];
  140. #endif
  141. #ifdef SOLARIS2
  142. static struct fmodsw fsw =
  143. {
  144. "chu",
  145. &chuinfo,
  146. D_NEW | D_MP
  147. };
  148. extern struct mod_ops mod_strmodops;
  149. static struct modlstrmod modlstrmod =
  150. {
  151. &mod_strmodops,
  152. "CHU timecode decoder v2.6",
  153. &fsw
  154. };
  155. static struct modlinkage modlinkage =
  156. {
  157. MODREV_1,
  158. (void*) &modlstrmod,
  159. NULL
  160. };
  161. int _init()
  162. {
  163. return mod_install(&modlinkage);
  164. }
  165. int _info(foo)
  166. struct modinfo *foo;
  167. {
  168. return mod_info(&modlinkage,foo);
  169. }
  170. int _fini()
  171. {
  172. return mod_remove(&modlinkage);
  173. }
  174. #endif /* SOLARIS2 */
  175. #ifdef LOADABLE
  176. # ifdef sun
  177. static struct vdldrv vd =
  178. {
  179. VDMAGIC_PSEUDO,
  180. "chu",
  181. NULL, NULL, NULL, 0, 0, NULL, NULL, 0, 0,
  182. };
  183. static struct fmodsw *chu_fmod;
  184. /*ARGSUSED*/
  185. chuinit (fc, vdp, vdi, vds)
  186. unsigned int fc;
  187. struct vddrv *vdp;
  188. addr_t vdi;
  189. struct vdstat *vds;
  190. {
  191. switch (fc) {
  192. case VDLOAD:
  193. {
  194. int dev, i;
  195. /* Find free entry in fmodsw */
  196. for (dev = 0; dev < fmodcnt; dev++) {
  197. if (fmodsw[dev].f_str == NULL)
  198. break;
  199. }
  200. if (dev == fmodcnt)
  201. return (ENODEV);
  202. chu_fmod = &fmodsw[dev];
  203. /* If you think a kernel would have strcpy() you're mistaken. */
  204. for (i = 0; i <= FMNAMESZ; i++)
  205. chu_fmod->f_name[i] = wminfo.mi_idname[i];
  206. chu_fmod->f_str = &chuinfo;
  207. }
  208. vdp->vdd_vdtab = (struct vdlinkage *) & vd;
  209. {
  210. int i;
  211. for (i=0; i<NCHU; i++)
  212. our_priv_data[i].in_use=0;
  213. }
  214. return 0;
  215. case VDUNLOAD:
  216. {
  217. int dev;
  218. for (dev = 0; dev < NCHU; dev++)
  219. if (our_priv_data[dev].in_use) {
  220. /* One of the modules is still open */
  221. return (EBUSY);
  222. }
  223. }
  224. chu_fmod->f_name[0] = '\0';
  225. chu_fmod->f_str = NULL;
  226. return 0;
  227. case VDSTAT:
  228. return 0;
  229. default:
  230. return EIO;
  231. }
  232. }
  233. # endif /* sun */
  234. #endif /* LOADABLE */
  235. #if !defined(LOADABLE) && !defined(SOLARIS2)
  236. char chu_first_open=1;
  237. #endif
  238. /*ARGSUSED*/
  239. static int chuopen(q, dev, flag, sflag)
  240. queue_t *q;
  241. dev_t dev;
  242. int flag;
  243. int sflag;
  244. {
  245. int i;
  246. #if !defined(LOADABLE) && !defined(SOLARIS2)
  247. if (chu_first_open)
  248. {
  249. chu_first_open=0;
  250. for(i=0;i<NCHU;i++)
  251. our_priv_data[i].in_use=0;
  252. }
  253. #endif
  254. #ifdef SOLARIS2
  255. /* According to the docs, calling with KM_SLEEP can never
  256. fail */
  257. q->q_ptr = kmem_alloc( sizeof(struct priv_data), KM_SLEEP );
  258. ((struct priv_data *) q->q_ptr)->chu_struct.ncodechars = 0;
  259. mutex_init(&((struct priv_data *) q->q_ptr)->chucode_mutex,"Chucode Mutex",MUTEX_DRIVER,NULL);
  260. qprocson(q);
  261. if (!putnextctl1(WR(q), M_CTL, MC_SERVICEIMM))
  262. {
  263. qprocsoff(q);
  264. mutex_destroy(&((struct priv_data *)q->q_ptr)->chucode_mutex);
  265. kmem_free(q->q_ptr, sizeof(struct chucode) );
  266. return (EFAULT);
  267. }
  268. return 0;
  269. #else
  270. for(i=0;i<NCHU;i++)
  271. if (!our_priv_data[i].in_use)
  272. {
  273. ((struct priv_data *) (q->q_ptr))=&(our_priv_data[i]);
  274. our_priv_data[i].in_use++;
  275. our_priv_data[i].chu_struct.ncodechars = 0;
  276. if (!putctl1(WR(q)->q_next, M_CTL, MC_SERVICEIMM))
  277. {
  278. our_priv_data[i].in_use=0;
  279. u.u_error = EFAULT;
  280. return (OPENFAIL);
  281. }
  282. return 0;
  283. }
  284. u.u_error = EBUSY;
  285. return (OPENFAIL);
  286. #endif
  287. }
  288. /*ARGSUSED*/
  289. static int chuclose(q, flag)
  290. queue_t *q;
  291. int flag;
  292. {
  293. #ifdef SOLARIS2
  294. qprocsoff(q);
  295. mutex_destroy(&((struct priv_data *)q->q_ptr)->chucode_mutex);
  296. kmem_free(q->q_ptr, sizeof(struct chucode) );
  297. #else
  298. ((struct priv_data *) (q->q_ptr))->in_use=0;
  299. #endif
  300. return (0);
  301. }
  302. /*
  303. * Now the crux of the biscuit.
  304. *
  305. * We will be passed data from the man downstairs. If it's not a data
  306. * packet, it must be important, so pass it along unmunged. If, however,
  307. * it is a data packet, we're gonna do special stuff to it. We're going
  308. * to pass each character we get to the old line discipline code we
  309. * include below for just such an occasion. When the old ldisc code
  310. * gets a full chucode struct, we'll hand it back upstairs.
  311. *
  312. * chuinput takes a single character and q (as quickly as possible).
  313. * passback takes a pointer to a chucode struct and q and sends it upstream.
  314. */
  315. void chuinput();
  316. void passback();
  317. static int churput(q, mp)
  318. queue_t *q;
  319. mblk_t *mp;
  320. {
  321. mblk_t *bp;
  322. switch(mp->b_datap->db_type)
  323. {
  324. case M_DATA:
  325. for(bp=mp; bp!=NULL; bp=bp->b_cont)
  326. {
  327. while(bp->b_rptr < bp->b_wptr)
  328. chuinput( ((u_char)*(bp->b_rptr++)) , q );
  329. }
  330. freemsg(mp);
  331. break;
  332. default:
  333. putnext(q,mp);
  334. break;
  335. }
  336. }
  337. /*
  338. * Writing to a chu device doesn't make sense, but we'll pass them
  339. * through in case they're important.
  340. */
  341. static int chuwput(q, mp)
  342. queue_t *q;
  343. mblk_t *mp;
  344. {
  345. putnext(q,mp);
  346. }
  347. /*
  348. * Take a pointer to a filled chucode struct and a queue and
  349. * send the chucode stuff upstream
  350. */
  351. void passback(outdata,q)
  352. struct chucode *outdata;
  353. queue_t *q;
  354. {
  355. mblk_t *mp;
  356. int j;
  357. mp=(mblk_t*) allocb(sizeof(struct chucode),BPRI_LO);
  358. if (mp==NULL)
  359. {
  360. #ifdef SOLARIS2
  361. cmn_err(CE_WARN,"chu module couldn't allocate message block");
  362. #else
  363. log(LOG_ERR,"chu: cannot allocate message");
  364. #endif
  365. return;
  366. }
  367. for(j=0;j<sizeof(struct chucode); j++)
  368. *mp->b_wptr++ = *( ((char*)outdata) + j );
  369. putnext(q,mp);
  370. }
  371. /*
  372. * This routine was copied nearly verbatim from the old line discipline.
  373. */
  374. void chuinput(c,q)
  375. register u_char c;
  376. queue_t *q;
  377. {
  378. register struct chucode *chuc;
  379. register int i;
  380. long sec, usec;
  381. struct timeval tv;
  382. /*
  383. * Quick, Batman, get a timestamp! We need to do this
  384. * right away. The time between the end of the stop bit
  385. * and this point is critical, and should be as nearly
  386. * constant and as short as possible. (Un)fortunately,
  387. * the Sun's clock granularity is so big this isn't a
  388. * major problem.
  389. *
  390. * uniqtime() is totally undocumented, but there you are.
  391. */
  392. uniqtime(&tv);
  393. #ifdef SOLARIS2
  394. mutex_enter(&((struct priv_data *)q->q_ptr)->chucode_mutex);
  395. #endif
  396. /*
  397. * Now, locate the chu struct once so we don't have to do it
  398. * over and over.
  399. */
  400. chuc=&(((struct priv_data *) (q->q_ptr))->chu_struct);
  401. /*
  402. * Compute the difference in this character's time stamp
  403. * and the last. If it exceeds the margin, blow away all
  404. * the characters currently in the buffer.
  405. */
  406. i = (int)chuc->ncodechars;
  407. if (i > 0)
  408. {
  409. sec = tv.tv_sec - chuc->codetimes[i-1].tv_sec;
  410. usec = tv.tv_usec - chuc->codetimes[i-1].tv_usec;
  411. if (usec < 0)
  412. {
  413. sec -= 1;
  414. usec += 1000000;
  415. }
  416. if (sec != 0 || usec > CHUMAXUSEC)
  417. {
  418. i = 0;
  419. chuc->ncodechars = 0;
  420. }
  421. }
  422. /*
  423. * Store the character.
  424. */
  425. chuc->codechars[i] = (u_char)c;
  426. chuc->codetimes[i] = tv;
  427. /*
  428. * Now we perform the 'sixth byte' heuristics.
  429. *
  430. * This is a long story.
  431. *
  432. * We used to be able to count on the first byte of the code
  433. * having a '6' in the LSD. This prevented most code framing
  434. * errors (garbage before the first byte wouldn't typically
  435. * have a 6 in the LSD). That's no longer the case.
  436. *
  437. * We can get around this, however, by noting that the 6th byte
  438. * must be either equal to or one's complement of the first.
  439. * If we get a sixth byte that ISN'T like that, then it may
  440. * well be that the first byte is garbage. The right thing
  441. * to do is to left-shift the whole buffer one count and
  442. * continue to wait for the sixth byte.
  443. */
  444. if (i == NCHUCHARS/2)
  445. {
  446. register u_char temp_byte;
  447. temp_byte=chuc->codechars[i] ^ chuc->codechars[0];
  448. if ( (temp_byte) && (temp_byte!=0xff) )
  449. {
  450. register int t;
  451. /*
  452. * No match. Left-shift the buffer and try again
  453. */
  454. for(t=0;t<=NCHUCHARS/2;t++)
  455. {
  456. chuc->codechars[t]=chuc->codechars[t+1];
  457. chuc->codetimes[t]=chuc->codetimes[t+1];
  458. }
  459. i--; /* This is because of the ++i immediately following */
  460. }
  461. }
  462. /*
  463. * We done yet?
  464. */
  465. if (++i < NCHUCHARS)
  466. {
  467. /*
  468. * We're not done. Not much to do here. Save the count and wait
  469. * for another character.
  470. */
  471. chuc->ncodechars = (u_char)i;
  472. }
  473. else
  474. {
  475. /*
  476. * We are done. Mark this buffer full and pass it along.
  477. */
  478. chuc->ncodechars = NCHUCHARS;
  479. /*
  480. * Now we have a choice. Either the front half and back half
  481. * have to match, or be one's complement of each other.
  482. *
  483. * So let's try the first byte and see
  484. */
  485. if(chuc->codechars[0] == chuc->codechars[NCHUCHARS/2])
  486. {
  487. chuc->chutype = CHU_TIME;
  488. for( i=0; i<(NCHUCHARS/2); i++)
  489. if (chuc->codechars[i] != chuc->codechars[i+(NCHUCHARS/2)])
  490. {
  491. chuc->ncodechars = 0;
  492. #ifdef SOLARIS2
  493. mutex_exit(&((struct priv_data *)q->q_ptr)->chucode_mutex);
  494. #endif
  495. return;
  496. }
  497. }
  498. else
  499. {
  500. chuc->chutype = CHU_YEAR;
  501. for( i=0; i<(NCHUCHARS/2); i++)
  502. if (((chuc->codechars[i] ^ chuc->codechars[i+(NCHUCHARS/2)]) & 0xff)
  503. != 0xff )
  504. {
  505. chuc->ncodechars = 0;
  506. #ifdef SOLARIS2
  507. mutex_exit(&((struct priv_data *)q->q_ptr)->chucode_mutex);
  508. #endif
  509. return;
  510. }
  511. }
  512. passback(chuc,q); /* We're done! */
  513. chuc->ncodechars = 0; /* Start all over again! */
  514. }
  515. #ifdef SOLARIS2
  516. mutex_exit(&((struct priv_data *)q->q_ptr)->chucode_mutex);
  517. #endif
  518. }
  519. #endif /* NCHU > 0 */