1/*
2 * Copyright (c) 2000-2007 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License").  You may not use this file except in compliance with the
9 * License.  Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22// 45678901234567890123456789012345678901234567890123456789012345678901234567890
23/*
24 * IOSerialBSDClient.cpp
25 *
26 * 2007-07-12	dreece	fixed full-buffer hang
27 * 2002-04-19	dreece	moved device node removal from free() to didTerminate()
28 * 2001-11-30	gvdl	open/close pre-emptible arbitration for termios
29 *			IOSerialStreams.
30 * 2001-09-02	gvdl	Fixed hot unplug code now terminate cleanly.
31 * 2001-07-20	gvdl	Add new ioctl for DATA_LATENCY control.
32 * 2001-05-11	dgl	Update iossparam function to recognize MIDI clock mode.
33 * 2000-10-21	gvdl	Initial real change to IOKit serial family.
34 *
35 */
36#include <sys/types.h>
37
38__BEGIN_DECLS
39
40#include <kern/thread.h>
41#include <sys/time.h>
42
43__END_DECLS
44
45#include <sys/proc.h>
46#include <sys/errno.h>
47#include <sys/dkstat.h>
48#include <sys/fcntl.h>
49#include <sys/conf.h>
50#include <sys/tty.h>
51#include <sys/ucred.h>
52#include <sys/kernel.h>
53#include <miscfs/devfs/devfs.h>
54#include <sys/systm.h>
55#include <sys/kauth.h>
56#include <libkern/OSAtomic.h>
57#include <pexpert/pexpert.h>
58
59#include <IOKit/assert.h>
60#include <IOKit/system.h>
61#include <TargetConditionals.h>
62
63#include <IOKit/IOBSD.h>
64#include <IOKit/IOLib.h>
65
66#include "IORS232SerialStreamSync.h"
67
68#include "ioss.h"
69#include "IOSerialKeys.h"
70
71#include "IOSerialBSDClient.h"
72
73#define super IOService
74
75OSDefineMetaClassAndStructors(IOSerialBSDClient, IOService)
76
77/*
78 * Debugging assertions for tty locks
79 */
80#define TTY_DEBUG 1
81#if TTY_DEBUG
82#define	TTY_LOCK_OWNED(tp) do {lck_mtx_assert(&tp->t_lock, LCK_MTX_ASSERT_OWNED); } while (0)
83#define	TTY_LOCK_NOTOWNED(tp) do {lck_mtx_assert(&tp->t_lock, LCK_MTX_ASSERT_NOTOWNED); } while (0)
84#else
85#define TTY_LOCK_OWNED(tp)
86#define TTY_LOCK_NOTOWNED(tp)
87#endif
88
89/*
90 * enable/disable kprint debugging
91 */
92#ifndef JLOG
93#define JLOG 0
94#endif
95
96
97/* Macros to clear/set/test flags. */
98#define	SET(t, f)	(t) |= (f)
99#define	CLR(t, f)	(t) &= ~(f)
100#define	ISSET(t, f)	((t) & (f))
101#define SAFE_RELEASE(x) do { if (x) x->release(); x = 0; } while(0)
102
103/*
104 * Options and tunable parameters
105 *
106 * must match what is in IOSerialBSDClient.h
107 */
108#define	TTY_DIALIN_INDEX	0
109#define	TTY_CALLOUT_INDEX	1
110#define TTY_NUM_FLAGS		1
111#define TTY_NUM_TYPES		(1 << TTY_NUM_FLAGS)
112
113#define TTY_HIGH_HEADROOM	4	/* size error code + 1 */
114#define TTY_HIGHWATER		(TTYHOG - TTY_HIGH_HEADROOM)
115#define TTY_LOWWATER		((TTY_HIGHWATER * 7) / 8)
116
117#define	IS_TTY_OUTWARD(dev)	( minor(dev) &  TTY_CALLOUT_INDEX)
118#define TTY_UNIT(dev)		( minor(dev) >> TTY_NUM_FLAGS)
119
120#define TTY_QUEUESIZE(tp)	(tp->t_rawq.c_cc + tp->t_canq.c_cc)
121#define IS_TTY_PREEMPT(dev, cflag)	\
122    ( !IS_TTY_OUTWARD((dev)) && !ISSET((cflag), CLOCAL) )
123
124#define TTY_DEVFS_PREFIX	"/dev/"
125#define TTY_CALLOUT_PREFIX	TTY_DEVFS_PREFIX "cu."
126#define TTY_DIALIN_PREFIX	TTY_DEVFS_PREFIX "tty."
127
128/*
129 * All times are in Micro Seconds
130 *
131 * replacing hz from kern_clock with constant 100 (i.e. hz from kern_clock)
132 *
133 * doing it with a #define so it will be easier to remember what to fix
134 *
135 * TODO: stop using tsleep
136 */
137#define LOCAL_HZ 100
138
139#define MUSEC2TICK(x) \
140            ((int) (((long long) (x) * LOCAL_HZ + 500000) / 1000000))
141#define MUSEC2TIMEVALDECL(x)	{ (x) / 1000000, ((x) % 1000000) }
142
143#define	MAX_INPUT_LATENCY   40000	/* 40 ms */
144#define	MIN_INPUT_LATENCY   10000	/* 10 ms */
145
146#define	DTR_DOWN_DELAY	  2000000	/* DTR down time  2 seconds */
147#define PREEMPT_IDLE	  DTR_DOWN_DELAY /* Same as close delay */
148#define DCD_DELAY 	    10000 	/* Ignore DCD change of < 10ms */
149#define BRK_DELAY 	   250000 	/* Minimum break  .25 sec */
150
151#define	RS232_S_ON		(PD_RS232_S_RTS | PD_RS232_S_DTR)
152#define	RS232_S_OFF		(0)
153
154#define	RS232_S_INPUTS		(PD_RS232_S_CAR | PD_RS232_S_CTS)
155#define	RS232_S_OUTPUTS		(PD_RS232_S_DTR | PD_RS232_S_RTS)
156
157/* Default line state */
158#define	ISPEED	B9600
159#define	IFLAGS	(EVENP|ODDP|ECHO|CRMOD)
160
161# define IOSERIAL_DEBUG_INIT        (1<<0)
162# define IOSERIAL_DEBUG_SETUP       (1<<1)
163# define IOSERIAL_DEBUG_MISC        (1<<2)
164# define IOSERIAL_DEBUG_CONTROL     (1<<3)  // flow control, stop bits, etc.
165# define IOSERIAL_DEBUG_FLOW        (1<<4)
166# define IOSERIAL_DEBUG_WATCHSTATE  (1<<5)
167# define IOSERIAL_DEBUG_RETURNS     (1<<6)
168# define IOSERIAL_DEBUG_BLOCK     (1<<7)
169# define IOSERIAL_DEBUG_SLEEP     (1<<8)
170# define IOSERIAL_DEBUG_DCDTRD    (1<<9)
171# define IOSERIAL_DEBUG_MULTI	  (1<<10)
172
173# define IOSERIAL_DEBUG_ERROR       (1<<15)
174# define IOSERIAL_DEBUG_ALWAYS      (1<<16)
175
176#ifdef DEBUG
177
178#define IOSERIAL_DEBUG (IOSERIAL_DEBUG_ERROR | IOSERIAL_DEBUG_MULTI )
179
180#else
181// production debug output should be minimal
182# define IOSERIAL_DEBUG (IOSERIAL_DEBUG_ERROR)
183#endif
184
185
186
187#ifdef IOSERIAL_DEBUG
188# define REQUIRE(_expr)                                         \
189        do {                                                    \
190                if (!(_expr))                                   \
191                        panic("%s:%s:%u: REQUIRE failed: %s",   \
192                              __FILE__,                         \
193                              __PRETTY_FUNCTION__,              \
194                              __LINE__, #_expr);                \
195        } while(0);
196
197# define debug(fac, fmt, args...)                                                       \
198do {                                                                                    \
199        if (IOSERIAL_DEBUG_##fac & (IOSERIAL_DEBUG | IOSERIAL_DEBUG_ALWAYS))                     \
200                kprintf("IOSerialFamily::%s: " fmt "\n", __FUNCTION__ , ##args);    \
201} while(0)
202#else
203# define REQUIRE(_expr)                         \
204        do {                                    \
205                if (_expr) {                    \
206                }                               \
207        } while(0);
208
209# define debug(fac, fmt, args...)       do { } while(0)
210#endif
211
212// External OSSymbol Cache, they have to be somewhere.
213const OSSymbol *gIOSerialBSDServiceValue = 0;
214const OSSymbol *gIOSerialBSDTypeKey = 0;
215const OSSymbol *gIOSerialBSDAllTypes = 0;
216const OSSymbol *gIOSerialBSDModemType = 0;
217const OSSymbol *gIOSerialBSDRS232Type = 0;
218const OSSymbol *gIOTTYDeviceKey = 0;
219const OSSymbol *gIOTTYBaseNameKey = 0;
220const OSSymbol *gIOTTYSuffixKey = 0;
221const OSSymbol *gIOCalloutDeviceKey = 0;
222const OSSymbol *gIODialinDeviceKey = 0;
223const OSSymbol *gIOTTYWaitForIdleKey = 0;
224
225class IOSerialBSDClientGlobals {
226private:
227
228    unsigned int fMajor;
229    unsigned int fLastMinor;
230    IOSerialBSDClient **fClients;
231    OSDictionary *fNames;
232	IOLock * fFunnelLock;
233
234public:
235    IOSerialBSDClientGlobals();
236    ~IOSerialBSDClientGlobals();
237
238    inline bool isValid();
239    inline IOSerialBSDClient *getClient(dev_t dev);
240
241    dev_t assign_dev_t();
242    bool registerTTY(dev_t dev, IOSerialBSDClient *tty);
243    const OSSymbol *getUniqueTTYSuffix
244        (const OSSymbol *inName, const OSSymbol *suffix, dev_t dev);
245    void releaseUniqueTTYSuffix(const OSSymbol *inName, const OSSymbol *suffix);
246	void takefFunnelLock();
247	void releasefFunnelLock();
248};
249
250// Create an instance of the IOSerialBSDClientGlobals
251// This runs the static constructor and destructor so that
252// I can grab and release a lock as appropriate.
253static IOSerialBSDClientGlobals sBSDGlobals;
254
255struct cdevsw IOSerialBSDClient::devsw =
256{
257    /* d_open     */ IOSerialBSDClient::iossopen,
258    /* d_close    */ IOSerialBSDClient::iossclose,
259    /* d_read     */ IOSerialBSDClient::iossread,
260    /* d_write    */ IOSerialBSDClient::iosswrite,
261    /* d_ioctl    */ IOSerialBSDClient::iossioctl,
262    /* d_stop     */ IOSerialBSDClient::iossstop,
263    /* d_reset    */ (reset_fcn_t *) &nulldev,
264    /* d_ttys     */ NULL,
265    /* d_select   */ IOSerialBSDClient::iossselect,
266    /* d_mmap     */ eno_mmap,
267    /* d_strategy */ eno_strat,
268    /* d_getc     */ eno_getc,
269    /* d_putc     */ eno_putc,
270    /* d_type     */ D_TTY
271};
272
273static const struct timeval kDTRDownDelay = MUSEC2TIMEVALDECL(DTR_DOWN_DELAY);
274static const struct timeval kPreemptIdle  = MUSEC2TIMEVALDECL(PREEMPT_IDLE);
275static const struct timeval kNever        = { 0, 0 };
276
277/*
278 * Idea for the line discipline routines came from FreeBSD 2004,
279 * see src/sys/sys/linedisc.h
280 */
281static inline int bsdld_open(dev_t dev, struct tty *tp)
282    { return (*linesw[tp->t_line].l_open)(dev, tp); }
283
284static inline int bsdld_close(struct tty *tp, int flag)
285    { return (*linesw[tp->t_line].l_close)(tp, flag); }
286
287static inline int bsdld_read(struct tty *tp, struct uio *uio, int flag)
288    { return (*linesw[tp->t_line].l_read)(tp, uio, flag); }
289
290static inline int bsdld_write(struct tty *tp, struct uio *uio, int flag)
291    { return (*linesw[tp->t_line].l_write)(tp, uio, flag); }
292
293static inline int
294bsdld_ioctl(struct tty *tp, u_long cmd, caddr_t data, int flag,
295	    struct proc *p)
296    { return (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); }
297
298static inline int bsdld_rint(int c, struct tty *tp)
299    { return (*linesw[tp->t_line].l_rint)(c, tp); }
300
301static inline void  bsdld_start(struct tty *tp)
302    { (*linesw[tp->t_line].l_start)(tp); }
303
304static inline int bsdld_modem(struct tty *tp, int flag)
305    { return (*linesw[tp->t_line].l_modem)(tp, flag); }
306
307/*
308 * Map from Unix baud rate defines to <PortDevices> baud rate.  NB all
309 * reference to bits used in a PortDevice are always 1 bit fixed point.
310 * The extra bit is used to indicate 1/2 bits.
311 */
312#define IOSS_HALFBIT_BRD	1
313#define IOSS_BRD(x)	((int) ((x) * 2.0))
314
315static struct speedtab iossspeeds[] = {
316    {       0,	               0    },
317    {      50,	IOSS_BRD(     50.0) },
318    {      75,	IOSS_BRD(     75.0) },
319    {     110,	IOSS_BRD(    110.0) },
320    {     134,	IOSS_BRD(    134.5) },	/* really 134.5 baud */
321    {     150,	IOSS_BRD(    150.0) },
322    {     200,	IOSS_BRD(    200.0) },
323    {     300,	IOSS_BRD(    300.0) },
324    {     600,	IOSS_BRD(    600.0) },
325    {    1200,	IOSS_BRD(   1200.0) },
326    {    1800,	IOSS_BRD(   1800.0) },
327    {    2400,	IOSS_BRD(   2400.0) },
328    {    4800,	IOSS_BRD(   4800.0) },
329    {    7200,	IOSS_BRD(   7200.0) },
330    {    9600,	IOSS_BRD(   9600.0) },
331    {   14400,	IOSS_BRD(  14400.0) },
332    {   19200,	IOSS_BRD(  19200.0) },
333    {   28800,	IOSS_BRD(  28800.0) },
334    {   38400,	IOSS_BRD(  38400.0) },
335    {   57600,	IOSS_BRD(  57600.0) },
336    {   76800,	IOSS_BRD(  76800.0) },
337    {  115200,	IOSS_BRD( 115200.0) },
338    {  230400,	IOSS_BRD( 230400.0) },
339    {  460800,	IOSS_BRD( 460800.0) },
340    {  921600,	IOSS_BRD( 921600.0) },
341    { 1843200,	IOSS_BRD(1843200.0) },
342    {   19001,	IOSS_BRD(  19200.0) },	// Add some convenience mappings
343    {   38000,	IOSS_BRD(  38400.0) },
344    {   57000,	IOSS_BRD(  57600.0) },
345    {  115000,	IOSS_BRD( 115200.0) },
346    {  230000,	IOSS_BRD( 230400.0) },
347    {  460000,	IOSS_BRD( 460800.0) },
348    {  920000,	IOSS_BRD( 921600.0) },
349    {  921000,	IOSS_BRD( 921600.0) },
350    { 1840000,	IOSS_BRD(1843200.0) },
351    {     -1,	              -1    }
352};
353
354
355static inline UInt64 getDebugFlagsTable(OSDictionary *props)
356{
357    OSNumber *debugProp;
358    UInt64    debugFlags = gIOKitDebug;
359
360    debugProp = OSDynamicCast(OSNumber, props->getObject(gIOKitDebugKey));
361    if (debugProp)
362	debugFlags = debugProp->unsigned64BitValue();
363
364    return debugFlags;
365}
366
367#define getDebugFlags() (getDebugFlagsTable(getPropertyTable()));
368
369#define IOLogCond(cond, args...) do { if (cond) kprintf(args); } while (0)
370
371#define SAFE_PORTRELEASE(provider) do {			\
372    if (fAcquired && provider)					\
373    	{ provider->releasePort(); fAcquired = false; }	\
374} while (0)
375
376//
377// Static global data maintainence routines
378//
379static void
380termios32to64(struct termios32 *in, struct user_termios *out)
381{
382	out->c_iflag = (user_tcflag_t)in->c_iflag;
383	out->c_oflag = (user_tcflag_t)in->c_oflag;
384	out->c_cflag = (user_tcflag_t)in->c_cflag;
385	out->c_lflag = (user_tcflag_t)in->c_lflag;
386
387	/* bcopy is OK, since this type is ILP32/LP64 size invariant */
388	bcopy(in->c_cc, out->c_cc, sizeof(in->c_cc));
389
390	out->c_ispeed = (user_speed_t)in->c_ispeed;
391	out->c_ospeed = (user_speed_t)in->c_ospeed;
392}
393
394static void
395termios64to32(struct user_termios *in, struct termios32 *out)
396{
397	out->c_iflag = (tcflag_t)in->c_iflag;
398	out->c_oflag = (tcflag_t)in->c_oflag;
399	out->c_cflag = (tcflag_t)in->c_cflag;
400	out->c_lflag = (tcflag_t)in->c_lflag;
401
402	/* bcopy is OK, since this type is ILP32/LP64 size invariant */
403	bcopy(in->c_cc, out->c_cc, sizeof(in->c_cc));
404
405	out->c_ispeed = (speed_t)in->c_ispeed;
406	out->c_ospeed = (speed_t)in->c_ospeed;
407}
408
409bool IOSerialBSDClientGlobals::isValid()
410{
411    return (fFunnelLock && fClients && fNames && fMajor != (unsigned int) -1);
412}
413
414#define OSSYM(str) OSSymbol::withCStringNoCopy(str)
415IOSerialBSDClientGlobals::IOSerialBSDClientGlobals()
416{
417#if JLOG
418	debug(MULTI,"init");
419#endif
420    gIOSerialBSDServiceValue = OSSYM(kIOSerialBSDServiceValue);
421    gIOSerialBSDTypeKey      = OSSYM(kIOSerialBSDTypeKey);
422    gIOSerialBSDAllTypes     = OSSYM(kIOSerialBSDAllTypes);
423    gIOSerialBSDModemType    = OSSYM(kIOSerialBSDModemType);
424    gIOSerialBSDRS232Type    = OSSYM(kIOSerialBSDRS232Type);
425    gIOTTYDeviceKey          = OSSYM(kIOTTYDeviceKey);
426    gIOTTYBaseNameKey        = OSSYM(kIOTTYBaseNameKey);
427    gIOTTYSuffixKey          = OSSYM(kIOTTYSuffixKey);
428    gIOCalloutDeviceKey      = OSSYM(kIOCalloutDeviceKey);
429    gIODialinDeviceKey       = OSSYM(kIODialinDeviceKey);
430    gIOTTYWaitForIdleKey     = OSSYM(kIOTTYWaitForIdleKey);
431
432    fMajor = (unsigned int) -1;
433    fNames = OSDictionary::withCapacity(4);
434    fLastMinor = 4;
435    fClients = (IOSerialBSDClient **)
436                        IOMalloc(fLastMinor * sizeof(fClients[0]));
437    if (fClients && fNames) {
438        bzero(fClients, fLastMinor * sizeof(fClients[0]));
439        fMajor = cdevsw_add(-1, &IOSerialBSDClient::devsw);
440        cdevsw_setkqueueok(fMajor, &IOSerialBSDClient::devsw, 0);
441    }
442	fFunnelLock = IOLockAlloc();
443    if (!isValid())
444        IOLog("IOSerialBSDClient didn't initialize");
445}
446#undef OSSYM
447
448IOSerialBSDClientGlobals::~IOSerialBSDClientGlobals()
449{
450#if JLOG
451	kprintf("IOSerialBSDClientGlobals::~IOSerialBSDClientGlobals\n");
452#endif
453    SAFE_RELEASE(gIOSerialBSDServiceValue);
454    SAFE_RELEASE(gIOSerialBSDTypeKey);
455    SAFE_RELEASE(gIOSerialBSDAllTypes);
456    SAFE_RELEASE(gIOSerialBSDModemType);
457    SAFE_RELEASE(gIOSerialBSDRS232Type);
458    SAFE_RELEASE(gIOTTYDeviceKey);
459    SAFE_RELEASE(gIOTTYBaseNameKey);
460    SAFE_RELEASE(gIOTTYSuffixKey);
461    SAFE_RELEASE(gIOCalloutDeviceKey);
462    SAFE_RELEASE(gIODialinDeviceKey);
463    SAFE_RELEASE(gIOTTYWaitForIdleKey);
464    SAFE_RELEASE(fNames);
465    if (fMajor != (unsigned int) -1)
466        cdevsw_remove(fMajor, &IOSerialBSDClient::devsw);
467    if (fClients)
468        IOFree(fClients, fLastMinor * sizeof(fClients[0]));
469	if (fFunnelLock) {
470		IOLockFree(fFunnelLock);
471	}
472}
473
474void IOSerialBSDClientGlobals::takefFunnelLock() {
475	IOLockLock(fFunnelLock);
476}
477void IOSerialBSDClientGlobals::releasefFunnelLock() {
478	IOLockUnlock(fFunnelLock);
479}
480dev_t IOSerialBSDClientGlobals::assign_dev_t()
481{
482    unsigned int i;
483    debug(MULTI,"begin");
484	for (i = 0; i < fLastMinor && fClients[i]; i++)
485        ;
486
487    if (i == fLastMinor)
488    {
489        unsigned int newLastMinor = fLastMinor + 4;
490        IOSerialBSDClient **newClients;
491
492        newClients = (IOSerialBSDClient **)
493                    IOMalloc(newLastMinor * sizeof(fClients[0]));
494        if (!newClients) {
495            debug(MULTI,"end not normal");
496			return (dev_t) -1;
497		}
498        bzero(&newClients[fLastMinor], 4 * sizeof(fClients[0]));
499        bcopy(fClients, newClients, fLastMinor * sizeof(fClients[0]));
500        IOFree(fClients, fLastMinor * sizeof(fClients[0]));
501        fLastMinor = newLastMinor;
502        fClients = newClients;
503    }
504
505    dev_t dev = makedev(fMajor, i << TTY_NUM_FLAGS);
506    fClients[i] = (IOSerialBSDClient *) -1;
507    debug(MULTI,"end normal");
508    return dev;
509}
510
511bool IOSerialBSDClientGlobals::
512registerTTY(dev_t dev, IOSerialBSDClient *client)
513{
514    debug(MULTI,"begin");
515    bool ret = false;
516    unsigned int i = TTY_UNIT(dev);
517
518    assert(i < fLastMinor);
519    if (i < fLastMinor) {
520        assert(!client || fClients[i] != (IOSerialBSDClient *) -1);
521        if (client && fClients[i] == (IOSerialBSDClient *) -1) {
522            fClients[i] = client;
523            ret = true;
524        }
525    }
526	debug(MULTI,"end");
527    return ret;
528}
529
530// Assumes the caller has grabbed the funnel if necessary.
531// Any call from UNIX is funnelled, I need to funnel any IOKit upcalls
532// explicitly.
533IOSerialBSDClient *IOSerialBSDClientGlobals::getClient(dev_t dev)
534{
535    //debug(MULTI,"begin");
536    unsigned int i = TTY_UNIT(dev);
537    assert(i < LastMinor);
538    if (i < fLastMinor) {
539        return fClients[TTY_UNIT(dev)];
540    }
541    return NULL;
542}
543
544const OSSymbol *IOSerialBSDClientGlobals::
545getUniqueTTYSuffix(const OSSymbol *inName, const OSSymbol *suffix, dev_t dev)
546{
547    OSSet *suffixSet = 0;
548    debug(MULTI,"begin");
549    do {
550        // Do we have this name already registered?
551        suffixSet = (OSSet *) fNames->getObject(inName);
552        if (!suffixSet) {
553            suffixSet = OSSet::withCapacity(4);
554            if (!suffixSet) {
555                suffix = 0;
556                break;
557            }
558
559            suffixSet->setObject((OSObject *) suffix);
560            if (!fNames->setObject(inName, suffixSet))
561                suffix = 0;
562
563            suffixSet->release();
564            break;
565        }
566
567        // Have we seen this suffix before?
568        if (!suffixSet->containsObject((OSObject *) suffix)) {
569            // Nope so add it to the list of suffixes we HAVE seen.
570            if (!suffixSet->setObject((OSObject *) suffix))
571                suffix = 0;
572            break;
573        }
574
575        // We have seen it before so we have to generate a new suffix
576        // I'm going to use the unit as an unique index for this run
577        // of the OS.
578        char ind[8]; // 23 bits, 7 decimal digits + '\0'
579        snprintf(ind, sizeof (ind), "%d", TTY_UNIT(dev));
580
581        suffix = OSSymbol::withCString(ind);
582        if (!suffix)
583            break;
584
585        // What about this suffix then?
586        if (suffixSet->containsObject((OSObject *) suffix) // Been there before?
587        || !suffixSet->setObject((OSObject *) suffix)) {
588            suffix->release();	// Now what?
589            suffix = 0;
590        }
591        if (suffix)
592            suffix->release();	// Release the creation reference
593    } while(false);
594	debug(MULTI,"end");
595    return suffix;
596}
597
598void IOSerialBSDClientGlobals::
599releaseUniqueTTYSuffix(const OSSymbol *inName, const OSSymbol *suffix)
600{
601    OSSet *suffixSet;
602    debug(MULTI,"begin");
603    suffixSet = (OSSet *) fNames->getObject(inName);
604    if (suffixSet)
605        suffixSet->removeObject((OSObject *) suffix);
606
607	debug(MULTI,"end");
608}
609
610bool IOSerialBSDClient::
611createDevNodes()
612{
613    bool ret = false;
614    OSData *tmpData;
615    OSString *deviceKey = 0, *calloutName = 0, *dialinName = 0;
616    void *calloutNode = 0, *dialinNode = 0;
617    const OSSymbol *nubName, *suffix;
618    debug(MULTI,"begin");
619
620    // Convert the provider's base name to an OSSymbol if necessary
621    nubName = (const OSSymbol *) fProvider->getProperty(gIOTTYBaseNameKey);
622    if (!nubName || !OSDynamicCast(OSSymbol, (OSObject *) nubName)) {
623        if (nubName)
624            nubName = OSSymbol::withString((OSString *) nubName);
625        else
626            nubName = OSSymbol::withCString("");
627        if (!nubName) {
628			debug(MULTI,"no Nub for basename");
629            return false;
630		}
631        ret = fProvider->setProperty(gIOTTYBaseNameKey, (OSObject *) nubName);
632        nubName->release();
633        if (!ret) {
634			debug(MULTI,"no Nub for basename SET");
635            return false;
636		}
637    }
638
639    // Convert the provider's suffix to an OSSymbol if necessary
640    suffix = (const OSSymbol *) fProvider->getProperty(gIOTTYSuffixKey);
641    if (!suffix || !OSDynamicCast(OSSymbol, (OSObject *) suffix)) {
642        if (suffix)
643            suffix = OSSymbol::withString((OSString *) suffix);
644        else
645            suffix = OSSymbol::withCString("");
646        if (!suffix) {
647			debug(MULTI,"no suffix");
648            return false;
649		}
650        ret = fProvider->setProperty(gIOTTYSuffixKey, (OSObject *) suffix);
651        suffix->release();
652        if (!ret) {
653			debug(MULTI,"no suffix SET");
654            return false;
655		}
656    }
657
658    suffix = sBSDGlobals.getUniqueTTYSuffix(nubName, suffix, fBaseDev);
659    if (!suffix) {
660		debug(MULTI,"no UniqueTTYSuffix");
661        return false;
662	}
663
664    setProperty(gIOTTYSuffixKey,   (OSObject *) suffix);
665    fProvider->setProperty(gIOTTYSuffixKey,   (OSObject *) suffix);
666    setProperty(gIOTTYBaseNameKey, (OSObject *) nubName);
667
668    do {
669        int nameLen = nubName->getLength();
670        int suffLen = suffix->getLength();
671        int devLen  = nameLen + suffLen + 1;
672
673        // Create the device key symbol
674        tmpData = OSData::withCapacity(devLen);
675        if (tmpData) {
676            tmpData->appendBytes(nubName->getCStringNoCopy(), nameLen);
677            tmpData->appendBytes(suffix->getCStringNoCopy(), suffLen + 1);
678            deviceKey = OSString::
679                withCString((char *) tmpData->getBytesNoCopy());
680            tmpData->release();
681        }
682        if (!tmpData || !deviceKey)
683            break;
684
685        // Create the calloutName symbol
686        tmpData = OSData::withCapacity(devLen + (uint32_t)sizeof(TTY_CALLOUT_PREFIX));
687        if (tmpData) {
688            tmpData->appendBytes(TTY_CALLOUT_PREFIX,
689                                 (uint32_t)sizeof(TTY_CALLOUT_PREFIX)-1);
690            tmpData->appendBytes(deviceKey->getCStringNoCopy(), devLen);
691            calloutName = OSString::
692                withCString((char *) tmpData->getBytesNoCopy());
693            tmpData->release();
694        }
695        if (!tmpData || !calloutName)
696            break;
697
698        // Create the dialinName symbol
699        tmpData = OSData::withCapacity(devLen + (uint32_t)sizeof(TTY_DIALIN_PREFIX));
700        if (tmpData) {
701            tmpData->appendBytes(TTY_DIALIN_PREFIX,
702                                 (uint32_t)sizeof(TTY_DIALIN_PREFIX)-1);
703            tmpData->appendBytes(deviceKey->getCStringNoCopy(), devLen);
704            dialinName = OSString::
705                withCString((char *) tmpData->getBytesNoCopy());
706            tmpData->release();
707        }
708        if (!tmpData || !dialinName)
709            break;
710
711        // Create the device nodes
712        calloutNode = devfs_make_node(fBaseDev | TTY_CALLOUT_INDEX,
713            DEVFS_CHAR, UID_ROOT, GID_WHEEL, 0666,
714            (char *) calloutName->getCStringNoCopy() + (uint32_t)sizeof(TTY_DEVFS_PREFIX) - 1);
715        dialinNode = devfs_make_node(fBaseDev | TTY_DIALIN_INDEX,
716            DEVFS_CHAR, UID_ROOT, GID_WHEEL, 0666,
717            (char *) dialinName->getCStringNoCopy() + (uint32_t)sizeof(TTY_DEVFS_PREFIX) - 1);
718        if (!calloutNode || !dialinNode)
719            break;
720
721        // Always reset the name of our provider
722        if (!setProperty(gIOTTYDeviceKey,     (OSObject *) deviceKey)
723        ||  !setProperty(gIOCalloutDeviceKey, (OSObject *) calloutName)
724        ||  !setProperty(gIODialinDeviceKey,  (OSObject *) dialinName))
725            break;
726
727
728        fSessions[TTY_DIALIN_INDEX].fCDevNode  = dialinNode;  dialinNode = 0;
729        fSessions[TTY_CALLOUT_INDEX].fCDevNode = calloutNode; calloutNode = 0;
730        ret = true;
731
732    } while(false);
733
734    SAFE_RELEASE(deviceKey);
735    SAFE_RELEASE(calloutName);
736    SAFE_RELEASE(dialinName);
737    if (dialinNode)
738        devfs_remove(dialinNode);
739    if (calloutNode)
740        devfs_remove(calloutNode);
741	debug(MULTI,"finish");
742    return ret;
743}
744
745bool IOSerialBSDClient::
746setBaseTypeForDev()
747{
748    const OSMetaClass *metaclass;
749    const OSSymbol *name;
750    static const char *streamTypeNames[] = {
751        "IOSerialStream", "IORS232SerialStream", "IOModemSerialStream", 0
752    };
753    debug(MULTI,"begin");
754
755
756    // Walk through the provider super class chain looking for an
757    // interface but stop at IOService 'cause that aint a IOSerialStream.
758    for (metaclass = fProvider->getMetaClass();
759         metaclass && metaclass != IOService::metaClass;
760         metaclass = metaclass->getSuperClass())
761    {
762        for (int i = 0; streamTypeNames[i]; i++) {
763            const char *trial = streamTypeNames[i];
764
765            // Check if class is prefixed by this name
766            // Prefix 'cause IO...Stream & IO...StreamSync
767            // should both match and if I just check for the prefix they will
768            if (!strncmp(metaclass->getClassName(), trial, strlen(trial))) {
769                bool ret = false;
770
771                name = OSSymbol::withCStringNoCopy(trial);
772                if (name) {
773                    ret = setProperty(gIOSerialBSDTypeKey, (OSObject *) name);
774                    name->release();
775                }
776				debug(MULTI,"finish normal");
777                return ret;
778            }
779        }
780    }
781	debug(MULTI,"finish error");
782    return false;
783}
784
785bool IOSerialBSDClient::
786start(IOService *provider)
787{
788    debug(MULTI,"begin");
789
790	fBaseDev = -1;
791    if (!super::start(provider))
792        return false;
793
794    if (!sBSDGlobals.isValid())
795        return false;
796
797	sBSDGlobals.takefFunnelLock();
798
799    fProvider = OSDynamicCast(IOSerialStreamSync, provider);
800    if (!fProvider)
801        return false;
802
803    fThreadLock = IOLockAlloc();
804    if (!fThreadLock)
805        return false;
806
807	fOpenCloseLock = IOLockAlloc();
808	if (!fOpenCloseLock)
809		return false;
810
811	fIoctlLock = IOLockAlloc();
812	if (!fIoctlLock)
813		return false;
814
815	fisBlueTooth = false;
816	fPreemptInProgress = false;
817	fDCDThreadCall = 0;
818
819
820    /*
821     * First initialise the dial in device.
822     * We don't use all the flags from <sys/ttydefaults.h> since they are
823     * only relevant for logins.
824	 *
825	 * initialize the hotplug flag to zero (bsd hasn't attached so we are safe to unplug)
826     */
827    fSessions[TTY_DIALIN_INDEX].fThis = this;
828    fSessions[TTY_DIALIN_INDEX].fInitTerm.c_iflag = 0;
829    fSessions[TTY_DIALIN_INDEX].fInitTerm.c_oflag = 0;
830    fSessions[TTY_DIALIN_INDEX].fInitTerm.c_cflag = TTYDEF_CFLAG;
831    fSessions[TTY_DIALIN_INDEX].fInitTerm.c_lflag = 0;
832    fSessions[TTY_DIALIN_INDEX].fInitTerm.c_ispeed
833	= fSessions[TTY_DIALIN_INDEX].fInitTerm.c_ospeed
834	= (gPESerialBaud == -1)? TTYDEF_SPEED : gPESerialBaud;
835    termioschars(&fSessions[TTY_DIALIN_INDEX].fInitTerm);
836
837    // Now initialise the call out device
838	//
839	// initialize the hotplug flag to zero (bsd hasn't attached so we are safe to unplug)
840
841    fSessions[TTY_CALLOUT_INDEX].fThis = this;
842    fSessions[TTY_CALLOUT_INDEX].fInitTerm
843        = fSessions[TTY_DIALIN_INDEX].fInitTerm;
844
845    do {
846
847		fBaseDev = sBSDGlobals.assign_dev_t();
848        if ((dev_t) -1 == fBaseDev) {
849            break;
850		}
851        if (!createDevNodes()) {
852           break;
853		}
854        if (!setBaseTypeForDev()) {
855           break;
856		}
857        if (!sBSDGlobals.registerTTY(fBaseDev, this)) {
858            break;
859		}
860        // Let userland know that this serial port exists
861        registerService();
862		debug(MULTI," finished");
863		sBSDGlobals.releasefFunnelLock();
864        return true;
865    } while (0);
866    // Failure path
867    debug(MULTI," Cleanup Resources");
868    sBSDGlobals.releasefFunnelLock();
869	cleanupResources();
870    return false;
871}
872
873static inline const char *devName(IORegistryEntry *self)
874{
875    OSString *devNameStr = ((OSString *) self->getProperty(gIOTTYDeviceKey));
876    assert(devNameStr);
877
878    return devNameStr->getCStringNoCopy();
879}
880
881bool IOSerialBSDClient::
882matchPropertyTable(OSDictionary *table)
883{
884    bool matched;
885    OSString *desiredType;
886    OSObject *desiredTypeObj;
887    const OSMetaClass *providerClass;
888    unsigned int desiredLen;
889    const char *desiredName;
890    bool logMatch = (0 != (kIOLogMatch & getDebugFlagsTable(table)));
891
892    if (!super::matchPropertyTable(table)) {
893        IOLogCond(logMatch, "TTY.%s: Failed superclass match\n",
894                             devName(this));
895        return false;	// One of the name based matches has failed, thats it.
896    }
897
898    // Do some name matching
899    matched = compareProperty(table, gIOTTYDeviceKey)
900           && compareProperty(table, gIOTTYBaseNameKey)
901           && compareProperty(table, gIOTTYSuffixKey)
902           && compareProperty(table, gIOCalloutDeviceKey)
903           && compareProperty(table, gIODialinDeviceKey);
904    if (!matched) {
905        IOLogCond(logMatch, "TTY.%s: Failed non type based match\n",
906                             devName(this));
907        return false;	// One of the name based matches has failed, thats it.
908    }
909
910    // The name matching is valid, so if we don't have a type based match
911    // then we have no further matching to do and should return true.
912    desiredTypeObj = table->getObject(gIOSerialBSDTypeKey);
913    if (!desiredTypeObj)
914	return true;
915
916    // At this point we have to check for type based matching.
917    desiredType = OSDynamicCast(OSString, desiredTypeObj);
918    if (!desiredType) {
919        IOLogCond(logMatch, "TTY.%s: %s isn't an OSString?\n",
920                             devName(this),
921                             kIOSerialBSDTypeKey);
922        return false;
923    }
924    desiredLen = desiredType->getLength();
925    desiredName = desiredType->getCStringNoCopy();
926	debug(FLOW, "desiredName is: %s", desiredName);
927
928    // Walk through the provider super class chain looking for an
929    // interface but stop at IOService 'cause that aint a IOSerialStream.
930    for (providerClass = fProvider->getMetaClass();
931
932         providerClass && providerClass != IOService::metaClass;
933         providerClass = providerClass->getSuperClass())
934    {
935        // Check if provider class is prefixed by desiredName
936        // Prefix 'cause IOModemSerialStream & IOModemSerialStreamSync
937        // should both match and if I just look for the prefix they will
938        if (!strncmp(providerClass->getClassName(), desiredName, desiredLen)) {
939			if (fProvider->metaCast("IOBluetoothSerialClientModemStreamSync") || fProvider->metaCast("IOBluetoothSerialClientSerialStreamSync")) {
940				debug(FLOW,"ah hah, bluetooth");
941				fisBlueTooth = true;
942			}
943			return true;
944		}
945    }
946
947
948    // Couldn't find the desired name in the super class chain
949    // so report the failure and return false
950    IOLogCond(logMatch, "TTY.%s: doesn't have a %s interface\n",
951            devName(this),
952            desiredName);
953    return false;
954}
955
956void IOSerialBSDClient::free()
957{
958
959#if JLOG
960		kprintf("IOSerialBSDClient::free\n");
961#endif
962	sBSDGlobals.takefFunnelLock();
963	if ((dev_t) -1 != fBaseDev) {
964	    sBSDGlobals.registerTTY(fBaseDev, 0);
965    }
966
967	Session *sp = &fSessions[TTY_DIALIN_INDEX];
968	if (sp->ftty) {
969		ttyfree(sp->ftty);
970		sp->ftty = NULL;
971		debug(FLOW,"we free'd the ftty struct");
972	}
973
974    if (fThreadLock)
975	IOLockFree(fThreadLock);
976
977	if (fOpenCloseLock)
978		IOLockFree(fOpenCloseLock);
979
980	if (fIoctlLock)
981		IOLockFree(fIoctlLock);
982
983	if (fDCDThreadCall) {
984		debug(DCDTRD, "DCDThread is freed in free");
985		thread_call_cancel(fDCDThreadCall);
986		thread_call_free(fDCDThreadCall);
987		fDCDThreadCall = 0;
988		fDCDTimerDue = false;
989	}
990	sBSDGlobals.releasefFunnelLock();
991    super::free();
992}
993
994bool IOSerialBSDClient::
995requestTerminate(IOService *provider, IOOptionBits options)
996{
997#if JLOG
998	kprintf("IOSerialBSDClient::requestTerminate\n");
999#endif
1000    do {
1001		// Don't have anything to do, just a teardown synchronisation
1002		// for the isInactive() call.  We can't be made inactive in a
1003		// funneled call anymore
1004
1005		// ah, but we're not under the funnel anymore...
1006		// so we'll call out to the termination routine so we can still
1007		// synchronize...
1008
1009		if (super::requestTerminate(provider, options))
1010			return (true);
1011
1012		} while(1);
1013	// can't get here
1014	return(true);
1015}
1016
1017bool IOSerialBSDClient::
1018didTerminate(IOService *provider, IOOptionBits options, bool *defer)
1019{
1020    bool deferTerm;
1021    {
1022#if JLOG
1023		kprintf("IOSerialBSDClient::didTerminate\n");
1024#endif
1025		cleanupResources();
1026
1027        for (int i = 0; i < TTY_NUM_TYPES; i++) {
1028            Session *sp = &fSessions[i];
1029            struct tty *tp = sp->ftty;
1030
1031            // Now kill any stream that may currently be running
1032            sp->fErrno = ENXIO;
1033
1034			if (tp == NULL) // we found a session with no tty configured
1035				continue;
1036#if JLOG
1037			kprintf("IOSerialBSDClient::didTerminate::we still have a session around...\n");
1038#endif
1039            // Enforce a zombie and unconnected state on the discipline
1040			tty_lock(tp);
1041			CLR(tp->t_cflag, CLOCAL);		// Fake up a carrier drop
1042			(void) bsdld_modem(tp, false);
1043			tty_unlock(tp);
1044        }
1045	fActiveSession = 0;
1046	deferTerm = (frxThread || ftxThread || fInOpensPending);
1047	if (deferTerm) {
1048	    fKillThreads = true;
1049	    fProvider->executeEvent(PD_E_ACTIVE, false);
1050	    fDeferTerminate = true;
1051	    *defer = true;	// Defer until the threads die
1052	}
1053	else
1054	    SAFE_PORTRELEASE(fProvider);
1055
1056    }
1057
1058    return deferTerm || super::didTerminate(provider, options, defer);
1059}
1060
1061IOReturn IOSerialBSDClient::
1062setOneProperty(const OSSymbol *key, OSObject * /* value */)
1063{
1064#if JLOG
1065	kprintf("IOSerialBSDClient::setOneProperty\n");
1066#endif
1067    if (key == gIOTTYWaitForIdleKey) {
1068        int error = waitForIdle();
1069        if (ENXIO == error)
1070            return kIOReturnOffline;
1071        else if (error)
1072            return kIOReturnAborted;
1073        else
1074            return kIOReturnSuccess;
1075    }
1076
1077    return kIOReturnUnsupported;
1078}
1079
1080IOReturn IOSerialBSDClient::
1081setProperties(OSObject *properties)
1082{
1083
1084    IOReturn res = kIOReturnBadArgument;
1085#if JLOG
1086	kprintf("IOSerialBSDClient::setProperties\n");
1087#endif
1088    if (OSDynamicCast(OSString, properties)) {
1089        const OSSymbol *propSym =
1090            OSSymbol::withString((OSString *) properties);
1091        res = setOneProperty(propSym, 0);
1092        propSym->release();
1093    }
1094    else if (OSDynamicCast(OSDictionary, properties)) {
1095        const OSDictionary *dict = (const OSDictionary *) properties;
1096        OSCollectionIterator *keysIter;
1097        const OSSymbol *key;
1098
1099        keysIter = OSCollectionIterator::withCollection(dict);
1100        if (!keysIter) {
1101            res = kIOReturnNoMemory;
1102            goto bail;
1103        }
1104
1105        while ( (key = (const OSSymbol *) keysIter->getNextObject()) ) {
1106            res = setOneProperty(key, dict->getObject(key));
1107            if (res)
1108                break;
1109        }
1110
1111        keysIter->release();
1112    }
1113
1114bail:
1115    return res;		// Successful just return now
1116}
1117
1118// Bracket all open attempts with a reference on ourselves.
1119int IOSerialBSDClient::
1120iossopen(dev_t dev, int flags, int devtype, struct proc *p)
1121{
1122#if JLOG
1123	kprintf("IOSerialBSDClient::iossopen\n");
1124#endif
1125	sBSDGlobals.takefFunnelLock();
1126    IOSerialBSDClient *me = sBSDGlobals.getClient(dev);
1127	sBSDGlobals.releasefFunnelLock();
1128    if (!me || me->isInactive())
1129        return ENXIO;
1130
1131    me->retain();
1132
1133	// protect the open from the close
1134	IOLockLock(me->fOpenCloseLock);
1135
1136    int ret = me->open(dev, flags, devtype, p);
1137
1138	IOLockUnlock(me->fOpenCloseLock);
1139    me->release();
1140
1141    return ret;
1142}
1143
1144int IOSerialBSDClient::
1145iossclose(dev_t dev, int flags, int devtype, struct proc *p)
1146{
1147#if JLOG
1148	kprintf("IOSerialBSDClient::iossclose enter\n");
1149#endif
1150	sBSDGlobals.takefFunnelLock();
1151    IOSerialBSDClient *me = sBSDGlobals.getClient(dev);
1152	sBSDGlobals.releasefFunnelLock();
1153    if (!me)
1154        return ENXIO;
1155
1156    Session *sp = &me->fSessions[IS_TTY_OUTWARD(dev)];
1157    struct tty *tp = sp->ftty;
1158
1159	// protect the close from the open
1160	IOLockLock(me->fOpenCloseLock);
1161
1162    if (!ISSET(tp->t_state, TS_ISOPEN)) {
1163		IOLockUnlock(me->fOpenCloseLock);
1164	    return EBADF;
1165	}
1166
1167    me->close(dev, flags, devtype, p);
1168	IOLockUnlock(me->fOpenCloseLock);
1169	// Remember this is the last close so we may have to delete ourselves
1170	// This reference was held just before we opened the line discipline
1171    // in open().
1172    me->release();
1173#if JLOG
1174	kprintf("IOSerialBSDClient::iossclose exit\n");
1175#endif
1176    return 0;
1177}
1178
1179int IOSerialBSDClient::
1180iossread(dev_t dev, struct uio *uio, int ioflag)
1181{
1182#if JLOG
1183	kprintf("IOSerialBSDClient::iossread\n");
1184#endif
1185	sBSDGlobals.takefFunnelLock();
1186    IOSerialBSDClient *me = sBSDGlobals.getClient(dev);
1187	sBSDGlobals.releasefFunnelLock();
1188    int error;
1189
1190    assert(me);
1191
1192    Session *sp = &me->fSessions[IS_TTY_OUTWARD(dev)];
1193    struct tty *tp = sp->ftty;
1194
1195
1196    error = sp->fErrno;
1197    if (!error) {
1198		tty_lock(tp);
1199		error = bsdld_read(tp, uio, ioflag);
1200		tty_unlock(tp);
1201
1202        if (me->frxBlocked && TTY_QUEUESIZE(tp) < TTY_LOWWATER) {
1203#if JLOG
1204			kprintf("IOSerialBSDClient::iossread::TTY_QUEUESIZE(tp) < TTY_LOWWATER\n");
1205#endif
1206            me->sessionSetState(sp, PD_S_RX_EVENT, PD_S_RX_EVENT);
1207		}
1208    }
1209
1210
1211    return error;
1212}
1213
1214int IOSerialBSDClient::
1215iosswrite(dev_t dev, struct uio *uio, int ioflag)
1216{
1217	sBSDGlobals.takefFunnelLock();
1218    IOSerialBSDClient *me = sBSDGlobals.getClient(dev);
1219	sBSDGlobals.releasefFunnelLock();
1220    int error;
1221
1222#if JLOG
1223	kprintf("IOSerialBSDClient::iosswrite\n");
1224#endif
1225    assert(me);
1226
1227    Session *sp = &me->fSessions[IS_TTY_OUTWARD(dev)];
1228    struct tty *tp = sp->ftty;
1229
1230    error = sp->fErrno;
1231
1232    if (!error) {
1233		tty_lock(tp);
1234        error = bsdld_write(tp, uio, ioflag);
1235		tty_unlock(tp);
1236	}
1237
1238    return error;
1239}
1240
1241int IOSerialBSDClient::
1242iossselect(dev_t dev, int which, void *wql, struct proc *p)
1243{
1244	sBSDGlobals.takefFunnelLock();
1245    IOSerialBSDClient *me = sBSDGlobals.getClient(dev);
1246	sBSDGlobals.releasefFunnelLock();
1247    int error;
1248
1249#if JLOG
1250	kprintf("IOSerialBSDClient::iossselect\n");
1251#endif
1252
1253    assert(me);
1254
1255    Session *sp = &me->fSessions[IS_TTY_OUTWARD(dev)];
1256    struct tty *tp = sp->ftty;
1257
1258    error = sp->fErrno;
1259    if (!error) {
1260		tty_lock(tp);
1261        error = ttyselect(tp, which, wql, p);
1262		tty_unlock(tp);
1263	}
1264    return error;
1265}
1266
1267static inline int
1268tiotors232(int bits)
1269{
1270    UInt32 out_b = bits;
1271#if JLOG
1272	kprintf("IOSerialBSDClient::tiotors232\n");
1273#endif
1274    out_b &= ( PD_RS232_S_DTR | PD_RS232_S_RFR | PD_RS232_S_CTS
1275	     | PD_RS232_S_CAR | PD_RS232_S_BRK );
1276    return out_b;
1277}
1278
1279static inline int
1280rs232totio(int bits)
1281{
1282    UInt32 out_b = bits;
1283#if JLOG
1284	kprintf("IOSerialBSDClient::rs232totio\n");
1285#endif
1286
1287    out_b &= ( PD_RS232_S_DTR | PD_RS232_S_DSR
1288             | PD_RS232_S_RFR | PD_RS232_S_CTS
1289             | PD_RS232_S_BRK | PD_RS232_S_CAR  | PD_RS232_S_RNG);
1290    return out_b;
1291}
1292
1293int IOSerialBSDClient::
1294iossioctl(dev_t dev, u_long cmd, caddr_t data, int fflag,				// XXX64
1295                         struct proc *p)
1296{
1297	sBSDGlobals.takefFunnelLock();
1298    IOSerialBSDClient *me = sBSDGlobals.getClient(dev);
1299	sBSDGlobals.releasefFunnelLock();
1300    int error = 0;
1301
1302    debug(FLOW, "begin");
1303    IOLockLock(me->fIoctlLock);
1304    assert(me);
1305
1306    Session *sp = &me->fSessions[IS_TTY_OUTWARD(dev)];
1307    struct tty *tp = sp->ftty;
1308
1309    if (sp->fErrno) {
1310		debug(FLOW,"immediate error sp->fErrno: %d", sp->fErrno);
1311        error = sp->fErrno;
1312        goto exitIoctl;
1313    }
1314
1315    /*
1316     * tty line disciplines return >= 0 if they could process this
1317     * ioctl request.  If so, simply return, we're done
1318     */
1319    error = bsdld_ioctl(tp, cmd, data, fflag, p);
1320    if (ENOTTY != error) {
1321		debug(FLOW,"got ENOTTY from BSD land");
1322        me->optimiseInput(&tp->t_termios);
1323        goto exitIoctl;
1324    }
1325
1326    // ...->l_ioctl may block so we need to check our state again
1327    if (sp->fErrno) {
1328		debug(FLOW,"recheck sp->fErrno: %d", sp->fErrno);
1329        error = sp->fErrno;
1330        goto exitIoctl;
1331    }
1332
1333	debug(CONTROL, "cmd: 0x%lx", cmd);
1334
1335    /* First pre-process and validate ioctl command */
1336    switch(cmd)
1337    {
1338    case TIOCGETA_32:
1339    {
1340        debug(CONTROL,"TIOCGETA_32");
1341#ifdef __LP64__
1342        termios64to32((struct user_termios *)&tp->t_termios, (struct termios32 *)data);
1343#else
1344        bcopy(&tp->t_termios, data, sizeof(struct termios));
1345#endif
1346        me->convertFlowCtrl(sp, (struct termios *) data);
1347        error = 0;
1348        goto exitIoctl;
1349    }
1350    case TIOCGETA_64:
1351    {
1352        debug(CONTROL,"TIOCGETA_64");
1353#ifdef __LP64__
1354		bcopy(&tp->t_termios, data, sizeof(struct termios));
1355#else
1356		termios32to64((struct termios32 *)&tp->t_termios, (struct user_termios *)data);
1357#endif
1358        me->convertFlowCtrl(sp, (struct termios *) data);
1359        error = 0;
1360        goto exitIoctl;
1361    }
1362    case TIOCSETA_32:
1363    case TIOCSETAW_32:
1364    case TIOCSETAF_32:
1365    case TIOCSETA_64:
1366    case TIOCSETAW_64:
1367    case TIOCSETAF_64:
1368    {
1369		debug(CONTROL,"TIOCSETA_32/64/TIOCSETAW_32/64/TIOCSETAF_32/64");
1370		struct termios *dt = (struct termios *)data;
1371		struct termios lcl_termios;
1372
1373#ifdef __LP64__
1374        if (cmd==TIOCSETA_32 || cmd==TIOCSETAW_32 || cmd==TIOCSETAF_32) {
1375            termios32to64((struct termios32 *)data, (struct user_termios *)&lcl_termios);
1376            dt = &lcl_termios;
1377        }
1378#else
1379        if (cmd==TIOCSETA_64 || cmd==TIOCSETAW_64 || cmd==TIOCSETAF_64) {
1380            termios64to32((struct user_termios *)data, (struct termios32 *)&lcl_termios);
1381            dt = &lcl_termios;
1382        }
1383#endif
1384
1385        /* Convert the PortSessionSync's flow control setting to termios */
1386		tty_lock(tp);
1387        me->convertFlowCtrl(sp, &tp->t_termios);
1388		tty_unlock(tp);
1389        /*
1390         * Check to see if we are trying to disable either the start or
1391         * stop character at the same time as using the XON/XOFF character
1392         * based flow control system.  This is not implemented in the
1393         * current PortDevices protocol.
1394         */
1395        if (ISSET(dt->c_cflag, CIGNORE)
1396        &&  ISSET(tp->t_iflag, (IXON|IXOFF))
1397        && ( dt->c_cc[VSTART] == _POSIX_VDISABLE
1398                || dt->c_cc[VSTOP]  == _POSIX_VDISABLE ) )
1399        {
1400            error = EINVAL;
1401            goto exitIoctl;
1402        }
1403        break;
1404    }
1405
1406    case TIOCEXCL:
1407		debug(CONTROL,"TIOCEXCL");
1408        // Force the TIOCEXCL ioctl to be atomic!
1409        if (ISSET(tp->t_state, TS_XCLUDE)) {
1410            error = EBUSY;
1411            goto exitIoctl;
1412        }
1413        break;
1414
1415    default:
1416        break;
1417    }
1418
1419    /* See if generic tty understands this. */
1420    if ( (error = ttioctl(tp, cmd, data, fflag, p)) != ENOTTY) {
1421		debug(CONTROL,"generic tty handled this");
1422        if (error) {
1423            iossparam(tp, &tp->t_termios);	/* reestablish old state */
1424		}
1425        me->optimiseInput(&tp->t_termios);
1426	goto exitIoctl;
1427    }
1428
1429    // ttioctl may block so we need to check our state again
1430    if (sp->fErrno) {
1431		debug(FLOW,"2nd recheck sp->fErrno: %d", sp->fErrno);
1432        error = sp->fErrno;
1433        goto exitIoctl;
1434    }
1435
1436    //
1437    // The generic ioctl handlers don't know what is going on
1438    // so try to interpret them here.
1439    //
1440    error = 0;
1441    switch (cmd)
1442    {
1443    case TIOCSBRK:
1444		debug(CONTROL,"TIOCSBRK");
1445        (void) me->mctl(PD_RS232_S_BRK, DMBIS);  break;
1446
1447	case TIOCCBRK:
1448		debug(CONTROL,"TIOCCBRK");
1449        (void) me->mctl(PD_RS232_S_BRK, DMBIC);  break;
1450
1451    case TIOCSDTR:
1452		debug(CONTROL,"TIOCSDTR");
1453        (void) me->mctl(PD_RS232_S_DTR, DMBIS);  break;
1454
1455    case TIOCCDTR:
1456		debug(CONTROL,"TIOCCDTR");
1457        (void) me->mctl(PD_RS232_S_DTR, DMBIC);  break;
1458
1459    case TIOCMSET:
1460		debug(CONTROL,"TIOCMSET");
1461        (void) me->mctl(tiotors232(*(int *)data), DMSET);  break;
1462
1463    case TIOCMBIS:
1464		debug(CONTROL,"TIOCMBIS");
1465        (void) me->mctl(tiotors232(*(int *)data), DMBIS);  break;
1466
1467    case TIOCMBIC:
1468		debug(CONTROL,"TIOCMBIC");
1469        (void) me->mctl(tiotors232(*(int *)data), DMBIC);  break;
1470
1471    case TIOCMGET:
1472		debug(CONTROL,"TIOCMGET");
1473        *(int *)data = rs232totio(me->mctl(0,     DMGET)); break;
1474
1475    case IOSSDATALAT_32:
1476    case IOSSDATALAT_64:
1477        // all users currently assume this data is a UInt32
1478		debug(CONTROL,"IOSSDATALAT");
1479        (void) me->sessionExecuteEvent(sp, PD_E_DATA_LATENCY, *(UInt32 *) data);
1480        break;
1481
1482    case IOSSPREEMPT:
1483		debug(CONTROL,"IOSSPREEMPT");
1484        me->fPreemptAllowed = (bool) (*(int *) data);
1485        if (me->fPreemptAllowed) {
1486            me->fLastUsedTime = kNever;
1487            // initialize fPreemptInProgress in case we manage to
1488            // call the Preemption ioctl before it is initialized elsewhere
1489            //me->fPreemptInProgress = false;
1490        }
1491        else
1492            wakeup(&me->fPreemptAllowed);	// Wakeup any pre-empters
1493        break;
1494
1495    case IOSSIOSPEED_32:
1496    case IOSSIOSPEED_64:
1497    {
1498		debug(CONTROL,"IOSSIOSPEED_32/64");
1499		speed_t speed = *(speed_t *) data;
1500
1501		// Remember that the speed is in half bits
1502		IOReturn rtn = me->sessionExecuteEvent(sp, PD_E_DATA_RATE, speed << 1);
1503		debug(CONTROL, "IOSSIOSPEED_32 session execute return: 0x%x", rtn);
1504		if (kIOReturnSuccess != rtn) {
1505			error = (kIOReturnBadArgument == rtn)? EINVAL : EDEVERR;
1506			break;
1507		}
1508		tty_lock(tp);
1509		tp->t_ispeed = tp->t_ospeed = speed;
1510		ttsetwater(tp);
1511		tty_unlock(tp);
1512		break;
1513    }
1514
1515    default: debug(CONTROL,"Unhandled ioctl"); error = ENOTTY; break;
1516    }
1517
1518exitIoctl:
1519    /*
1520     * These flags functionality has been totally subsumed by the PortDevice
1521     * driver so make sure they always get cleared down before any serious
1522     * work is done.
1523     */
1524	debug(FLOW, "exiting");
1525	tty_lock(tp);
1526    CLR(tp->t_iflag, IXON | IXOFF | IXANY);
1527    CLR(tp->t_cflag, CRTS_IFLOW | CCTS_OFLOW);
1528	tty_unlock(tp);
1529	IOLockUnlock(me->fIoctlLock);
1530    return error;
1531}
1532
1533
1534void IOSerialBSDClient::
1535iossstart(struct tty *tp)
1536{
1537	Session *sp = (Session *)tp->t_iokit;
1538    IOSerialBSDClient *me = sp->fThis;
1539    IOReturn rtn;
1540
1541#if JLOG
1542	kprintf("IOSerialBSDClient::iossstart\n");
1543#endif
1544
1545    assert(me);
1546
1547    if (sp->fErrno)
1548	return;
1549
1550    if ( !me->fIstxEnabled && !ISSET(tp->t_state, TS_TTSTOP) ) {
1551        me->fIstxEnabled = true;
1552#if JLOG
1553		kprintf("iossstart calls sessionSetState to enable PD_S_TX_ENABLE\n");
1554#endif
1555        me->sessionSetState(sp, -1U, PD_S_TX_ENABLE);
1556    }
1557
1558    if  (tp->t_outq.c_cc) {
1559        // Notify the transmit thread of action to be performed
1560#if JLOG
1561		kprintf("iossstart calls sessionSetState to do the PD_S_TX_EVENT\n");
1562#endif
1563		rtn = me->sessionSetState(sp, PD_S_TX_EVENT, PD_S_TX_EVENT);
1564		assert(!rtn || rtn == kIOReturnOffline || rtn == kIOReturnNotOpen);
1565    }
1566}
1567
1568int IOSerialBSDClient::
1569iossstop(struct tty *tp, int rw)
1570{
1571
1572    Session *sp = (Session *) tp->t_iokit;
1573    IOSerialBSDClient *me = sp->fThis;
1574#if JLOG
1575	kprintf("IOSerialBSDClient::iossstop\n");
1576#endif
1577
1578    assert(me);
1579    if (sp->fErrno)
1580	return 0;
1581
1582    if ( ISSET(tp->t_state, TS_TTSTOP) ) {
1583		me->fIstxEnabled = false;
1584#if JLOG
1585		kprintf("iossstop calls sessionSetState to disable PD_S_TX_EVENT\n");
1586#endif
1587		me->sessionSetState(sp, 0, PD_S_TX_ENABLE);
1588    }
1589
1590    if ( ISSET(rw, FWRITE) ) {
1591#if JLOG
1592		kprintf("iossstop calls sessionExecuteEvent to PD_E_TXQ_FLUSH\n");
1593#endif
1594        me->sessionExecuteEvent(sp, PD_E_TXQ_FLUSH, 0);
1595	}
1596    if ( ISSET(rw, FREAD) ) {
1597#if JLOG
1598		kprintf("iossstop calls sessionExecuteEvent to PD_E_RXQ_FLUSH\n");
1599#endif
1600        me->sessionExecuteEvent(sp, PD_E_RXQ_FLUSH, 0);
1601        if (me->frxBlocked)	{ // wake up a blocked reader
1602#if JLOG
1603			kprintf("iossstop calls sessionSetState to wake PD_S_RX_ENABLE\n");
1604#endif
1605            me->sessionSetState(sp, PD_S_RX_ENABLE, PD_S_RX_ENABLE);
1606		}
1607    }
1608    return 0;
1609}
1610
1611/*
1612 * Parameter control functions
1613 *
1614 */
1615int IOSerialBSDClient::
1616iossparam(struct tty *tp, struct termios *t)
1617{
1618
1619    Session *sp = (Session *) tp->t_iokit;
1620    IOSerialBSDClient *me = sp->fThis;
1621    u_long data;
1622    int cflag, error;
1623    IOReturn rtn = kIOReturnOffline;
1624#if JLOG
1625	kprintf("IOSerialBSDClient::iossparam\n");
1626#endif
1627
1628    assert(me);
1629
1630    if (sp->fErrno)
1631	goto exitParam;
1632
1633    rtn = kIOReturnBadArgument;
1634    if (ISSET(t->c_iflag, (IXOFF|IXON))
1635    && (t->c_cc[VSTART]==_POSIX_VDISABLE || t->c_cc[VSTOP]==_POSIX_VDISABLE))
1636        goto exitParam;
1637
1638    /* do historical conversions */
1639    if (t->c_ispeed == 0) {
1640        t->c_ispeed = t->c_ospeed;
1641	}
1642
1643    /* First check to see if the requested speed is one of our valid ones */
1644    data = ttspeedtab(t->c_ospeed, iossspeeds);
1645
1646    if ((int) data != -1 && t->c_ispeed == t->c_ospeed) {
1647#if JLOG
1648		kprintf("IOSerialBSDClient::iossparam::sessionExecuteEvent::PD_E_DATA_RATE, %d\n", (int)data);
1649#endif
1650
1651	rtn  = me->sessionExecuteEvent(sp, PD_E_DATA_RATE, data);
1652	}
1653    else if ( (IOSS_HALFBIT_BRD & t->c_ospeed) ) {
1654	/*
1655	 * MIDI clock speed multipliers are used for externally clocked MIDI
1656	 * devices, and are evident by a 1 in the low bit of c_ospeed/c_ispeed
1657	 */
1658	data = (u_long) t->c_ospeed >> 1;	// set data to MIDI clock mode
1659#if JLOG
1660		kprintf("IOSerialBSDClient::iossparam::sessionExecuteEvent::PD_E_EXTERNAL_CLOCK_MODE, %d\n", (int)data);
1661#endif
1662
1663	rtn  = me->sessionExecuteEvent(sp, PD_E_EXTERNAL_CLOCK_MODE, data);
1664    }
1665    if (rtn)
1666        goto exitParam;
1667
1668    /*
1669     * Setup SCC as for data and character len
1670     * Note: ttycharmask is anded with both transmitted and received
1671     * characters.
1672     */
1673    cflag = t->c_cflag;
1674    switch (cflag & CSIZE) {
1675    case CS5:       data = 5 << 1; break;
1676    case CS6:	    data = 6 << 1; break;
1677    case CS7:	    data = 7 << 1; break;
1678    default:	    /* default to 8bit setup */
1679    case CS8:	    data = 8 << 1; break;
1680    }
1681#if JLOG
1682	kprintf("IOSerialBSDClient::iossparam::sessionExecuteEvent::PD_E_DATA_SIZE, %d\n", (int)data);
1683#endif
1684
1685    rtn  = me->sessionExecuteEvent(sp, PD_E_DATA_SIZE, data);
1686    if (rtn)
1687        goto exitParam;
1688
1689
1690    data = PD_RS232_PARITY_NONE;
1691    if ( ISSET(cflag, PARENB) ) {
1692        if ( ISSET(cflag, PARODD) )
1693            data = PD_RS232_PARITY_ODD;
1694        else
1695            data = PD_RS232_PARITY_EVEN;
1696    }
1697#if JLOG
1698	kprintf("IOSerialBSDClient::iossparam::sessionExecuteEvent::PD_E_DATA_INTEGRITY, %d\n", (int)data);
1699#endif
1700
1701    rtn = me->sessionExecuteEvent(sp, PD_E_DATA_INTEGRITY, data);
1702    if (rtn)
1703        goto exitParam;
1704
1705    /* Set stop bits to 2 1/2 bits in length */
1706    if (ISSET(cflag, CSTOPB))
1707        data = 4;
1708    else
1709        data = 2;
1710#if JLOG
1711	kprintf("IOSerialBSDClient::iossparam::sessionExecuteEvent::PD_RS232_E_STOP_BITS, %d\n", (int)data);
1712#endif
1713
1714    rtn = me->sessionExecuteEvent(sp, PD_RS232_E_STOP_BITS, data);
1715    if (rtn)
1716        goto exitParam;
1717
1718    //
1719    // Reset the Flow Control values
1720    //
1721    data = 0;
1722    if ( ISSET(t->c_iflag, IXON) )
1723        SET(data, PD_RS232_A_TXO);
1724    if ( ISSET(t->c_iflag, IXANY) )
1725        SET(data, PD_RS232_A_XANY);
1726    if ( ISSET(t->c_iflag, IXOFF) )
1727        SET(data, PD_RS232_A_RXO);
1728
1729    if ( ISSET(cflag, CRTS_IFLOW) )
1730        SET(data, PD_RS232_A_RFR);
1731    if ( ISSET(cflag, CCTS_OFLOW) )
1732        SET(data, PD_RS232_A_CTS);
1733    if ( ISSET(cflag, CDTR_IFLOW) )
1734        SET(data, PD_RS232_A_DTR);
1735    CLR(t->c_iflag, IXON | IXOFF | IXANY);
1736    CLR(t->c_cflag, CRTS_IFLOW | CCTS_OFLOW);
1737#if JLOG
1738	kprintf("IOSerialBSDClient::iossparam::sessionExecuteEvent::PD_E_FLOW_CONTROL, %d\n", (int)data);
1739#endif
1740
1741    rtn = me->sessionExecuteEvent(sp, PD_E_FLOW_CONTROL, data);
1742    if (rtn)
1743        goto exitParam;
1744
1745    //
1746    // Load the flow control start and stop characters.
1747    //
1748#if JLOG
1749	kprintf("IOSerialBSDClient::iossparam::sessionExecuteEvent::PD_RS232_E_XON_BYTE, t->c_cc[VSTART]\n");
1750#endif
1751    rtn  = me->sessionExecuteEvent(sp, PD_RS232_E_XON_BYTE,  t->c_cc[VSTART]);
1752#if JLOG
1753	kprintf("IOSerialBSDClient::iossparam::sessionExecuteEvent::PD_RS232_E_XOFF_BYTE, t->c_cc[VSTOP]\n");
1754#endif
1755    rtn |= me->sessionExecuteEvent(sp, PD_RS232_E_XOFF_BYTE, t->c_cc[VSTOP]);
1756    if (rtn)
1757        goto exitParam;
1758
1759    /* Always enable for transmission */
1760    me->fIstxEnabled = true;
1761#if JLOG
1762	kprintf("IOSerialBSDClient::iossparam::sessionSetState::PD_S_TX_ENABLE, PD_S_TX_ENABLE\n");
1763#endif
1764    rtn = me->sessionSetState(sp, PD_S_TX_ENABLE, PD_S_TX_ENABLE);
1765    if (rtn)
1766        goto exitParam;
1767
1768    /* Only enable reception if necessary */
1769    if ( ISSET(cflag, CREAD) ) {
1770#if JLOG
1771		kprintf("IOSerialBSDClient::iossparam::sessionSetState::-1U, PD_S_RX_ENABLE\n");
1772#endif
1773        rtn = me->sessionSetState(sp, -1U, PD_S_RX_ENABLE);
1774	}
1775    else {
1776#if JLOG
1777		kprintf("IOSerialBSDClient::iossparam::sessionSetState::0U, PD_S_RX_ENABLE\n");
1778#endif
1779        rtn = me->sessionSetState(sp,  0U, PD_S_RX_ENABLE);
1780	}
1781
1782exitParam:
1783    if (kIOReturnSuccess == rtn)
1784        error = 0;
1785    else if (kIOReturnOffline == rtn)
1786        error = sp->fErrno;
1787    else
1788        error = EINVAL;
1789
1790    return error;
1791}
1792
1793
1794/*
1795 * Decision Tables for open semantic
1796 *
1797 * The Exact semantic to be used when open serial ports is very complicated.
1798 * We have nasty combinations of ports opened exclusively but pre-emptible while
1799 * a root user tries to open the port.  Anyway all of the states that are
1800 * interesting are listed below with pseudo code that implements the tables.
1801 *
1802 * The states across the top are for desired state.  Vertical for the current
1803 * open port's state, with State prefix:- ' ' true, '!' not true, 'x' dont care
1804 *
1805 *  Results
1806 * 	B => Block   E => Error Busy   S => Success   P => Pre-empt
1807 *
1808 * OPEN port was open and is not waiting for carrier
1809 * EXCL port is open and desires exclusivity
1810 * PREM port is open and is pre-emptible
1811 *
1812 * Callout Decision table
1813 *
1814 *         CALLOUT | 0 | 0 | 1 | 1 | 1 | 1 |
1815 *        NONBLOCK | 0 | 1 | 0 | 0 | 1 | 1 |
1816 *            ROOT | x | x | 0 | 1 | 0 | 1 |
1817 * -----------------------------------------
1818 *      !EXCL      | Bi| E | S | S | S | S |
1819 *       EXCL      | Bi| E | E | S | E | S |
1820 *
1821 * Is Callout Open
1822 *     if (wantCallout) {
1823 *         if (isExclusive && !wantSuser)
1824 *             return BUSY;
1825 *         else
1826 *             ; // Success;
1827 *     }
1828 *     else {
1829 * checkAndWaitForIdle:
1830 *         if (wantNonBlock)
1831 *             return BUSY;
1832 *         else {
1833 *             waitForIdle;
1834 *             goto checkBusy;
1835 *         }
1836 *     }
1837 *
1838 * Dial out Table
1839 *
1840 *         CALLOUT | 0 | 0 | 1 | 1 | 1 | 1 |
1841 *        NONBLOCK | 0 | 1 | 0 | 0 | 1 | 1 |
1842 *            ROOT | x | x | 0 | 1 | 0 | 1 |
1843 * ----------------------------------------
1844 * !OPENxEXCLxPREM | S | S | P | P | P | P |
1845 *  OPEN!EXCL!PREM | S | S | Bi| S | E | S |
1846 *  OPEN!EXCL PREM | S | S | P | P | P | P |
1847 *  OPEN EXCL!PREM | E | E | Bi| S | E | S |
1848 *  OPEN EXCL PREM | E | E | P | P | P | P |
1849 *
1850 * Is Dialout Waiting for carrier
1851 *     if (wantCallout)
1852 *         preempt;
1853 *     else
1854 *         // Success Wait for carrier later on
1855 *
1856 * Is Dialout open
1857 *     if (wantCallout) {
1858 *         if (isPreempt)
1859 *             preempt;
1860 *         else if (!wantSuser)
1861 *             goto checkAndWaitForIdle;
1862 *         else
1863 *         	; // Success
1864 *     }
1865 *     else {
1866 *         if (isExclusive)
1867 *             return BUSY;
1868 *         else
1869 *         	; // Success
1870 *     }
1871 *
1872 */
1873
1874int IOSerialBSDClient::
1875open(dev_t dev, int flags, int /* devtype */, struct proc * /* p */)
1876{
1877    Session *sp;
1878    struct tty *tp;
1879    int error = 0;
1880    bool wantNonBlock = flags & O_NONBLOCK;
1881    bool imPreempting = false;
1882    bool firstOpen = false;
1883    // fPreemptInProgress is false at the beginning of every open
1884    // as Preemption can only occur later in the open process
1885    //fPreemptInProgress = false;
1886
1887#if JLOG
1888	kprintf("IOSerialBSDClient::open\n");
1889#endif
1890
1891checkBusy:
1892    if (isInactive()) {
1893        error = ENXIO;
1894        goto exitOpen;
1895    }
1896
1897    // Check to see if the currently active device has been pre-empted.
1898    // If the device has been preempted then we have to wait for the
1899    // current owner to close the port.  And THAT means we have to return
1900    // from this open otherwise UNIX doesn't deign to inform us when the
1901    // other process DOES close the port.  Welcome to UNIX being helpful.
1902    sp = &fSessions[IS_TTY_OUTWARD(dev)];
1903	if (sp->ftty == NULL) {
1904#if JLOG
1905		kprintf("IOSerialBSDClient::open::ttymalloc'd\n");
1906#endif
1907		sp->ftty = ttymalloc();
1908		sp->ftty->t_iokit = sp;
1909	}
1910    if (sp->fErrno == EBUSY) {
1911        error = EBUSY;
1912        goto exitOpen;
1913    }
1914
1915    // Can't call startConnectTransit as we need to make sure that
1916    // the device hasn't been hot unplugged while we were waiting.
1917    if (!imPreempting && fConnectTransit) {
1918        tsleep((caddr_t) this, TTIPRI, "ttyopn", 0);
1919        goto checkBusy;
1920    }
1921    fConnectTransit = true;
1922
1923    // Check to see if the device is already open, which means we have an
1924    // active session
1925    if (fActiveSession) {
1926        tp = fActiveSession->ftty;
1927
1928        bool isCallout    = IS_TTY_OUTWARD(tp->t_dev);
1929		fisCallout = isCallout;
1930        bool isPreempt    = fPreemptAllowed;
1931        bool isExclusive  = ISSET(tp->t_state, TS_XCLUDE);
1932        bool isOpen       = ISSET(tp->t_state, TS_ISOPEN);
1933        bool wantCallout  = IS_TTY_OUTWARD(dev);
1934		fwantCallout = wantCallout;
1935        // kauth_cred_issuser returns opposite of suser used in Leopard
1936        bool wantSuser    = kauth_cred_issuser(kauth_cred_get());
1937
1938        if (isCallout) {
1939            // Is Callout and must be open
1940            if (wantCallout) {
1941                if (isExclusive && !wantSuser) {
1942                    //
1943                    // @@@ - UNIX doesn't allow us to block the open
1944                    // until the current session idles if they have the
1945                    // same dev_t.  The opens are reference counted
1946                    // this means that I must return an error and tell
1947                    // the users to use IOKit.
1948                    //
1949                    error = EBUSY;
1950                    goto exitOpen;
1951                }
1952//                else
1953//                    ; // Success - use current session
1954            }
1955            else {
1956checkAndWaitForIdle:
1957                if (wantNonBlock) {
1958                    error = EBUSY;
1959                    goto exitOpen;
1960                } else {
1961                    endConnectTransit();
1962                    error = waitForIdle();
1963                    if (error)
1964                        return error;	// No transition to clean up
1965                    goto checkBusy;
1966                }
1967            }
1968        }
1969        else if (isOpen) {
1970            // Is dial in and open
1971            if (wantCallout) {
1972                if (isPreempt) {
1973                    imPreempting = true;
1974                    preemptActive();
1975                    goto checkBusy;
1976                }
1977                else if (!wantSuser)
1978                    goto checkAndWaitForIdle;
1979//                else
1980//                    ; // Success - use current session (root override)
1981            }
1982            else {
1983                // Want dial in connection
1984                if (isExclusive) {
1985                    //
1986                    // @@@ - UNIX doesn't allow us to block the open
1987                    // until the current session idles if they have the
1988                    // same dev_t.  The opens are reference counted
1989                    // this means that I must return an error and tell
1990                    // the users to use IOKit.
1991                    //
1992                    error = EBUSY;
1993                    goto exitOpen;
1994                }
1995//                else
1996//                    ; // Success - use current session
1997            }
1998        }
1999        else {
2000            // Is dial in and blocking for carrier, i.e. not open
2001            if (wantCallout) {
2002                imPreempting = true;
2003                preemptActive();
2004                goto checkBusy;
2005            }
2006//            else
2007//                ; // Successful, will wait for carrier later
2008        }
2009    }
2010
2011    // If we are here then we have successfully run the open gauntlet.
2012    tp = sp->ftty;
2013
2014    // If there is no active session that means that we have to acquire
2015    // the serial port.
2016    if (!fActiveSession) {
2017        IOReturn rtn = fProvider->acquirePort(/* sleep */ false);
2018	fAcquired = (kIOReturnSuccess == rtn);
2019
2020	// Check for a unplug while we blocked acquiring the port
2021	if (isInactive()) {
2022	    SAFE_PORTRELEASE(fProvider);
2023	    error = ENXIO;
2024	    goto exitOpen;
2025	}
2026	else if (kIOReturnSuccess != rtn) {
2027            error = EBUSY;
2028            goto exitOpen;
2029        }
2030
2031	// We acquired the port successfully
2032	fActiveSession = sp;
2033    }
2034
2035    /*
2036     * Initialize Unix's tty struct,
2037     * set device parameters and RS232 state
2038     */
2039    if ( !ISSET(tp->t_state, TS_ISOPEN) ) {
2040        initSession(sp);
2041        // racey, racey - and initSession doesn't return/set anything useful
2042        if (!fActiveSession || isInactive()) {
2043            SAFE_PORTRELEASE(fProvider);
2044            error = ENXIO;
2045            goto exitOpen;
2046        }
2047
2048        // Initialise the line state
2049        iossparam(tp, &tp->t_termios);
2050    }
2051
2052    /*
2053     * Handle DCD:
2054     * If outgoing or not hw dcd or dcd is asserted, then continue.
2055     * Otherwise, block till dcd is asserted or open fPreempt.
2056     */
2057    if (IS_TTY_OUTWARD(dev)
2058    ||  ISSET(sessionGetState(sp), PD_RS232_S_CAR) ) {
2059		tty_lock(tp);
2060        bsdld_modem(tp, true);
2061		tty_unlock(tp);
2062    }
2063
2064    if (!IS_TTY_OUTWARD(dev) && !ISSET(flags, FNONBLOCK)
2065    &&  !ISSET(tp->t_state, TS_CARR_ON) && !ISSET(tp->t_cflag, CLOCAL)) {
2066
2067        // Drop transit while we wait for the carrier
2068        fInOpensPending++;	// Note we are sleeping
2069        endConnectTransit();
2070
2071        /* Track DCD Transistion to high */
2072        UInt32 pd_state = PD_RS232_S_CAR;
2073        IOReturn rtn = sessionWatchState(sp, &pd_state, PD_RS232_S_CAR);
2074
2075	// Rely on the funnel for atomicicity
2076	int wasPreempted = (EBUSY == sp->fErrno);
2077        fInOpensPending--;
2078	if (!fInOpensPending)
2079	    wakeup(&fInOpensPending);
2080
2081        startConnectTransit(); 	// Sync with the pre-emptor here
2082	if (wasPreempted)	{
2083	    endConnectTransit();
2084	    goto checkBusy;	// Try again
2085	}
2086	else if (kIOReturnSuccess != rtn) {
2087
2088	    // We were probably interrupted
2089	    if (!fInOpensPending) {
2090		// clean up if we are the last opener
2091		SAFE_PORTRELEASE(fProvider);
2092                fActiveSession = 0;
2093
2094		if (fDeferTerminate && isInactive()) {
2095		    bool defer = false;
2096		    super::didTerminate(fProvider, 0, &defer);
2097		}
2098            }
2099
2100            // End the connect transit lock and return the error
2101            endConnectTransit();
2102	    if (isInactive())
2103		return ENXIO;
2104	    else switch (rtn) {
2105	    case kIOReturnAborted:
2106	    case kIOReturnIPCError:	return EINTR;
2107
2108	    case kIOReturnNotOpen:
2109	    case kIOReturnIOError:
2110	    case kIOReturnOffline:	return ENXIO;
2111
2112	    default:
2113					return EIO;
2114	    }
2115	}
2116
2117		// To be here we must be transiting and have DCD
2118		tty_lock(tp);
2119		bsdld_modem(tp, true);
2120		tty_unlock(tp);
2121
2122    }
2123
2124    tty_lock(tp);
2125    if ( !ISSET(tp->t_state, TS_ISOPEN) ) {
2126        firstOpen = true;
2127    }
2128    error = bsdld_open(dev, tp);    // sets TS_ISOPEN
2129    if (error) {
2130	tty_unlock(tp);
2131    } else {
2132	tty_unlock(tp);
2133	if (firstOpen) {
2134	    retain();	// Hold a reference until the port is closed
2135		// because we can still get caught up if we get yanked late
2136		if (!fActiveSession || isInactive()) {
2137			SAFE_PORTRELEASE(fProvider);
2138            error = ENXIO;
2139            goto exitOpen;
2140		}
2141            launchThreads(); // launch the transmit and receive threads
2142		// and we got caught in launchThreads once
2143		if (!fActiveSession || isInactive()) {
2144			SAFE_PORTRELEASE(fProvider);
2145            error = ENXIO;
2146            goto exitOpen;
2147		}
2148	}
2149    }
2150
2151exitOpen:
2152    endConnectTransit();
2153
2154    return error;
2155}
2156
2157void IOSerialBSDClient::
2158close(dev_t dev, int flags, int /* devtype */, struct proc * /* p */)
2159{
2160    struct tty *tp;
2161    Session *sp;
2162    IOReturn rtn;
2163#if JLOG
2164	kprintf("IOSerialBSDClient::close\n");
2165#endif
2166
2167    startConnectTransit();
2168
2169    sp = &fSessions[IS_TTY_OUTWARD(dev)];
2170    tp = sp->ftty;
2171
2172    if (!tp->t_dev && fInOpensPending) {
2173	// Never really opened - time to give up on this device
2174        (void) fProvider->executeEvent(PD_E_ACTIVE, false);
2175        endConnectTransit();
2176        while (fInOpensPending)
2177            tsleep((caddr_t) &fInOpensPending, TTIPRI, "ttyrev", 0);
2178		retain();	// Hold a reference for iossclose to release()
2179        return;
2180    }
2181    /* We are closing, it doesn't matter now about holding back ... */
2182	tty_lock(tp);
2183    CLR(tp->t_state, TS_TTSTOP);
2184	tty_unlock(tp);
2185
2186    if (!sp->fErrno) {
2187        (void) sessionExecuteEvent(sp, PD_E_FLOW_CONTROL, 0);
2188        (void) sessionSetState(sp, -1U, PD_S_RX_ENABLE | PD_S_TX_ENABLE);
2189
2190        // Clear any outstanding line breaks
2191        rtn = sessionEnqueueEvent(sp, PD_RS232_E_LINE_BREAK, false, true);
2192	assert(!rtn || rtn == kIOReturnOffline || rtn == kIOReturnNotOpen);
2193    }
2194	tty_lock(tp);
2195    bsdld_close(tp, flags);
2196	tty_unlock(tp);
2197    if (!sp->fErrno) {
2198        if (ISSET(tp->t_cflag, HUPCL) || !ISSET(tp->t_state, TS_ISOPEN)
2199        || (IS_TTY_PREEMPT(dev, sp->fInitTerm.c_cflag)
2200            && !ISSET(sessionGetState(sp), PD_RS232_S_CAR)) ) {
2201            /*
2202             * XXX we will miss any carrier drop between here and the
2203             * next open.  Perhaps we should watch DCD even when the
2204             * port is closed; it is not sufficient to check it at
2205             * the next open because it might go up and down while
2206             * we're not watching.
2207             */
2208            (void) mctl(RS232_S_OFF, DMSET);
2209        }
2210    }
2211	tty_lock(tp);
2212    ttyclose(tp);	// Drops TS_ISOPEN flag
2213    assert(!tp->t_outq.c_cc);
2214
2215    tty_unlock(tp);
2216    // Shut down the port, this will cause the RX && TX threads to terminate
2217    // Then wait for threads to terminate, this should be over very quickly.
2218
2219    if (!sp->fErrno)
2220        killThreads(); // Disable the chip
2221
2222    if (sp == fActiveSession)
2223    {
2224	SAFE_PORTRELEASE(fProvider);
2225        fPreemptAllowed = false;
2226        fActiveSession = 0;
2227        wakeup(&fPreemptAllowed);	// Wakeup any pre-empters
2228    }
2229
2230    sp->fErrno = 0;	/* Clear the error condition on last close */
2231
2232    endConnectTransit();
2233}
2234/*
2235 * no lock is assumed
2236 */
2237void IOSerialBSDClient::
2238initSession(Session *sp)
2239{
2240    struct tty *tp = sp->ftty;
2241    IOReturn rtn;
2242
2243#if JLOG
2244	kprintf("IOSerialBSDClient::initSession\n");
2245#endif
2246
2247	tty_lock(tp);
2248    tp->t_oproc = iossstart;
2249    tp->t_param = iossparam;
2250    tp->t_termios = sp->fInitTerm;
2251    ttsetwater(tp);
2252	tty_unlock(tp);
2253    /* Activate the session's port */
2254#if JLOG
2255	kprintf("IOSerialBSDClient::initSession::sessionExecuteEvent::PD_E_ACTIVE\n");
2256#endif
2257
2258    rtn = sessionExecuteEvent(sp, PD_E_ACTIVE, true);
2259    if (rtn)
2260        IOLog("ttyioss%04x: ACTIVE failed (%x)\n", tp->t_dev, rtn);
2261#if JLOG
2262	kprintf("IOSerialBSDClient::initSession::sessionExecuteEvent::PD_E_TXQ_FLUSH, 0\n");
2263#endif
2264
2265    rtn  = sessionExecuteEvent(sp, PD_E_TXQ_FLUSH, 0);
2266#if JLOG
2267	kprintf("IOSerialBSDClient::initSession::sessionExecuteEvent::PD_E_RXQ_FLUSH, 0\n");
2268#endif
2269
2270    rtn |= sessionExecuteEvent(sp, PD_E_RXQ_FLUSH, 0);
2271    assert(!rtn || rtn == kIOReturnOffline || rtn == kIOReturnNotOpen);
2272
2273	tty_lock(tp);
2274    CLR(tp->t_state, TS_CARR_ON | TS_BUSY);
2275	tty_unlock(tp);
2276
2277    fKillThreads = false;
2278
2279	if (!fDCDThreadCall) {
2280		debug(DCDTRD, "DCDThread is allocated");
2281		fDCDThreadCall =
2282			thread_call_allocate(&IOSerialBSDClient::iossdcddelay, this);
2283	}
2284    // racey again
2285    // if the early part of initSession takes too long to complete
2286    // we could have been unplugged (or reset) so we should check
2287    // we wait until here because this is the first place we're
2288    // touching the hardware semi-directly
2289    if(sp->fErrno || !fActiveSession || isInactive()) {
2290		debug(DCDTRD, "and then we return offline");
2291        rtn = kIOReturnOffline;
2292        return;
2293    }
2294    // Cycle the PD_RS232_S_DTR line if necessary
2295    if ( !ISSET(fProvider->getState(), PD_RS232_S_DTR) ) {
2296        (void) waitOutDelay(0, &fDTRDownTime, &kDTRDownDelay);
2297        // racey, racey
2298        if(sp->fErrno || !fActiveSession || isInactive()) {
2299            rtn = kIOReturnOffline;
2300            return;
2301        } else
2302            (void) mctl(RS232_S_ON, DMSET);
2303	}
2304
2305    // Disable all flow control  & data movement initially
2306#if JLOG
2307	kprintf("IOSerialBSDClient::initSession::sessionExecuteEvent::PD_E_FLOW_CONTROL, 0\n");
2308#endif
2309    rtn  = sessionExecuteEvent(sp, PD_E_FLOW_CONTROL, 0);
2310#if JLOG
2311	kprintf("IOSerialBSDClient::initSession::sessionSetState::0, PD_S_RX_ENABLE | PD_S_TX_ENABLE\n");
2312#endif
2313
2314    rtn |= sessionSetState(sp, 0, PD_S_RX_ENABLE | PD_S_TX_ENABLE);
2315    assert(!rtn || rtn == kIOReturnOffline || rtn == kIOReturnNotOpen);
2316
2317    /* Raise RTS */
2318#if JLOG
2319	kprintf("IOSerialBSDClient::initSession::sessionSetState::PD_RS232_S_RTS, PD_RS232_S_RTS\n");
2320#endif
2321
2322    rtn = sessionSetState(sp,  PD_RS232_S_RTS, PD_RS232_S_RTS);
2323
2324    assert(!rtn || rtn == kIOReturnOffline || rtn == kIOReturnNotOpen);
2325}
2326
2327bool IOSerialBSDClient::
2328waitOutDelay(void *event,
2329             const struct timeval *start, const struct timeval *duration)
2330{
2331
2332    struct timeval delta;
2333#if JLOG
2334	kprintf("IOSerialBSDClient::waitOutDelay\n");
2335#endif
2336
2337    timeradd(start, duration, &delta); // Delay Till = start + duration
2338
2339    {
2340	struct timeval now;
2341
2342	microuptime(&now);
2343	timersub(&delta, &now, &delta);    // Delay Duration = Delay Till - now
2344    }
2345
2346    if ( delta.tv_sec < 0 || !timerisset(&delta) )
2347        return false;	// Delay expired
2348    else if (event) {
2349        unsigned int delayTicks;
2350
2351        delayTicks = MUSEC2TICK(delta.tv_sec * 1000000 + delta.tv_usec);
2352        tsleep((caddr_t) event, TTIPRI, "ttydelay", delayTicks);
2353    }
2354    else {
2355        unsigned int delayMS;
2356
2357        /* Calculate the required delay in milliseconds, rounded up */
2358        delayMS =  delta.tv_sec * 1000 + (delta.tv_usec + 999) / 1000;
2359
2360        IOSleep(delayMS);
2361    }
2362    return true;	// We did sleep
2363}
2364
2365int IOSerialBSDClient::
2366waitForIdle()
2367{
2368#if JLOG
2369	kprintf("IOSerialBSDClient::waitForIdle\n");
2370#endif
2371
2372    while (fActiveSession || fConnectTransit) {
2373        if (isInactive())
2374            return ENXIO;
2375
2376        int error = tsleep((caddr_t) this, TTIPRI | PCATCH, "ttyidl", 0);
2377        if (error)
2378            return error;
2379    }
2380
2381    return 0;
2382}
2383
2384void IOSerialBSDClient::
2385preemptActive()
2386{
2387#if JLOG
2388	kprintf("IOSerialBSDClient::preemptActive\n");
2389#endif
2390    //
2391    // We are not allowed to pre-empt if the current port has been
2392    // active recently.  So wait out the delay and if we sleep
2393    // then we will need to return to check the open conditions again.
2394    //
2395    if (waitOutDelay(&fPreemptAllowed, &fLastUsedTime, &kPreemptIdle))
2396        return;
2397
2398    Session *sp = fActiveSession;
2399    struct tty *tp = sp->ftty;
2400
2401    sp->fErrno = EBUSY;
2402
2403    // This flag gets reset once we actually take over the session
2404    // this is done by the open code where it acquires the port
2405    // obviously we don't need to re-acquire the port as we didn't
2406    // release it in this case.
2407    //
2408    // setting fPreemptAllowed false here effectively locks other
2409    // preemption out...
2410    fPreemptAllowed = false;
2411    // set fPreemptInProgress to keep the EBUSY condition held high
2412    // during termination of the Preempted open
2413    // --- manifested in txfunc and rxfunc
2414    //
2415    // side effect of locking around the thread start/stop code
2416    fPreemptInProgress = true;
2417
2418    // Enforce a zombie and unconnected state on the discipline
2419	tty_lock(tp);
2420    CLR(tp->t_cflag, CLOCAL);		// Fake up a carrier drop
2421    (void) bsdld_modem(tp, false);
2422	tty_unlock(tp);
2423
2424    // Wakeup all possible sleepers
2425    wakeup(TSA_CARR_ON(tp));
2426	tty_lock(tp);
2427    ttwakeup(tp);
2428	ttwwakeup(tp);
2429    tty_unlock(tp);
2430
2431    killThreads();
2432
2433    // Shutdown the open connection - complicated hand shaking
2434    if (fInOpensPending) {
2435	// Wait for the openers to finish up - still connectTransit
2436	while (fInOpensPending)
2437	    tsleep((caddr_t) &fInOpensPending, TTIPRI, "ttypre", 0);
2438	// Once the sleepers have all woken up it is safe to reset the
2439	// errno and continue on.
2440	sp->fErrno = 0;
2441    }
2442    // Preemption is over (it has occurred)
2443    fPreemptInProgress = false;
2444    fActiveSession = 0;
2445    SAFE_PORTRELEASE(fProvider);
2446}
2447
2448void IOSerialBSDClient::
2449startConnectTransit()
2450{
2451#if JLOG
2452	kprintf("IOSerialBSDClient::startConnectTransit\n");
2453#endif
2454    // Wait for the connection (open()/close()) engine to stabilise
2455    while (fConnectTransit)
2456        tsleep((caddr_t) this, TTIPRI, "ttyctr", 0);
2457    fConnectTransit = true;
2458}
2459
2460void IOSerialBSDClient::
2461endConnectTransit()
2462{
2463#if JLOG
2464	kprintf("IOSerialBSDClient::endConnectTransit\n");
2465#endif
2466    // Clear up the transit while we are waiting for carrier
2467    fConnectTransit = false;
2468    wakeup(this);
2469}
2470/*
2471 * convertFlowCtrl
2472 */
2473void
2474IOSerialBSDClient::convertFlowCtrl(Session *sp, struct termios *t)
2475{
2476    IOReturn rtn;
2477    UInt32 flowCtrl = 0;
2478#if JLOG
2479	kprintf("IOSerialBSDClient::convertFlowCtrl\n");
2480#endif
2481    //
2482    // Have to reconstruct the flow control bits
2483    //
2484    rtn = sessionRequestEvent(sp, PD_E_FLOW_CONTROL, &flowCtrl);
2485    assert(!rtn);
2486
2487    if ( ISSET(flowCtrl, PD_RS232_A_TXO) )
2488        SET(t->c_iflag, IXON);
2489    if ( ISSET(flowCtrl, PD_RS232_A_XANY) )
2490        SET(t->c_iflag, IXANY);
2491    if ( ISSET(flowCtrl, PD_RS232_A_RXO) )
2492        SET(t->c_iflag, IXOFF);
2493
2494    if ( ISSET(flowCtrl, PD_RS232_A_RFR) )
2495        SET(t->c_cflag, CRTS_IFLOW);
2496    if ( ISSET(flowCtrl, PD_RS232_A_CTS) )
2497        SET(t->c_cflag, CCTS_OFLOW);
2498    if ( ISSET(flowCtrl, PD_RS232_A_DTR) )
2499        SET(t->c_cflag, CDTR_IFLOW);
2500
2501}
2502
2503// XXX gvdl: Must only call when session is valid, check isInActive as well
2504/*
2505 * mctl assumes lock isn't held
2506 */
2507int IOSerialBSDClient::
2508mctl(u_int bits, int how)
2509{
2510    u_long oldBits, mbits;
2511    IOReturn rtn;
2512#if JLOG
2513	kprintf("IOSerialBSDClient::mctl\n");
2514#endif
2515    if ( ISSET(bits, PD_RS232_S_BRK) && (how == DMBIS || how == DMBIC) ) {
2516	oldBits = (how == DMBIS);
2517	rtn = fProvider->enqueueEvent(PD_RS232_E_LINE_BREAK, oldBits, true);
2518	if (!rtn && oldBits)
2519	    rtn = fProvider->enqueueEvent(PD_E_DELAY, BRK_DELAY, true);
2520	assert(!rtn || rtn == kIOReturnOffline || rtn == kIOReturnNotOpen);
2521	return oldBits;
2522    }
2523
2524    bits &= RS232_S_OUTPUTS;
2525    oldBits = fProvider->getState();
2526
2527    mbits = oldBits;
2528    switch (how)
2529    {
2530    case DMSET:
2531	mbits = bits | (mbits & RS232_S_INPUTS);
2532	break;
2533
2534    case DMBIS:
2535	SET(mbits, bits);
2536	break;
2537
2538    case DMBIC:
2539	CLR(mbits, bits);
2540	break;
2541
2542    case DMGET:
2543	return mbits;
2544    }
2545
2546    /* Check for a transition of DTR to low and record the down time */
2547    if ( ISSET(oldBits & ~mbits, PD_RS232_S_DTR) )
2548	microuptime(&fDTRDownTime);
2549
2550    rtn = fProvider->setState(mbits, RS232_S_OUTPUTS);
2551    if (rtn)
2552	IOLog("ttyioss%04x: mctl RS232_S_OUTPUTS failed %x\n",
2553	    fBaseDev, rtn);
2554
2555
2556    return mbits;
2557}
2558
2559/*
2560 * Support routines
2561 */
2562#define NOBYPASS_IFLAG_MASK   (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON)
2563#define NOBYPASS_PAR_MASK     (IGNPAR | IGNBRK)
2564#define NOBYPASS_LFLAG_MASK   (ECHO | ICANON | IEXTEN | ISIG)
2565/*
2566 * optimiseInput assumes lock is held
2567 */
2568void IOSerialBSDClient::
2569optimiseInput(struct termios *t)
2570{
2571    Session *sp = fActiveSession;
2572#if JLOG
2573	kprintf("IOSerialBSDClient::optimiseInput\n");
2574#endif
2575    if (!sp)	// Check for a hot unplug
2576	return;
2577
2578    struct tty *tp = sp->ftty;
2579    UInt32 slipEvent, pppEvent;
2580
2581    bool cantByPass =
2582        (ISSET(t->c_iflag, NOBYPASS_IFLAG_MASK)
2583          || ( ISSET(t->c_iflag, BRKINT) && !ISSET(t->c_iflag, IGNBRK) )
2584          || ( ISSET(t->c_iflag, PARMRK)
2585               && ISSET(t->c_iflag, NOBYPASS_PAR_MASK) != NOBYPASS_PAR_MASK)
2586          || ISSET(t->c_lflag, NOBYPASS_LFLAG_MASK)
2587          || linesw[tp->t_line].l_rint != ttyinput);
2588
2589	tty_lock(tp);
2590    if (cantByPass)
2591        CLR(tp->t_state, TS_CAN_BYPASS_L_RINT);
2592    else
2593        SET(tp->t_state, TS_CAN_BYPASS_L_RINT);
2594	tty_unlock(tp);
2595
2596    /*
2597     * Prepare to reduce input latency for packet
2598     * disciplines with a end of packet character.
2599     */
2600    if (tp->t_line == SLIPDISC) {
2601        slipEvent = PD_E_SPECIAL_BYTE;
2602        pppEvent  = PD_E_VALID_DATA_BYTE;
2603    }
2604    else if (tp->t_line == PPPDISC) {
2605        slipEvent = PD_E_VALID_DATA_BYTE;
2606        pppEvent  = PD_E_SPECIAL_BYTE;
2607    }
2608    else {
2609        slipEvent = PD_E_VALID_DATA_BYTE;
2610        pppEvent  = PD_E_VALID_DATA_BYTE;
2611    }
2612    (void) sessionExecuteEvent(sp, slipEvent, 0xc0);
2613    (void) sessionExecuteEvent(sp, pppEvent, 0xc0);
2614}
2615
2616void IOSerialBSDClient::
2617iossdcddelay(thread_call_param_t vSelf, thread_call_param_t vSp)
2618{
2619#if JLOG
2620	kprintf("IOSerialBSDClient::iossdcddelay\n");
2621#endif
2622
2623    IOSerialBSDClient *self = (IOSerialBSDClient *) vSelf;
2624    Session *sp = (Session *) vSp;
2625    struct tty *tp = sp->ftty;
2626
2627    assert(self->fDCDTimerDue);
2628
2629    if (!sp->fErrno && ISSET(tp->t_state, TS_ISOPEN)) {
2630
2631	bool pd_state = ISSET(self->sessionGetState(sp), PD_RS232_S_CAR);
2632	tty_lock(tp);
2633	(void) bsdld_modem(tp, (int) pd_state);
2634	tty_unlock(tp);
2635    }
2636
2637    self->fDCDTimerDue = false;
2638    self->release();
2639}
2640
2641
2642/*
2643 * The three functions below make up the recieve thread of the
2644 * Port Devices Line Discipline interface.
2645 *
2646 *	getData		// Main sleeper function
2647 *	procEvent	// Event processing
2648 *	rxFunc		// Thread main loop
2649*/
2650
2651#define VALID_DATA (PD_E_VALID_DATA_BYTE & PD_E_MASK)
2652
2653void IOSerialBSDClient::
2654getData(Session *sp)
2655{
2656    struct tty *tp = sp->ftty;
2657    UInt32 transferCount, bufferSize, minCount;
2658    UInt8 rx_buf[1024];
2659    IOReturn rtn;
2660
2661#if JLOG
2662	kprintf("IOSerialBSDClient::getData\n");
2663#endif
2664    if (fKillThreads)
2665        return;
2666
2667    bufferSize = TTY_HIGHWATER - TTY_QUEUESIZE(tp);
2668    bufferSize = MIN(bufferSize, (uint32_t)sizeof(rx_buf));
2669    if (bufferSize <= 0) {
2670        frxBlocked = true;	// No buffer space so block ourselves
2671        return;			// Will try again if data present
2672    }
2673    if (frxBlocked) {
2674        frxBlocked = false;
2675    }
2676
2677    // minCount = (delay_usecs)? bufferSize : 1;
2678    minCount = 1;
2679
2680    rtn = sessionDequeueData(sp, rx_buf, bufferSize, &transferCount, minCount);
2681    if (rtn) {
2682	if (rtn == kIOReturnOffline || rtn == kIOReturnNotOpen)
2683	    frxBlocked = true;	// Force a session condition check
2684	else if (rtn != kIOReturnIOError)
2685	    IOLog("ttyioss%04x: dequeueData ret %x\n", tp->t_dev, rtn);
2686        return;
2687    }
2688
2689    if (!transferCount)
2690        return;
2691
2692    // Track last in bound data time
2693    if (fPreemptAllowed)
2694	microuptime(&fLastUsedTime);
2695
2696    /*
2697     * Avoid the grotesquely inefficient lineswitch routine
2698     * (ttyinput) in "raw" mode.  It usually takes about 450
2699     * instructions (that's without canonical processing or echo!).
2700     * slinput is reasonably fast (usually 40 instructions plus
2701     * call overhead).
2702     */
2703    if ( ISSET(tp->t_state, TS_CAN_BYPASS_L_RINT)
2704    &&  !ISSET(tp->t_lflag, PENDIN) ) {
2705		tty_lock(tp);
2706		/* Update statistics */
2707        tk_nin += transferCount;
2708        tk_rawcc += transferCount;
2709        tp->t_rawcc += transferCount;
2710
2711        /* update the rawq and tell recieve waiters to wakeup */
2712		(void) b_to_q(rx_buf, transferCount, &tp->t_rawq);
2713        ttwakeup(tp);
2714		tty_unlock(tp);
2715    }
2716    else {
2717
2718        for (minCount = 0; minCount < transferCount; minCount++) {
2719			tty_lock(tp);
2720            bsdld_rint(rx_buf[minCount], tp);
2721			tty_unlock(tp);
2722		}
2723    }
2724}
2725
2726void IOSerialBSDClient::
2727procEvent(Session *sp)
2728{
2729    struct tty *tp = sp->ftty;
2730    UInt32 event, data;
2731    IOReturn rtn;
2732#if JLOG
2733	kprintf("IOSerialBSDClient::procEvent\n");
2734#endif
2735    if (frxBlocked) {
2736        frxBlocked = false;
2737    }
2738
2739    rtn = sessionDequeueEvent(sp, &event, &data, false);
2740    if (kIOReturnOffline == rtn)
2741	return;
2742
2743    assert(!rtn && event != PD_E_EOQ && (event & PD_E_MASK) != VALID_DATA);
2744
2745    switch(event) {
2746    case PD_E_SPECIAL_BYTE:
2747	break;	// Pass on the character to tty layer
2748
2749    case PD_RS232_E_LINE_BREAK:	data  = 0;	   /* no_break */
2750    case PD_E_FRAMING_ERROR:	SET(data, TTY_FE);	break;
2751    case PD_E_INTEGRITY_ERROR:	SET(data, TTY_PE);	break;
2752
2753    case PD_E_HW_OVERRUN_ERROR:
2754    case PD_E_SW_OVERRUN_ERROR:
2755	IOLog("ttyioss%04x: %sware Overflow\n", tp->t_dev,
2756	    (event == PD_E_SW_OVERRUN_ERROR) ? "Soft" : "Hard" );
2757	event = 0;
2758	break;
2759
2760    case PD_E_DATA_LATENCY:
2761	/* no_break */
2762
2763    case PD_E_FLOW_CONTROL:
2764    default:	/* Ignore */
2765	event = 0;
2766	break;
2767    }
2768
2769    if (event) {
2770        // Track last in bound event time
2771        if (fPreemptAllowed)
2772		microuptime(&fLastUsedTime);
2773	tty_lock(tp);
2774	bsdld_rint(data, tp);
2775	tty_unlock(tp);
2776    }
2777}
2778
2779void IOSerialBSDClient::
2780rxFunc()
2781{
2782    Session *sp;
2783    int event;
2784    UInt32 wakeup_with;	// states
2785    IOReturn rtn;
2786#if JLOG
2787	kprintf("IOSerialBSDClient::rxFunc\n");
2788#endif
2789    sp = fActiveSession;
2790	struct tty *tp = sp->ftty;
2791
2792    IOLockLock(fThreadLock);
2793    frxThread = IOThreadSelf();
2794    IOLockWakeup(fThreadLock, &frxThread, true);	// wakeup the thread launcher
2795    IOLockUnlock(fThreadLock);
2796
2797    frxBlocked = false;
2798
2799    while ( !fKillThreads ) {
2800        if (frxBlocked) {
2801            wakeup_with = PD_S_RX_EVENT;
2802            rtn = sessionWatchState(sp, &wakeup_with, PD_S_RX_EVENT);
2803            sessionSetState(sp, 0, PD_S_RX_EVENT);
2804            if ( kIOReturnOffline == rtn || kIOReturnNotOpen == rtn
2805	    ||   fKillThreads)
2806                break;	// Terminate thread loop
2807        }
2808	event = (sessionNextEvent(sp) & PD_E_MASK);
2809	if (event == PD_E_EOQ || event == VALID_DATA)
2810	    getData(sp);
2811	else
2812	    procEvent(sp);
2813    }
2814
2815    // commit seppuku cleanly
2816#ifdef DEBUG
2817    debug(CONTROL, "%s\n%s\n%s", state2StringPD(sessionGetState(sp)), state2StringTTY(tp->t_state), state2StringTermios((int)tp->t_cflag));
2818#endif
2819
2820    IOLockLock(fThreadLock);
2821    frxThread = THREAD_NULL;
2822    IOLockWakeup(fThreadLock, &frxThread, true);	// wakeup the thread killer
2823	debug(FLOW, "fisCallout is: %d, fwantCallout is: %d, fisBlueTooth is: %d", fisCallout, fwantCallout, fisBlueTooth);
2824	debug(FLOW, "fPreemptAllowed is: %d", fPreemptAllowed);
2825
2826    if (fDeferTerminate && !ftxThread && !fInOpensPending) {
2827	SAFE_PORTRELEASE(fProvider);
2828
2829	bool defer = false;
2830	super::didTerminate(fProvider, 0, &defer);
2831    }
2832    else // we shouldn't go down this path if we've already released the port
2833         // (and didTerminate handles the rest of the issues anyway)
2834    {
2835        debug(FLOW, "we're killing our thread");
2836        // because bluetooth leaves its /dev/tty entries around
2837        // we need to tell the bsd side that carrier has dropped
2838        // when bluetooth tells us kIOReturnNotOpen (which it does correctly)
2839        // other tty like driver stacks would also ask us to remove the
2840        // /dev/tty entries which would terminate us cleanly
2841        // so... this check should be benign except for bluetooth
2842        // it should also be pointed out that it may be a limitation of the CLOCAL
2843        // handling in ppp that contributes to this problem
2844        //
2845        // benign except for the preemption case - fixed...
2846        if (!ftxThread && !fInOpensPending && !fPreemptInProgress && fisBlueTooth)
2847        {
2848            // no transmit thread, we're about to kill the receive thread
2849            // tell the bsd side no more bytes (fErrno = 0)
2850            debug(FLOW, "no more threads, so we shouldn't be busy or have carrier");
2851            // Now kill any stream that may currently be running
2852            sp->fErrno = 0;
2853
2854            // Enforce a zombie and unconnected state on the discipline
2855#ifdef DEBUG
2856            debug(CONTROL, "%s\n%s\n%s", state2StringPD(sessionGetState(sp)), state2StringTTY(tp->t_state), state2StringTermios((int)tp->t_cflag));
2857#endif
2858            debug(FLOW, "faking a CLOCAL drop");
2859            tty_lock(tp);
2860            CLR(tp->t_cflag, CLOCAL);  // Fake up a carrier drop
2861            debug(FLOW, "faked a CLOCAL drop, about to fake a carrier drop");
2862#ifdef DEBUG
2863            debug(CONTROL, "%s\n%s\n%s", state2StringPD(sessionGetState(sp)), state2StringTTY(tp->t_state), state2StringTermios((int)tp->t_cflag));
2864#endif
2865
2866            (void) bsdld_modem(tp, false);
2867            tty_unlock(tp);
2868            debug(FLOW, "faked a carrier drop");
2869#ifdef DEBUG
2870            debug(CONTROL, "%s\n%s\n%s", state2StringPD(sessionGetState(sp)), state2StringTTY(tp->t_state), state2StringTermios((int)tp->t_cflag));
2871#endif
2872
2873        }
2874    }
2875    debug(FLOW, "thread be dead");
2876    IOLockUnlock(fThreadLock);
2877    (void) thread_terminate(current_thread());
2878}
2879
2880/*
2881 * The three functions below make up the status monitoring and transmition
2882 * part of the Port Devices Line Discipline interface.
2883 *
2884 *	txload		// TX data download to Port Device
2885 *	dcddelay	// DCD callout function for DCD transitions
2886 *	txFunc		// Thread main loop and sleeper
2887 *
2888 *  txload assumes the lock is not held when it is called...
2889 */
2890
2891void IOSerialBSDClient::
2892txload(Session *sp, UInt32 *wait_mask)
2893{
2894    struct tty *tp = sp->ftty;
2895    IOReturn rtn;
2896    UInt8 tx_buf[CBSIZE * 8];	// 1/2k buffer
2897    UInt32 data;
2898    UInt32 cc, size;
2899#if JLOG
2900	kprintf("IOSerialBSDClient::txload\n");
2901#endif
2902    if ( !tp->t_outq.c_cc )
2903		return;		// Nothing to do
2904    if ( !ISSET(tp->t_state, TS_BUSY) ) {
2905		tty_lock(tp);
2906        SET(tp->t_state, TS_BUSY);
2907        tty_unlock(tp);
2908		SET(*wait_mask, PD_S_TXQ_EMPTY); // Start tracking PD_S_TXQ_EMPTY
2909		CLR(*wait_mask, PD_S_TX_BUSY);
2910
2911    }
2912
2913    while ( (cc = tp->t_outq.c_cc) ) {
2914        rtn = sessionRequestEvent(sp, PD_E_TXQ_AVAILABLE, &data);
2915		if (kIOReturnOffline == rtn || kIOReturnNotOpen == rtn)
2916			return;
2917
2918		assert(!rtn);
2919
2920        size = data;
2921		if (size > 0)
2922			size = MIN(size, (uint32_t)sizeof(tx_buf));
2923		else {
2924			SET(*wait_mask, PD_S_TXQ_LOW_WATER); // Start tracking low water
2925			return;
2926		}
2927		tty_lock(tp);
2928		size = q_to_b(&tp->t_outq, tx_buf, MIN(cc, size));
2929		tty_unlock(tp);
2930		assert(size);
2931
2932	/* There was some data left over from the previous load */
2933        rtn = sessionEnqueueData(sp, tx_buf, size, &cc, false);
2934        if (fPreemptAllowed)
2935	    microuptime(&fLastUsedTime);
2936
2937		if (kIOReturnSuccess == rtn) {
2938			tty_lock(tp);
2939			bsdld_start(tp);
2940			tty_unlock(tp);
2941		}
2942        else
2943	    IOLog("ttyioss%04x: enqueueData rtn (%x)\n", tp->t_dev, rtn);
2944#ifdef DEBUG
2945        if ((u_int) cc != size)
2946            IOLog("ttyioss%04x: enqueueData didn't queue everything\n",
2947                  tp->t_dev);
2948#endif
2949    }
2950}
2951
2952void IOSerialBSDClient::
2953txFunc()
2954{
2955    Session *sp;
2956    struct tty *tp;
2957    UInt32 waitfor, waitfor_mask, wakeup_with;	// states
2958    UInt32 interesting_bits;
2959    IOReturn rtn;
2960#if JLOG
2961	kprintf("IOSerialBSDClient::txFunc\n");
2962#endif
2963    sp = fActiveSession;
2964    tp = sp->ftty;
2965
2966    IOLockLock(fThreadLock);
2967    ftxThread = IOThreadSelf();
2968    IOLockWakeup(fThreadLock, &ftxThread, true);	// wakeup the thread launcher
2969    IOLockUnlock(fThreadLock);
2970
2971    /*
2972     * Register interest in transitions to high of the
2973     *  PD_S_TXQ_LOW_WATER, PD_S_TXQ_EMPTY, PD_S_TX_EVENT status bits
2974     * and all other bit's being low
2975     */
2976    waitfor_mask = (PD_S_TX_EVENT | PD_S_TX_BUSY       | PD_RS232_S_CAR);
2977    waitfor      = (PD_S_TX_EVENT | PD_S_TXQ_LOW_WATER | PD_S_TXQ_EMPTY);
2978
2979    // Get the current carrier state and toggle it
2980    SET(waitfor, ISSET(sessionGetState(sp), PD_RS232_S_CAR) ^ PD_RS232_S_CAR);
2981    for ( ;; ) {
2982		wakeup_with = waitfor;
2983		rtn  = sessionWatchState(sp, &wakeup_with, waitfor_mask);
2984		if ( rtn )
2985			break;	// Terminate thread loop
2986
2987		//
2988		// interesting_bits are set to true if the wait_for = wakeup_with
2989		// and we expressed an interest in the bit in waitfor_mask.
2990		//
2991		interesting_bits = waitfor_mask & (~waitfor ^ wakeup_with);
2992
2993		// Has iossstart been trying to get out attention
2994		if ( ISSET(PD_S_TX_EVENT, interesting_bits) ) {
2995			/* Clear PD_S_TX_EVENT bit in state register */
2996			rtn = sessionSetState(sp, 0, PD_S_TX_EVENT);
2997			assert(!rtn || rtn == kIOReturnOffline || rtn == kIOReturnNotOpen);
2998			txload(sp, &waitfor_mask);
2999		}
3000
3001		//
3002		// Now process the carriers current state if it has changed
3003		//
3004		if ( ISSET(PD_RS232_S_CAR, interesting_bits) ) {
3005			waitfor ^= PD_RS232_S_CAR;		/* toggle value */
3006
3007			if (fDCDTimerDue) {
3008				/* Stop dcd timer interval was too short */
3009				if (thread_call_cancel(fDCDThreadCall)) {
3010					debug(DCDTRD,"DCD thread canceled (interval too short)");
3011					release();
3012					fDCDTimerDue = false;
3013				}
3014			} else {
3015				AbsoluteTime dl;
3016
3017				clock_interval_to_deadline(DCD_DELAY, kMicrosecondScale, &dl);
3018				thread_call_enter1_delayed(fDCDThreadCall, sp, dl);
3019				debug(DCDTRD,"DCD thread enter1 delayed");
3020				retain();
3021				fDCDTimerDue = true;
3022			}
3023		}
3024
3025		//
3026		// Check to see if we can unblock the data transmission
3027		//
3028
3029		if ( ISSET(PD_S_TXQ_LOW_WATER, interesting_bits) ) {
3030			CLR(waitfor_mask, PD_S_TXQ_LOW_WATER); // Not interested any more
3031			txload(sp, &waitfor_mask);
3032		}
3033
3034		//
3035		// 2 stage test for transmitter being no longer busy.
3036		// Stage 1: TXQ_EMPTY high, register interest in TX_BUSY bit
3037		//
3038		if ( ISSET(PD_S_TXQ_EMPTY, interesting_bits) ) {
3039			CLR(waitfor_mask, PD_S_TXQ_EMPTY); /* Not interested */
3040			SET(waitfor_mask, PD_S_TX_BUSY);   // But I want to know about chip
3041		}
3042
3043		//
3044		// Stage 2 TX_BUSY dropping.
3045		// NB don't want to use interesting_bits as the TX_BUSY mask may
3046		// have just been set.  Instead here we simply check for a low.
3047		//
3048		if (PD_S_TX_BUSY & waitfor_mask & ~wakeup_with) {
3049			CLR(waitfor_mask, PD_S_TX_BUSY); /* No longer interested */
3050			tty_lock(tp);
3051			CLR(tp->t_state,  TS_BUSY);
3052
3053			/* Notify disc, not busy anymore */
3054			bsdld_start(tp);
3055			tty_unlock(tp);
3056		}
3057
3058    }
3059
3060    // Clear the DCD timeout
3061    if (fDCDTimerDue && thread_call_cancel(fDCDThreadCall)) {
3062		debug(DCDTRD,"DCD thread canceled (clear timeout)");
3063		release();
3064		fDCDTimerDue = false;
3065    }
3066
3067    // Drop the carrier line and clear the BUSY bit
3068	if (!fActiveSession || isInactive()) {
3069		// we've been dropped via a hotplug
3070		// cleanup on aisle 5
3071		//
3072		// since there are 2 ways to die (sigh) if we died due to isInactive
3073		// notify upstream...
3074		if(fActiveSession) sp->fErrno = ENXIO;
3075
3076		SAFE_PORTRELEASE(fProvider);
3077
3078		bool defer = false;
3079		super::didTerminate(fProvider, 0, &defer);
3080	}
3081	else // we're still gonna die, just cleanly
3082	{
3083	tty_lock(tp);
3084    (void) bsdld_modem(tp, false);
3085	tty_unlock(tp);
3086
3087    IOLockLock(fThreadLock);
3088    ftxThread = THREAD_NULL;
3089    IOLockWakeup(fThreadLock, &ftxThread, true);	// wakeup the thread killer
3090	debug(FLOW, "fisCallout is: %d, fwantCallout is: %d, fisBlueTooth is: %d", fisCallout, fwantCallout, fisBlueTooth);
3091	debug(FLOW, "fPreemptAllowed is: %d", fPreemptAllowed);
3092
3093    if (fDeferTerminate && !frxThread && !fInOpensPending) {
3094		SAFE_PORTRELEASE(fProvider);
3095
3096		bool defer = false;
3097		super::didTerminate(fProvider, 0, &defer);
3098    }
3099    else // we shouldn't go down this path if we've already released the port
3100         // (and didTerminate handles the rest of the issues anyway)
3101    {
3102        debug(FLOW, "we're killing our thread");
3103        // because bluetooth leaves its /dev/tty entries around
3104        // we need to tell the bsd side that carrier has dropped
3105        // when bluetooth tells us kIOReturnNotOpen (which it does correctly)
3106        // other tty like driver stacks would also ask us to remove the
3107        // /dev/tty entries which would terminate us cleanly
3108        // so... this check should be benign except for bluetooth
3109        //
3110        // it should also be pointed out that it may be a limitation of the CLOCAL
3111        // handling in ppp that contributes to this problem
3112        //
3113        // benign except in the preemption case - fixed...
3114        if (!frxThread && !fInOpensPending && !fPreemptInProgress && fisBlueTooth)
3115        {
3116            // no receive thread, we're about to kill the transmit thread
3117            // tell the bsd side no more bytes (fErrno = 0)
3118            debug(FLOW, "no more threads, so we shouldn't be busy or have carrier");
3119            // Now kill any stream that may currently be running
3120            sp->fErrno = 0;
3121
3122            // Enforce a zombie and unconnected state on the discipline
3123#ifdef DEBUG
3124            debug(CONTROL, "%s\n%s\n%s", state2StringPD(sessionGetState(sp)), state2StringTTY(tp->t_state), state2StringTermios((int)tp->t_cflag));
3125#endif
3126            debug(FLOW, "faking a CLOCAL drop");
3127            tty_lock(tp);
3128            CLR(tp->t_cflag, CLOCAL);  // Fake up a carrier drop
3129            debug(FLOW, "faked a CLOCAL drop, about to fake a carrier drop");
3130#ifdef DEBUG
3131            debug(CONTROL, "%s\n%s\n%s", state2StringPD(sessionGetState(sp)), state2StringTTY(tp->t_state), state2StringTermios((int)tp->t_cflag));
3132#endif
3133
3134            (void) bsdld_modem(tp, false);
3135            tty_unlock(tp);
3136            debug(FLOW, "faked a carrier drop");
3137#ifdef DEBUG
3138            debug(CONTROL, "%s\n%s\n%s", state2StringPD(sessionGetState(sp)), state2StringTTY(tp->t_state), state2StringTermios((int)tp->t_cflag));
3139#endif
3140        }
3141    }
3142		IOLockUnlock(fThreadLock);
3143	}
3144
3145    debug(FLOW, "thread be dead");
3146    (void) thread_terminate(current_thread());
3147}
3148
3149void IOSerialBSDClient::
3150launchThreads()
3151{
3152    // Clear the have launched flags
3153#if JLOG
3154	kprintf("IOSerialBSDClient::launchThreads\n");
3155#endif
3156
3157    IOLockLock(fThreadLock);
3158
3159    ftxThread = frxThread = THREAD_NULL;
3160
3161    // Now launch the receive and transmitter threads
3162#if JLOG
3163	kprintf("IOSerialBSDClient::createThread::rxFunc\n");
3164#endif
3165
3166    createThread(
3167	OSMemberFunctionCast(IOThreadFunc, this, &IOSerialBSDClient::rxFunc),
3168	this);
3169#if JLOG
3170	kprintf("IOSerialBSDClient::createThread::txFunc\n");
3171#endif
3172    createThread(
3173	OSMemberFunctionCast(IOThreadFunc, this, &IOSerialBSDClient::txFunc),
3174	this);
3175
3176    // Now wait for the threads to actually launch
3177    while (!frxThread)
3178	IOLockSleep(fThreadLock, &frxThread, THREAD_UNINT);
3179    while (!ftxThread)
3180	IOLockSleep(fThreadLock, &ftxThread, THREAD_UNINT);
3181
3182    IOLockUnlock(fThreadLock);
3183}
3184
3185void IOSerialBSDClient::
3186killThreads()
3187{
3188#if JLOG
3189	kprintf("IOSerialBSDClient::killThreads\n");
3190#endif
3191    if (frxThread || ftxThread || fInOpensPending) {
3192        fKillThreads = true;
3193	fProvider->executeEvent(PD_E_ACTIVE, false);
3194
3195	IOLockLock(fThreadLock);
3196        while (frxThread)
3197	    IOLockSleep(fThreadLock, &frxThread, THREAD_UNINT);
3198        while (ftxThread)
3199	    IOLockSleep(fThreadLock, &ftxThread, THREAD_UNINT);
3200	IOLockUnlock(fThreadLock);
3201    }
3202#ifdef TARGET_OS_EMBEDDED
3203	// bluetooth, modem and fax team need to validate change
3204	// to remove this ifdef
3205	if (fDCDThreadCall) {
3206		debug(DCDTRD,"DCD Thread Freed in killThreads");
3207		thread_call_cancel(fDCDThreadCall);
3208		thread_call_free(fDCDThreadCall);
3209		fDCDTimerDue = false;
3210		fDCDThreadCall = 0;
3211	}
3212#endif
3213}
3214
3215void IOSerialBSDClient::
3216cleanupResources()
3217{
3218#if JLOG
3219	kprintf("IOSerialBSDClient::cleanupResources\n");
3220#endif
3221    // Remove our device name from the devfs
3222    if ((dev_t) -1 != fBaseDev) {
3223	sBSDGlobals.takefFunnelLock();
3224	sBSDGlobals.releaseUniqueTTYSuffix(
3225		(const OSSymbol *) getProperty(gIOTTYBaseNameKey),
3226		(const OSSymbol *) getProperty(gIOTTYSuffixKey));
3227	sBSDGlobals.releasefFunnelLock();
3228    }
3229
3230    if (fSessions[TTY_CALLOUT_INDEX].fCDevNode)
3231	devfs_remove(fSessions[TTY_CALLOUT_INDEX].fCDevNode);
3232    if (fSessions[TTY_DIALIN_INDEX].fCDevNode)
3233	devfs_remove(fSessions[TTY_DIALIN_INDEX].fCDevNode);
3234}
3235
3236//
3237// session based accessors to Serial Stream Sync
3238//
3239IOReturn IOSerialBSDClient::
3240sessionSetState(Session *sp, UInt32 state, UInt32 mask)
3241{
3242#if JLOG
3243	kprintf("IOSerialBSDClient::sessionSetState\n");
3244#endif
3245    if (sp->fErrno)
3246        return kIOReturnOffline;
3247    else
3248        return fProvider->setState(state, mask);
3249}
3250
3251UInt32 IOSerialBSDClient::
3252sessionGetState(Session *sp)
3253{
3254#if JLOG
3255	kprintf("IOSerialBSDClient::sessionGetState\n");
3256#endif
3257
3258    if (sp->fErrno)
3259        return 0;
3260    else
3261        return fProvider->getState();
3262}
3263
3264IOReturn IOSerialBSDClient::
3265sessionWatchState(Session *sp, UInt32 *state, UInt32 mask)
3266{
3267#if JLOG
3268	kprintf("IOSerialBSDClient::sessionWatchState\n");
3269#endif
3270
3271    if (sp->fErrno)
3272        return kIOReturnOffline;
3273    else
3274        return fProvider->watchState(state, mask);
3275}
3276
3277UInt32 IOSerialBSDClient::
3278sessionNextEvent(Session *sp)
3279{
3280#if JLOG
3281	kprintf("IOSerialBSDClient::sessionNextEvent\n");
3282#endif
3283
3284    if (sp->fErrno)
3285        return PD_E_EOQ;
3286    else
3287        return fProvider->nextEvent();
3288}
3289
3290IOReturn IOSerialBSDClient::
3291sessionExecuteEvent(Session *sp, UInt32 event, UInt32 data)
3292{
3293#if JLOG
3294	kprintf("IOSerialBSDClient::sessionExecuteEvent\n");
3295#endif
3296
3297    if (sp->fErrno)
3298        return kIOReturnOffline;
3299    else
3300        return fProvider->executeEvent(event, data);
3301}
3302
3303IOReturn IOSerialBSDClient::
3304sessionRequestEvent(Session *sp, UInt32 event, UInt32 *data)
3305{
3306#if JLOG
3307	kprintf("IOSerialBSDClient::sessionRequestEvent\n");
3308#endif
3309
3310    if (sp->fErrno)
3311        return kIOReturnOffline;
3312    else
3313        return fProvider->requestEvent(event, data);
3314}
3315
3316IOReturn IOSerialBSDClient::
3317sessionEnqueueEvent(Session *sp, UInt32 event, UInt32 data, bool sleep)
3318{
3319#if JLOG
3320	kprintf("IOSerialBSDClient::sessionEnqueueEvent\n");
3321#endif
3322
3323    if (sp->fErrno)
3324        return kIOReturnOffline;
3325    else
3326        return fProvider->enqueueEvent(event, data, sleep);
3327}
3328
3329IOReturn IOSerialBSDClient::
3330sessionDequeueEvent(Session *sp, UInt32 *event, UInt32 *data, bool sleep)
3331{
3332#if JLOG
3333	kprintf("IOSerialBSDClient::sessionDequeueEvent\n");
3334#endif
3335
3336    if (sp->fErrno)
3337        return kIOReturnOffline;
3338    else
3339        return fProvider->dequeueEvent(event, data, sleep);
3340}
3341
3342IOReturn IOSerialBSDClient::
3343sessionEnqueueData(Session *sp, UInt8 *buffer, UInt32 size, UInt32 *count, bool sleep)
3344{
3345#if JLOG
3346	kprintf("IOSerialBSDClient::sessionEnqueueData\n");
3347#endif
3348
3349    if (sp->fErrno)
3350        return kIOReturnOffline;
3351    else
3352        return fProvider->enqueueData(buffer, size, count, sleep);
3353}
3354
3355IOReturn IOSerialBSDClient::
3356sessionDequeueData(Session *sp, UInt8 *buffer, UInt32 size, UInt32 *count, UInt32 min)
3357{
3358#if JLOG
3359	kprintf("IOSerialBSDClient::sessionDequeueData\n");
3360#endif
3361
3362    if (sp->fErrno)
3363        return kIOReturnOffline;
3364    else
3365        return fProvider->dequeueData(buffer, size, count, min);
3366}
3367
3368IOThread IOSerialBSDClient::
3369createThread(IOThreadFunc fcn, void *arg)
3370{
3371	kern_return_t        result;
3372	thread_t                thread;
3373#if JLOG
3374	kprintf("IOSerialBSDClient::createThread\n");
3375#endif
3376
3377	result = kernel_thread_start((thread_continue_t)fcn, arg, &thread);
3378	if (result != KERN_SUCCESS)
3379		return (NULL);
3380	thread_deallocate(thread);
3381	return (thread);
3382}
3383
3384#ifdef DEBUG
3385char * IOSerialBSDClient::state2StringTermios(UInt32 state)
3386    {
3387    static char stateDescription[1024];
3388
3389    // Nulls the string:
3390    stateDescription[0] = 0;
3391
3392    // reads the state and appends values:
3393    if (state & CIGNORE)
3394        strncat(stateDescription, "CIGNORE ", sizeof(stateDescription) - 9);
3395
3396
3397    if (state & CSIZE)
3398    strncat(stateDescription, "CSIZE ", sizeof(stateDescription) - 7);
3399
3400    if (state & CSTOPB)
3401    strncat(stateDescription, "CSTOPB ", sizeof(stateDescription) - 8);
3402
3403    if (state & CREAD)
3404    strncat(stateDescription, "CREAD ", sizeof(stateDescription) - 7);
3405
3406    if (state & PARENB)
3407    strncat(stateDescription, "PARENB ", sizeof(stateDescription) - 8);
3408
3409    if (state & PARODD)
3410    strncat(stateDescription, "PARODD ", sizeof(stateDescription) - 8);
3411
3412    if (state & HUPCL)
3413    strncat(stateDescription, "HUPCL ", sizeof(stateDescription) - 7);
3414
3415    if (state & CLOCAL)
3416    strncat(stateDescription, "CLOCAL ", sizeof(stateDescription) - 8);
3417
3418    if (state & CCTS_OFLOW)
3419    strncat(stateDescription, "CCTS_OFLOW ", sizeof(stateDescription) - 12);
3420
3421    if (state & CRTSCTS)
3422    strncat(stateDescription, "CRTSCTS ", sizeof(stateDescription) - 9);
3423
3424    if (state & CRTS_IFLOW)
3425    strncat(stateDescription, "CRTS_IFLOW ", sizeof(stateDescription) - 12);
3426
3427    if (state & CDTR_IFLOW)
3428    strncat(stateDescription, "CDTR_IFLOW ", sizeof(stateDescription) - 12);
3429
3430    if (state & CDSR_OFLOW)
3431    strncat(stateDescription, "CDSR_OFLOW ", sizeof(stateDescription) - 12);
3432
3433    if (state & CCAR_OFLOW)
3434    strncat(stateDescription, "CCAR_OFLOW ", sizeof(stateDescription) - 12);
3435
3436    if (state & MDMBUF)
3437    strncat(stateDescription, "MDMBUF ", sizeof(stateDescription) - 8);
3438
3439    return (stateDescription);
3440    }
3441
3442char * IOSerialBSDClient::state2StringPD(UInt32 state)
3443    {
3444    static char stateDescription[1024];
3445
3446    // Nulls the string:
3447    stateDescription[0] = 0;
3448
3449    // reads the state and appends values:
3450    // reads the state and appends values:
3451    if (state & PD_RS232_S_CAR)
3452        strncat(stateDescription, "PD_RS232_S_CAR ", sizeof(stateDescription) - 16);
3453    else
3454        strncat(stateDescription, "^PD_RS232_S_CAR ", sizeof(stateDescription) - 17);
3455
3456    if (state & PD_S_ACQUIRED)
3457    strncat(stateDescription, "PD_S_ACQUIRED ", sizeof(stateDescription) - 16);
3458
3459    if (state & PD_S_ACTIVE)
3460    strncat(stateDescription, "PD_S_ACTIVE ", sizeof(stateDescription) - 13);
3461
3462    if (state & PD_S_TX_ENABLE)
3463    strncat(stateDescription, "PD_S_TX_ENABLE ", sizeof(stateDescription) - 16);
3464
3465    if (state & PD_S_TX_BUSY)
3466    strncat(stateDescription, "PD_S_TX_BUSY ", sizeof(stateDescription) - 14);
3467
3468    if (state & PD_S_TX_EVENT)
3469    strncat(stateDescription, "PD_S_TX_EVENT ", sizeof(stateDescription) - 15);
3470
3471    if (state & PD_S_TXQ_EMPTY)
3472    strncat(stateDescription, "PD_S_TXQ_EMPTY ", sizeof(stateDescription) - 16);
3473
3474    if (state & PD_S_TXQ_LOW_WATER)
3475    strncat(stateDescription, "PD_S_TXQ_LOW_WATER ", sizeof(stateDescription) - 20);
3476
3477    if (state & PD_S_TXQ_HIGH_WATER)
3478    strncat(stateDescription, "PD_S_TXQ_HIGH_WATER ", sizeof(stateDescription) - 21);
3479
3480    if (state & PD_S_TXQ_FULL)
3481    strncat(stateDescription, "PD_S_TXQ_FULL ", sizeof(stateDescription) - 15);
3482
3483    if (state & PD_S_TXQ_MASK)
3484    strncat(stateDescription, "(PD_S_TXQ_MASK) ", sizeof(stateDescription) - 17);
3485
3486    if (state & PD_S_RX_ENABLE)
3487    strncat(stateDescription, "PD_S_RX_ENABLE ", sizeof(stateDescription) - 16);
3488
3489    if (state & PD_S_RX_BUSY)
3490    strncat(stateDescription, "PD_S_RX_BUSY ", sizeof(stateDescription) - 14);
3491
3492    if (state & PD_S_RX_EVENT)
3493    strncat(stateDescription, "PD_S_RX_EVENT ", sizeof(stateDescription) - 15);
3494
3495    if (state & PD_S_RXQ_EMPTY)
3496    strncat(stateDescription, "PD_S_RXQ_EMPTY ", sizeof(stateDescription) - 16);
3497
3498    if (state & PD_S_RXQ_LOW_WATER)
3499    strncat(stateDescription, "PD_S_RXQ_LOW_WATER ", sizeof(stateDescription) - 20);
3500
3501    if (state & PD_S_RXQ_HIGH_WATER)
3502    strncat(stateDescription, "PD_S_RXQ_HIGH_WATER ", sizeof(stateDescription) - 21);
3503
3504    if (state & PD_S_RXQ_FULL)
3505    strncat(stateDescription, "PD_S_RXQ_FULL ", sizeof(stateDescription) - 15);
3506
3507    if (state & PD_S_RXQ_MASK)
3508    strncat(stateDescription, "(PD_S_RXQ_MASK) ", sizeof(stateDescription) - 17);
3509
3510    return (stateDescription);
3511    }
3512
3513char * IOSerialBSDClient::state2StringTTY(UInt32 state)
3514    {
3515    static char stateDescription[2048];
3516
3517    // Nulls the string:
3518    stateDescription[0] = 0;
3519
3520    // reads the state and appends values:
3521    if (state & TS_SO_OLOWAT)
3522    strncat(stateDescription, "TS_SO_OLOWAT ", sizeof(stateDescription) - 14);
3523
3524    if (state & TS_ASYNC)
3525    strncat(stateDescription, "TS_ASYNC ", sizeof(stateDescription) - 10);
3526
3527    if (state & TS_BUSY)
3528    strncat(stateDescription, "TS_BUSY ", sizeof(stateDescription) - 9);
3529
3530    if (state & TS_CARR_ON)
3531    strncat(stateDescription, "TS_CARR_ON ", sizeof(stateDescription) - 12);
3532
3533    if (state & TS_FLUSH)
3534    strncat(stateDescription, "TS_FLUSH ", sizeof(stateDescription) - 10);
3535
3536    if (state & TS_ISOPEN)
3537    strncat(stateDescription, "TS_ISOPEN ", sizeof(stateDescription) - 11);
3538
3539    if (state & TS_TBLOCK)
3540    strncat(stateDescription, "TS_TBLOCK ", sizeof(stateDescription) - 11);
3541
3542    if (state & TS_TIMEOUT)
3543    strncat(stateDescription, "TS_TIMEOUT ", sizeof(stateDescription) - 12);
3544
3545    if (state & TS_TTSTOP)
3546    strncat(stateDescription, "TS_TTSTOP ", sizeof(stateDescription) - 11);
3547
3548    // needs to pull in the notyet definition from tty.h
3549    //if (state & TS_WOPEN)
3550    //strncat(stateDescription, "TS_WOPEN ", sizeof(stateDescription) - 10);
3551
3552    if (state & TS_XCLUDE)
3553    strncat(stateDescription, "TS_XCLUDE ", sizeof(stateDescription) - 11);
3554
3555    if (state & TS_LOCAL)
3556    strncat(stateDescription, "TS_LOCAL ", sizeof(stateDescription) - 10);
3557
3558    if (state & TS_ZOMBIE)
3559    strncat(stateDescription, "TS_ZOMBIE ", sizeof(stateDescription) - 11);
3560
3561    if (state & TS_CONNECTED)
3562    strncat(stateDescription, "TS_CONNECTED ", sizeof(stateDescription) - 14);
3563
3564    if (state & TS_CAN_BYPASS_L_RINT)
3565    strncat(stateDescription, "TS_CAN_BYPASS_L_RINT ", sizeof(stateDescription) - 22);
3566
3567    if (state & TS_SNOOP)
3568    strncat(stateDescription, "TS_SNOOP ", sizeof(stateDescription) - 10);
3569
3570    if (state & TS_SO_OCOMPLETE)
3571    strncat(stateDescription, "TS_SO_OCOMPLETE ", sizeof(stateDescription) - 17);
3572
3573    if (state & TS_CAR_OFLOW)
3574    strncat(stateDescription, "TS_CAR_OFLOW ", sizeof(stateDescription) - 14);
3575
3576    // needs to pull in the notyet definition from tty.h
3577    //if (state & TS_CTS_OFLOW)
3578    //strncat(stateDescription, "TS_CTS_OFLOW ", sizeof(stateDescription) - 14);
3579
3580    // needs to pull in the notyet definition from tty.h
3581    //if (state & TS_DSR_OFLOW)
3582    //strncat(stateDescription, "TS_DSR_OFLOW ", sizeof(stateDescription) - 14);
3583
3584    return (stateDescription);
3585    }
3586#endif
3587