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    fThreadState = 0x0000;
804
805	fOpenCloseLock = IOLockAlloc();
806	if (!fOpenCloseLock)
807		return false;
808
809	fIoctlLock = IOLockAlloc();
810	if (!fIoctlLock)
811		return false;
812
813	fisBlueTooth = false;
814	fPreemptInProgress = false;
815	fDCDThreadCall = 0;
816
817
818    /*
819     * First initialise the dial in device.
820     * We don't use all the flags from <sys/ttydefaults.h> since they are
821     * only relevant for logins.
822	 *
823	 * initialize the hotplug flag to zero (bsd hasn't attached so we are safe to unplug)
824     */
825    fSessions[TTY_DIALIN_INDEX].fThis = this;
826    fSessions[TTY_DIALIN_INDEX].fInitTerm.c_iflag = 0;
827    fSessions[TTY_DIALIN_INDEX].fInitTerm.c_oflag = 0;
828    fSessions[TTY_DIALIN_INDEX].fInitTerm.c_cflag = TTYDEF_CFLAG;
829    fSessions[TTY_DIALIN_INDEX].fInitTerm.c_lflag = 0;
830    fSessions[TTY_DIALIN_INDEX].fInitTerm.c_ispeed
831	= fSessions[TTY_DIALIN_INDEX].fInitTerm.c_ospeed
832	= (gPESerialBaud == -1)? TTYDEF_SPEED : gPESerialBaud;
833    termioschars(&fSessions[TTY_DIALIN_INDEX].fInitTerm);
834
835    // Now initialise the call out device
836	//
837	// initialize the hotplug flag to zero (bsd hasn't attached so we are safe to unplug)
838
839    fSessions[TTY_CALLOUT_INDEX].fThis = this;
840    fSessions[TTY_CALLOUT_INDEX].fInitTerm
841        = fSessions[TTY_DIALIN_INDEX].fInitTerm;
842
843    do {
844
845		fBaseDev = sBSDGlobals.assign_dev_t();
846        if ((dev_t) -1 == fBaseDev) {
847            break;
848		}
849        if (!createDevNodes()) {
850           break;
851		}
852        if (!setBaseTypeForDev()) {
853           break;
854		}
855        if (!sBSDGlobals.registerTTY(fBaseDev, this)) {
856            break;
857		}
858        // Let userland know that this serial port exists
859        registerService();
860		debug(MULTI," finished");
861		sBSDGlobals.releasefFunnelLock();
862        return true;
863    } while (0);
864    // Failure path
865    debug(MULTI," Cleanup Resources");
866    sBSDGlobals.releasefFunnelLock();
867	cleanupResources();
868    return false;
869}
870
871static inline const char *devName(IORegistryEntry *self)
872{
873    OSString *devNameStr = ((OSString *) self->getProperty(gIOTTYDeviceKey));
874    assert(devNameStr);
875
876    return devNameStr->getCStringNoCopy();
877}
878
879bool IOSerialBSDClient::
880matchPropertyTable(OSDictionary *table)
881{
882    bool matched;
883    OSString *desiredType;
884    OSObject *desiredTypeObj;
885    const OSMetaClass *providerClass;
886    unsigned int desiredLen;
887    const char *desiredName;
888    bool logMatch = (0 != (kIOLogMatch & getDebugFlagsTable(table)));
889
890    if (!super::matchPropertyTable(table)) {
891        IOLogCond(logMatch, "TTY.%s: Failed superclass match\n",
892                             devName(this));
893        return false;	// One of the name based matches has failed, thats it.
894    }
895
896    // Do some name matching
897    matched = compareProperty(table, gIOTTYDeviceKey)
898           && compareProperty(table, gIOTTYBaseNameKey)
899           && compareProperty(table, gIOTTYSuffixKey)
900           && compareProperty(table, gIOCalloutDeviceKey)
901           && compareProperty(table, gIODialinDeviceKey);
902    if (!matched) {
903        IOLogCond(logMatch, "TTY.%s: Failed non type based match\n",
904                             devName(this));
905        return false;	// One of the name based matches has failed, thats it.
906    }
907
908    // The name matching is valid, so if we don't have a type based match
909    // then we have no further matching to do and should return true.
910    desiredTypeObj = table->getObject(gIOSerialBSDTypeKey);
911    if (!desiredTypeObj)
912	return true;
913
914    // At this point we have to check for type based matching.
915    desiredType = OSDynamicCast(OSString, desiredTypeObj);
916    if (!desiredType) {
917        IOLogCond(logMatch, "TTY.%s: %s isn't an OSString?\n",
918                             devName(this),
919                             kIOSerialBSDTypeKey);
920        return false;
921    }
922    desiredLen = desiredType->getLength();
923    desiredName = desiredType->getCStringNoCopy();
924	debug(FLOW, "desiredName is: %s", desiredName);
925
926    // Walk through the provider super class chain looking for an
927    // interface but stop at IOService 'cause that aint a IOSerialStream.
928    for (providerClass = fProvider->getMetaClass();
929
930         providerClass && providerClass != IOService::metaClass;
931         providerClass = providerClass->getSuperClass())
932    {
933        // Check if provider class is prefixed by desiredName
934        // Prefix 'cause IOModemSerialStream & IOModemSerialStreamSync
935        // should both match and if I just look for the prefix they will
936        if (!strncmp(providerClass->getClassName(), desiredName, desiredLen)) {
937			if (fProvider->metaCast("IOBluetoothSerialClientModemStreamSync") || fProvider->metaCast("IOBluetoothSerialClientSerialStreamSync")) {
938				debug(FLOW,"ah hah, bluetooth");
939				fisBlueTooth = true;
940			}
941			return true;
942		}
943    }
944
945
946    // Couldn't find the desired name in the super class chain
947    // so report the failure and return false
948    IOLogCond(logMatch, "TTY.%s: doesn't have a %s interface\n",
949            devName(this),
950            desiredName);
951    return false;
952}
953
954void IOSerialBSDClient::free()
955{
956
957#if JLOG
958		kprintf("IOSerialBSDClient::free\n");
959#endif
960	sBSDGlobals.takefFunnelLock();
961	if ((dev_t) -1 != fBaseDev) {
962	    sBSDGlobals.registerTTY(fBaseDev, 0);
963    }
964
965	Session *sp = &fSessions[TTY_DIALIN_INDEX];
966	if (sp->ftty) {
967		ttyfree(sp->ftty);
968		sp->ftty = NULL;
969		debug(FLOW,"we free'd the ftty struct");
970	}
971
972    // TODO: <rdar://15605565>
973	if (fOpenCloseLock)
974		IOLockFree(fOpenCloseLock);
975
976	if (fIoctlLock)
977		IOLockFree(fIoctlLock);
978
979	if (fDCDThreadCall) {
980		debug(DCDTRD, "DCDThread is freed in free");
981		thread_call_cancel(fDCDThreadCall);
982		thread_call_free(fDCDThreadCall);
983		fDCDThreadCall = 0;
984		fDCDTimerDue = false;
985	}
986	sBSDGlobals.releasefFunnelLock();
987    super::free();
988}
989
990bool IOSerialBSDClient::
991requestTerminate(IOService *provider, IOOptionBits options)
992{
993#if JLOG
994	kprintf("IOSerialBSDClient::requestTerminate\n");
995#endif
996    do {
997		// Don't have anything to do, just a teardown synchronisation
998		// for the isInactive() call.  We can't be made inactive in a
999		// funneled call anymore
1000
1001		// ah, but we're not under the funnel anymore...
1002		// so we'll call out to the termination routine so we can still
1003		// synchronize...
1004
1005		if (super::requestTerminate(provider, options))
1006			return (true);
1007
1008		} while(1);
1009	// can't get here
1010	return(true);
1011}
1012
1013bool IOSerialBSDClient::
1014didTerminate(IOService *provider, IOOptionBits options, bool *defer)
1015{
1016    bool deferTerm;
1017    {
1018#if JLOG
1019		kprintf("IOSerialBSDClient::didTerminate\n");
1020#endif
1021		cleanupResources();
1022
1023        for (int i = 0; i < TTY_NUM_TYPES; i++) {
1024            Session *sp = &fSessions[i];
1025            struct tty *tp = sp->ftty;
1026
1027            // Now kill any stream that may currently be running
1028            sp->fErrno = ENXIO;
1029
1030			if (tp == NULL) // we found a session with no tty configured
1031				continue;
1032#if JLOG
1033			kprintf("IOSerialBSDClient::didTerminate::we still have a session around...\n");
1034#endif
1035            // Enforce a zombie and unconnected state on the discipline
1036			tty_lock(tp);
1037			CLR(tp->t_cflag, CLOCAL);		// Fake up a carrier drop
1038			(void) bsdld_modem(tp, false);
1039			tty_unlock(tp);
1040        }
1041        fActiveSession = 0;
1042        deferTerm =
1043        ((fThreadState & THREAD_RX_MASK) == THREAD_RX_STARTED) ||
1044        ((fThreadState & THREAD_TX_MASK) == THREAD_TX_STARTED) ||
1045        fInOpensPending;
1046        if (deferTerm) {
1047            fKillThreads = true;
1048            fProvider->executeEvent(PD_E_ACTIVE, false);
1049            fDeferTerminate = true;
1050            *defer = true;	// Defer until the threads die
1051        }
1052        else
1053            SAFE_PORTRELEASE(fProvider);
1054
1055    }
1056
1057    return deferTerm || super::didTerminate(provider, options, defer);
1058}
1059
1060IOReturn IOSerialBSDClient::
1061setOneProperty(const OSSymbol *key, OSObject * /* value */)
1062{
1063#if JLOG
1064	kprintf("IOSerialBSDClient::setOneProperty\n");
1065#endif
1066    if (key == gIOTTYWaitForIdleKey) {
1067        int error = waitForIdle();
1068        if (ENXIO == error)
1069            return kIOReturnOffline;
1070        else if (error)
1071            return kIOReturnAborted;
1072        else
1073            return kIOReturnSuccess;
1074    }
1075
1076    return kIOReturnUnsupported;
1077}
1078
1079IOReturn IOSerialBSDClient::
1080setProperties(OSObject *properties)
1081{
1082
1083    IOReturn res = kIOReturnBadArgument;
1084#if JLOG
1085	kprintf("IOSerialBSDClient::setProperties\n");
1086#endif
1087    if (OSDynamicCast(OSString, properties)) {
1088        const OSSymbol *propSym =
1089            OSSymbol::withString((OSString *) properties);
1090        res = setOneProperty(propSym, 0);
1091        propSym->release();
1092    }
1093    else if (OSDynamicCast(OSDictionary, properties)) {
1094        const OSDictionary *dict = (const OSDictionary *) properties;
1095        OSCollectionIterator *keysIter;
1096        const OSSymbol *key;
1097
1098        keysIter = OSCollectionIterator::withCollection(dict);
1099        if (!keysIter) {
1100            res = kIOReturnNoMemory;
1101            goto bail;
1102        }
1103
1104        while ( (key = (const OSSymbol *) keysIter->getNextObject()) ) {
1105            res = setOneProperty(key, dict->getObject(key));
1106            if (res)
1107                break;
1108        }
1109
1110        keysIter->release();
1111    }
1112
1113bail:
1114    return res;		// Successful just return now
1115}
1116
1117// Bracket all open attempts with a reference on ourselves.
1118int IOSerialBSDClient::
1119iossopen(dev_t dev, int flags, int devtype, struct proc *p)
1120{
1121#if JLOG
1122	kprintf("IOSerialBSDClient::iossopen\n");
1123#endif
1124	sBSDGlobals.takefFunnelLock();
1125    IOSerialBSDClient *me = sBSDGlobals.getClient(dev);
1126	sBSDGlobals.releasefFunnelLock();
1127    if (!me || me->isInactive())
1128        return ENXIO;
1129
1130    me->retain();
1131
1132	// protect the open from the close
1133	IOLockLock(me->fOpenCloseLock);
1134
1135    int ret = me->open(dev, flags, devtype, p);
1136
1137	IOLockUnlock(me->fOpenCloseLock);
1138    me->release();
1139
1140    return ret;
1141}
1142
1143int IOSerialBSDClient::
1144iossclose(dev_t dev, int flags, int devtype, struct proc *p)
1145{
1146#if JLOG
1147	kprintf("IOSerialBSDClient::iossclose enter\n");
1148#endif
1149	sBSDGlobals.takefFunnelLock();
1150    IOSerialBSDClient *me = sBSDGlobals.getClient(dev);
1151	sBSDGlobals.releasefFunnelLock();
1152    if (!me)
1153        return ENXIO;
1154
1155    Session *sp = &me->fSessions[IS_TTY_OUTWARD(dev)];
1156    struct tty *tp = sp->ftty;
1157
1158	// protect the close from the open
1159	IOLockLock(me->fOpenCloseLock);
1160
1161    if (!ISSET(tp->t_state, TS_ISOPEN)) {
1162		IOLockUnlock(me->fOpenCloseLock);
1163	    return EBADF;
1164	}
1165
1166    me->close(dev, flags, devtype, p);
1167	IOLockUnlock(me->fOpenCloseLock);
1168	// Remember this is the last close so we may have to delete ourselves
1169	// This reference was held just before we opened the line discipline
1170    // in open().
1171    me->release();
1172#if JLOG
1173	kprintf("IOSerialBSDClient::iossclose exit\n");
1174#endif
1175    return 0;
1176}
1177
1178int IOSerialBSDClient::
1179iossread(dev_t dev, struct uio *uio, int ioflag)
1180{
1181#if JLOG
1182	kprintf("IOSerialBSDClient::iossread\n");
1183#endif
1184	sBSDGlobals.takefFunnelLock();
1185    IOSerialBSDClient *me = sBSDGlobals.getClient(dev);
1186	sBSDGlobals.releasefFunnelLock();
1187    assert(me);
1188    if (!me)
1189        return ENXIO;
1190
1191    int error;
1192
1193    Session *sp = &me->fSessions[IS_TTY_OUTWARD(dev)];
1194    struct tty *tp = sp->ftty;
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    assert(me);
1221    if (!me)
1222        return ENXIO;
1223
1224    int error;
1225
1226#if JLOG
1227	kprintf("IOSerialBSDClient::iosswrite\n");
1228#endif
1229
1230    Session *sp = &me->fSessions[IS_TTY_OUTWARD(dev)];
1231    struct tty *tp = sp->ftty;
1232
1233    error = sp->fErrno;
1234
1235    if (!error) {
1236		tty_lock(tp);
1237        error = bsdld_write(tp, uio, ioflag);
1238		tty_unlock(tp);
1239	}
1240
1241    return error;
1242}
1243
1244int IOSerialBSDClient::
1245iossselect(dev_t dev, int which, void *wql, struct proc *p)
1246{
1247	sBSDGlobals.takefFunnelLock();
1248    IOSerialBSDClient *me = sBSDGlobals.getClient(dev);
1249	sBSDGlobals.releasefFunnelLock();
1250    assert(me);
1251    if (!me)
1252        return ENXIO;
1253
1254    int error;
1255
1256#if JLOG
1257	kprintf("IOSerialBSDClient::iossselect\n");
1258#endif
1259
1260    Session *sp = &me->fSessions[IS_TTY_OUTWARD(dev)];
1261    struct tty *tp = sp->ftty;
1262
1263    error = sp->fErrno;
1264    if (!error) {
1265		tty_lock(tp);
1266        error = ttyselect(tp, which, wql, p);
1267		tty_unlock(tp);
1268	}
1269    return error;
1270}
1271
1272static inline int
1273tiotors232(int bits)
1274{
1275    UInt32 out_b = bits;
1276#if JLOG
1277	kprintf("IOSerialBSDClient::tiotors232\n");
1278#endif
1279    out_b &= ( PD_RS232_S_DTR | PD_RS232_S_RFR | PD_RS232_S_CTS
1280	     | PD_RS232_S_CAR | PD_RS232_S_BRK );
1281    return out_b;
1282}
1283
1284static inline int
1285rs232totio(int bits)
1286{
1287    UInt32 out_b = bits;
1288#if JLOG
1289	kprintf("IOSerialBSDClient::rs232totio\n");
1290#endif
1291
1292    out_b &= ( PD_RS232_S_DTR | PD_RS232_S_DSR
1293             | PD_RS232_S_RFR | PD_RS232_S_CTS
1294             | PD_RS232_S_BRK | PD_RS232_S_CAR  | PD_RS232_S_RNG);
1295    return out_b;
1296}
1297
1298int IOSerialBSDClient::
1299iossioctl(dev_t dev, u_long cmd, caddr_t data, int fflag,				// XXX64
1300                         struct proc *p)
1301{
1302	sBSDGlobals.takefFunnelLock();
1303    IOSerialBSDClient *me = sBSDGlobals.getClient(dev);
1304	sBSDGlobals.releasefFunnelLock();
1305    assert(me);
1306    if (!me)
1307        return ENXIO;
1308
1309    int error = 0;
1310
1311    debug(FLOW, "begin");
1312    IOLockLock(me->fIoctlLock);
1313
1314    Session *sp = &me->fSessions[IS_TTY_OUTWARD(dev)];
1315    struct tty *tp = sp->ftty;
1316
1317    if (sp->fErrno) {
1318		debug(FLOW,"immediate error sp->fErrno: %d", sp->fErrno);
1319        error = sp->fErrno;
1320        goto exitIoctl;
1321    }
1322
1323    /*
1324     * tty line disciplines return >= 0 if they could process this
1325     * ioctl request.  If so, simply return, we're done
1326     */
1327    error = bsdld_ioctl(tp, cmd, data, fflag, p);
1328    if (ENOTTY != error) {
1329		debug(FLOW,"got ENOTTY from BSD land");
1330        me->optimiseInput(&tp->t_termios);
1331        goto exitIoctl;
1332    }
1333
1334    // ...->l_ioctl may block so we need to check our state again
1335    if (sp->fErrno) {
1336		debug(FLOW,"recheck sp->fErrno: %d", sp->fErrno);
1337        error = sp->fErrno;
1338        goto exitIoctl;
1339    }
1340
1341	debug(CONTROL, "cmd: 0x%lx", cmd);
1342
1343    /* First pre-process and validate ioctl command */
1344    switch(cmd)
1345    {
1346    case TIOCGETA_32:
1347    {
1348        debug(CONTROL,"TIOCGETA_32");
1349#ifdef __LP64__
1350        termios64to32((struct user_termios *)&tp->t_termios, (struct termios32 *)data);
1351#else
1352        bcopy(&tp->t_termios, data, sizeof(struct termios));
1353#endif
1354        me->convertFlowCtrl(sp, (struct termios *) data);
1355        error = 0;
1356        goto exitIoctl;
1357    }
1358    case TIOCGETA_64:
1359    {
1360        debug(CONTROL,"TIOCGETA_64");
1361#ifdef __LP64__
1362		bcopy(&tp->t_termios, data, sizeof(struct termios));
1363#else
1364		termios32to64((struct termios32 *)&tp->t_termios, (struct user_termios *)data);
1365#endif
1366        me->convertFlowCtrl(sp, (struct termios *) data);
1367        error = 0;
1368        goto exitIoctl;
1369    }
1370    case TIOCSETA_32:
1371    case TIOCSETAW_32:
1372    case TIOCSETAF_32:
1373    case TIOCSETA_64:
1374    case TIOCSETAW_64:
1375    case TIOCSETAF_64:
1376    {
1377		debug(CONTROL,"TIOCSETA_32/64/TIOCSETAW_32/64/TIOCSETAF_32/64");
1378		struct termios *dt = (struct termios *)data;
1379		struct termios lcl_termios;
1380
1381#ifdef __LP64__
1382        if (cmd==TIOCSETA_32 || cmd==TIOCSETAW_32 || cmd==TIOCSETAF_32) {
1383            termios32to64((struct termios32 *)data, (struct user_termios *)&lcl_termios);
1384            dt = &lcl_termios;
1385        }
1386#else
1387        if (cmd==TIOCSETA_64 || cmd==TIOCSETAW_64 || cmd==TIOCSETAF_64) {
1388            termios64to32((struct user_termios *)data, (struct termios32 *)&lcl_termios);
1389            dt = &lcl_termios;
1390        }
1391#endif
1392
1393        /* Convert the PortSessionSync's flow control setting to termios */
1394		tty_lock(tp);
1395        me->convertFlowCtrl(sp, &tp->t_termios);
1396		tty_unlock(tp);
1397        /*
1398         * Check to see if we are trying to disable either the start or
1399         * stop character at the same time as using the XON/XOFF character
1400         * based flow control system.  This is not implemented in the
1401         * current PortDevices protocol.
1402         */
1403        if (ISSET(dt->c_cflag, CIGNORE)
1404        &&  ISSET(tp->t_iflag, (IXON|IXOFF))
1405        && ( dt->c_cc[VSTART] == _POSIX_VDISABLE
1406                || dt->c_cc[VSTOP]  == _POSIX_VDISABLE ) )
1407        {
1408            error = EINVAL;
1409            goto exitIoctl;
1410        }
1411        break;
1412    }
1413
1414    case TIOCEXCL:
1415		debug(CONTROL,"TIOCEXCL");
1416        // Force the TIOCEXCL ioctl to be atomic!
1417        if (ISSET(tp->t_state, TS_XCLUDE)) {
1418            error = EBUSY;
1419            goto exitIoctl;
1420        }
1421        break;
1422
1423    default:
1424        break;
1425    }
1426
1427    /* See if generic tty understands this. */
1428    if ( (error = ttioctl(tp, cmd, data, fflag, p)) != ENOTTY) {
1429		debug(CONTROL,"generic tty handled this");
1430        if (error) {
1431            iossparam(tp, &tp->t_termios);	/* reestablish old state */
1432		}
1433        me->optimiseInput(&tp->t_termios);
1434	goto exitIoctl;
1435    }
1436
1437    // ttioctl may block so we need to check our state again
1438    if (sp->fErrno) {
1439		debug(FLOW,"2nd recheck sp->fErrno: %d", sp->fErrno);
1440        error = sp->fErrno;
1441        goto exitIoctl;
1442    }
1443
1444    //
1445    // The generic ioctl handlers don't know what is going on
1446    // so try to interpret them here.
1447    //
1448    error = 0;
1449    switch (cmd)
1450    {
1451    case TIOCSBRK:
1452		debug(CONTROL,"TIOCSBRK");
1453        (void) me->mctl(PD_RS232_S_BRK, DMBIS);  break;
1454
1455	case TIOCCBRK:
1456		debug(CONTROL,"TIOCCBRK");
1457        (void) me->mctl(PD_RS232_S_BRK, DMBIC);  break;
1458
1459    case TIOCSDTR:
1460		debug(CONTROL,"TIOCSDTR");
1461        (void) me->mctl(PD_RS232_S_DTR, DMBIS);  break;
1462
1463    case TIOCCDTR:
1464		debug(CONTROL,"TIOCCDTR");
1465        (void) me->mctl(PD_RS232_S_DTR, DMBIC);  break;
1466
1467    case TIOCMSET:
1468		debug(CONTROL,"TIOCMSET");
1469        (void) me->mctl(tiotors232(*(int *)data), DMSET);  break;
1470
1471    case TIOCMBIS:
1472		debug(CONTROL,"TIOCMBIS");
1473        (void) me->mctl(tiotors232(*(int *)data), DMBIS);  break;
1474
1475    case TIOCMBIC:
1476		debug(CONTROL,"TIOCMBIC");
1477        (void) me->mctl(tiotors232(*(int *)data), DMBIC);  break;
1478
1479    case TIOCMGET:
1480		debug(CONTROL,"TIOCMGET");
1481        *(int *)data = rs232totio(me->mctl(0,     DMGET)); break;
1482
1483    case IOSSDATALAT_32:
1484    case IOSSDATALAT_64:
1485        // all users currently assume this data is a UInt32
1486		debug(CONTROL,"IOSSDATALAT");
1487        (void) me->sessionExecuteEvent(sp, PD_E_DATA_LATENCY, *(UInt32 *) data);
1488        break;
1489
1490    case IOSSPREEMPT:
1491		debug(CONTROL,"IOSSPREEMPT");
1492        me->fPreemptAllowed = (bool) (*(int *) data);
1493        if (me->fPreemptAllowed) {
1494            me->fLastUsedTime = kNever;
1495            // initialize fPreemptInProgress in case we manage to
1496            // call the Preemption ioctl before it is initialized elsewhere
1497            //me->fPreemptInProgress = false;
1498        }
1499        else
1500            wakeup(&me->fPreemptAllowed);	// Wakeup any pre-empters
1501        break;
1502
1503    case IOSSIOSPEED_32:
1504    case IOSSIOSPEED_64:
1505    {
1506		debug(CONTROL,"IOSSIOSPEED_32/64");
1507		speed_t speed = *(speed_t *) data;
1508
1509		// Remember that the speed is in half bits
1510		IOReturn rtn = me->sessionExecuteEvent(sp, PD_E_DATA_RATE, speed << 1);
1511		debug(CONTROL, "IOSSIOSPEED_32 session execute return: 0x%x", rtn);
1512		if (kIOReturnSuccess != rtn) {
1513			error = (kIOReturnBadArgument == rtn)? EINVAL : EDEVERR;
1514			break;
1515		}
1516		tty_lock(tp);
1517		tp->t_ispeed = tp->t_ospeed = speed;
1518		ttsetwater(tp);
1519		tty_unlock(tp);
1520		break;
1521    }
1522
1523    default: debug(CONTROL,"Unhandled ioctl"); error = ENOTTY; break;
1524    }
1525
1526exitIoctl:
1527    /*
1528     * These flags functionality has been totally subsumed by the PortDevice
1529     * driver so make sure they always get cleared down before any serious
1530     * work is done.
1531     */
1532	debug(FLOW, "exiting");
1533	tty_lock(tp);
1534    CLR(tp->t_iflag, IXON | IXOFF | IXANY);
1535    CLR(tp->t_cflag, CRTS_IFLOW | CCTS_OFLOW);
1536	tty_unlock(tp);
1537	IOLockUnlock(me->fIoctlLock);
1538    return error;
1539}
1540
1541
1542void IOSerialBSDClient::
1543iossstart(struct tty *tp)
1544{
1545	Session *sp = (Session *)tp->t_iokit;
1546    IOSerialBSDClient *me = sp->fThis;
1547    IOReturn rtn;
1548
1549#if JLOG
1550	kprintf("IOSerialBSDClient::iossstart\n");
1551#endif
1552
1553    assert(me);
1554
1555    if (sp->fErrno)
1556	return;
1557
1558    if ( !me->fIstxEnabled && !ISSET(tp->t_state, TS_TTSTOP) ) {
1559        me->fIstxEnabled = true;
1560#if JLOG
1561		kprintf("iossstart calls sessionSetState to enable PD_S_TX_ENABLE\n");
1562#endif
1563        me->sessionSetState(sp, -1U, PD_S_TX_ENABLE);
1564    }
1565
1566    if  (tp->t_outq.c_cc) {
1567        // Notify the transmit thread of action to be performed
1568#if JLOG
1569		kprintf("iossstart calls sessionSetState to do the PD_S_TX_EVENT\n");
1570#endif
1571		rtn = me->sessionSetState(sp, PD_S_TX_EVENT, PD_S_TX_EVENT);
1572		assert(!rtn || rtn == kIOReturnOffline || rtn == kIOReturnNotOpen);
1573    }
1574}
1575
1576int IOSerialBSDClient::
1577iossstop(struct tty *tp, int rw)
1578{
1579
1580    Session *sp = (Session *) tp->t_iokit;
1581    IOSerialBSDClient *me = sp->fThis;
1582#if JLOG
1583	kprintf("IOSerialBSDClient::iossstop\n");
1584#endif
1585
1586    assert(me);
1587    if (sp->fErrno)
1588	return 0;
1589
1590    if ( ISSET(tp->t_state, TS_TTSTOP) ) {
1591		me->fIstxEnabled = false;
1592#if JLOG
1593		kprintf("iossstop calls sessionSetState to disable PD_S_TX_EVENT\n");
1594#endif
1595		me->sessionSetState(sp, 0, PD_S_TX_ENABLE);
1596    }
1597
1598    if ( ISSET(rw, FWRITE) ) {
1599#if JLOG
1600		kprintf("iossstop calls sessionExecuteEvent to PD_E_TXQ_FLUSH\n");
1601#endif
1602        me->sessionExecuteEvent(sp, PD_E_TXQ_FLUSH, 0);
1603	}
1604    if ( ISSET(rw, FREAD) ) {
1605#if JLOG
1606		kprintf("iossstop calls sessionExecuteEvent to PD_E_RXQ_FLUSH\n");
1607#endif
1608        me->sessionExecuteEvent(sp, PD_E_RXQ_FLUSH, 0);
1609        if (me->frxBlocked)	{ // wake up a blocked reader
1610#if JLOG
1611			kprintf("iossstop calls sessionSetState to wake PD_S_RX_ENABLE\n");
1612#endif
1613            me->sessionSetState(sp, PD_S_RX_ENABLE, PD_S_RX_ENABLE);
1614		}
1615    }
1616    return 0;
1617}
1618
1619/*
1620 * Parameter control functions
1621 *
1622 */
1623int IOSerialBSDClient::
1624iossparam(struct tty *tp, struct termios *t)
1625{
1626
1627    Session *sp = (Session *) tp->t_iokit;
1628    IOSerialBSDClient *me = sp->fThis;
1629    u_long data;
1630    int cflag, error;
1631    IOReturn rtn = kIOReturnOffline;
1632#if JLOG
1633	kprintf("IOSerialBSDClient::iossparam\n");
1634#endif
1635
1636    assert(me);
1637
1638    if (sp->fErrno)
1639	goto exitParam;
1640
1641    rtn = kIOReturnBadArgument;
1642    if (ISSET(t->c_iflag, (IXOFF|IXON))
1643    && (t->c_cc[VSTART]==_POSIX_VDISABLE || t->c_cc[VSTOP]==_POSIX_VDISABLE))
1644        goto exitParam;
1645
1646    /* do historical conversions */
1647    if (t->c_ispeed == 0) {
1648        t->c_ispeed = t->c_ospeed;
1649	}
1650
1651    /* First check to see if the requested speed is one of our valid ones */
1652    data = ttspeedtab(t->c_ospeed, iossspeeds);
1653
1654    if ((int) data != -1 && t->c_ispeed == t->c_ospeed) {
1655#if JLOG
1656		kprintf("IOSerialBSDClient::iossparam::sessionExecuteEvent::PD_E_DATA_RATE, %d\n", (int)data);
1657#endif
1658
1659	rtn  = me->sessionExecuteEvent(sp, PD_E_DATA_RATE, data);
1660	}
1661    else if ( (IOSS_HALFBIT_BRD & t->c_ospeed) ) {
1662	/*
1663	 * MIDI clock speed multipliers are used for externally clocked MIDI
1664	 * devices, and are evident by a 1 in the low bit of c_ospeed/c_ispeed
1665	 */
1666	data = (u_long) t->c_ospeed >> 1;	// set data to MIDI clock mode
1667#if JLOG
1668		kprintf("IOSerialBSDClient::iossparam::sessionExecuteEvent::PD_E_EXTERNAL_CLOCK_MODE, %d\n", (int)data);
1669#endif
1670
1671	rtn  = me->sessionExecuteEvent(sp, PD_E_EXTERNAL_CLOCK_MODE, data);
1672    }
1673    if (rtn)
1674        goto exitParam;
1675
1676    /*
1677     * Setup SCC as for data and character len
1678     * Note: ttycharmask is anded with both transmitted and received
1679     * characters.
1680     */
1681    cflag = t->c_cflag;
1682    switch (cflag & CSIZE) {
1683    case CS5:       data = 5 << 1; break;
1684    case CS6:	    data = 6 << 1; break;
1685    case CS7:	    data = 7 << 1; break;
1686    default:	    /* default to 8bit setup */
1687    case CS8:	    data = 8 << 1; break;
1688    }
1689#if JLOG
1690	kprintf("IOSerialBSDClient::iossparam::sessionExecuteEvent::PD_E_DATA_SIZE, %d\n", (int)data);
1691#endif
1692
1693    rtn  = me->sessionExecuteEvent(sp, PD_E_DATA_SIZE, data);
1694    if (rtn)
1695        goto exitParam;
1696
1697
1698    data = PD_RS232_PARITY_NONE;
1699    if ( ISSET(cflag, PARENB) ) {
1700        if ( ISSET(cflag, PARODD) )
1701            data = PD_RS232_PARITY_ODD;
1702        else
1703            data = PD_RS232_PARITY_EVEN;
1704    }
1705#if JLOG
1706	kprintf("IOSerialBSDClient::iossparam::sessionExecuteEvent::PD_E_DATA_INTEGRITY, %d\n", (int)data);
1707#endif
1708
1709    rtn = me->sessionExecuteEvent(sp, PD_E_DATA_INTEGRITY, data);
1710    if (rtn)
1711        goto exitParam;
1712
1713    /* Set stop bits to 2 1/2 bits in length */
1714    if (ISSET(cflag, CSTOPB))
1715        data = 4;
1716    else
1717        data = 2;
1718#if JLOG
1719	kprintf("IOSerialBSDClient::iossparam::sessionExecuteEvent::PD_RS232_E_STOP_BITS, %d\n", (int)data);
1720#endif
1721
1722    rtn = me->sessionExecuteEvent(sp, PD_RS232_E_STOP_BITS, data);
1723    if (rtn)
1724        goto exitParam;
1725
1726    //
1727    // Reset the Flow Control values
1728    //
1729    data = 0;
1730    if ( ISSET(t->c_iflag, IXON) )
1731        SET(data, PD_RS232_A_TXO);
1732    if ( ISSET(t->c_iflag, IXANY) )
1733        SET(data, PD_RS232_A_XANY);
1734    if ( ISSET(t->c_iflag, IXOFF) )
1735        SET(data, PD_RS232_A_RXO);
1736
1737    if ( ISSET(cflag, CRTS_IFLOW) )
1738        SET(data, PD_RS232_A_RFR);
1739    if ( ISSET(cflag, CCTS_OFLOW) )
1740        SET(data, PD_RS232_A_CTS);
1741    if ( ISSET(cflag, CDTR_IFLOW) )
1742        SET(data, PD_RS232_A_DTR);
1743    CLR(t->c_iflag, IXON | IXOFF | IXANY);
1744    CLR(t->c_cflag, CRTS_IFLOW | CCTS_OFLOW);
1745#if JLOG
1746	kprintf("IOSerialBSDClient::iossparam::sessionExecuteEvent::PD_E_FLOW_CONTROL, %d\n", (int)data);
1747#endif
1748
1749    rtn = me->sessionExecuteEvent(sp, PD_E_FLOW_CONTROL, data);
1750    if (rtn)
1751        goto exitParam;
1752
1753    //
1754    // Load the flow control start and stop characters.
1755    //
1756#if JLOG
1757	kprintf("IOSerialBSDClient::iossparam::sessionExecuteEvent::PD_RS232_E_XON_BYTE, t->c_cc[VSTART]\n");
1758#endif
1759    rtn  = me->sessionExecuteEvent(sp, PD_RS232_E_XON_BYTE,  t->c_cc[VSTART]);
1760#if JLOG
1761	kprintf("IOSerialBSDClient::iossparam::sessionExecuteEvent::PD_RS232_E_XOFF_BYTE, t->c_cc[VSTOP]\n");
1762#endif
1763    rtn |= me->sessionExecuteEvent(sp, PD_RS232_E_XOFF_BYTE, t->c_cc[VSTOP]);
1764    if (rtn)
1765        goto exitParam;
1766
1767    /* Always enable for transmission */
1768    me->fIstxEnabled = true;
1769#if JLOG
1770	kprintf("IOSerialBSDClient::iossparam::sessionSetState::PD_S_TX_ENABLE, PD_S_TX_ENABLE\n");
1771#endif
1772    rtn = me->sessionSetState(sp, PD_S_TX_ENABLE, PD_S_TX_ENABLE);
1773    if (rtn)
1774        goto exitParam;
1775
1776    /* Only enable reception if necessary */
1777    if ( ISSET(cflag, CREAD) ) {
1778#if JLOG
1779		kprintf("IOSerialBSDClient::iossparam::sessionSetState::-1U, PD_S_RX_ENABLE\n");
1780#endif
1781        rtn = me->sessionSetState(sp, -1U, PD_S_RX_ENABLE);
1782	}
1783    else {
1784#if JLOG
1785		kprintf("IOSerialBSDClient::iossparam::sessionSetState::0U, PD_S_RX_ENABLE\n");
1786#endif
1787        rtn = me->sessionSetState(sp,  0U, PD_S_RX_ENABLE);
1788	}
1789
1790exitParam:
1791    if (kIOReturnSuccess == rtn)
1792        error = 0;
1793    else if (kIOReturnOffline == rtn)
1794        error = sp->fErrno;
1795    else
1796        error = EINVAL;
1797
1798    return error;
1799}
1800
1801
1802/*
1803 * Decision Tables for open semantic
1804 *
1805 * The Exact semantic to be used when open serial ports is very complicated.
1806 * We have nasty combinations of ports opened exclusively but pre-emptible while
1807 * a root user tries to open the port.  Anyway all of the states that are
1808 * interesting are listed below with pseudo code that implements the tables.
1809 *
1810 * The states across the top are for desired state.  Vertical for the current
1811 * open port's state, with State prefix:- ' ' true, '!' not true, 'x' dont care
1812 *
1813 *  Results
1814 * 	B => Block   E => Error Busy   S => Success   P => Pre-empt
1815 *
1816 * OPEN port was open and is not waiting for carrier
1817 * EXCL port is open and desires exclusivity
1818 * PREM port is open and is pre-emptible
1819 *
1820 * Callout Decision table
1821 *
1822 *         CALLOUT | 0 | 0 | 1 | 1 | 1 | 1 |
1823 *        NONBLOCK | 0 | 1 | 0 | 0 | 1 | 1 |
1824 *            ROOT | x | x | 0 | 1 | 0 | 1 |
1825 * -----------------------------------------
1826 *      !EXCL      | Bi| E | S | S | S | S |
1827 *       EXCL      | Bi| E | E | S | E | S |
1828 *
1829 * Is Callout Open
1830 *     if (wantCallout) {
1831 *         if (isExclusive && !wantSuser)
1832 *             return BUSY;
1833 *         else
1834 *             ; // Success;
1835 *     }
1836 *     else {
1837 * checkAndWaitForIdle:
1838 *         if (wantNonBlock)
1839 *             return BUSY;
1840 *         else {
1841 *             waitForIdle;
1842 *             goto checkBusy;
1843 *         }
1844 *     }
1845 *
1846 * Dial out Table
1847 *
1848 *         CALLOUT | 0 | 0 | 1 | 1 | 1 | 1 |
1849 *        NONBLOCK | 0 | 1 | 0 | 0 | 1 | 1 |
1850 *            ROOT | x | x | 0 | 1 | 0 | 1 |
1851 * ----------------------------------------
1852 * !OPENxEXCLxPREM | S | S | P | P | P | P |
1853 *  OPEN!EXCL!PREM | S | S | Bi| S | E | S |
1854 *  OPEN!EXCL PREM | S | S | P | P | P | P |
1855 *  OPEN EXCL!PREM | E | E | Bi| S | E | S |
1856 *  OPEN EXCL PREM | E | E | P | P | P | P |
1857 *
1858 * Is Dialout Waiting for carrier
1859 *     if (wantCallout)
1860 *         preempt;
1861 *     else
1862 *         // Success Wait for carrier later on
1863 *
1864 * Is Dialout open
1865 *     if (wantCallout) {
1866 *         if (isPreempt)
1867 *             preempt;
1868 *         else if (!wantSuser)
1869 *             goto checkAndWaitForIdle;
1870 *         else
1871 *         	; // Success
1872 *     }
1873 *     else {
1874 *         if (isExclusive)
1875 *             return BUSY;
1876 *         else
1877 *         	; // Success
1878 *     }
1879 *
1880 */
1881
1882int IOSerialBSDClient::
1883open(dev_t dev, int flags, int /* devtype */, struct proc * /* p */)
1884{
1885    Session *sp;
1886    struct tty *tp;
1887    int error = 0;
1888    bool wantNonBlock = flags & O_NONBLOCK;
1889    bool imPreempting = false;
1890    bool firstOpen = false;
1891    // fPreemptInProgress is false at the beginning of every open
1892    // as Preemption can only occur later in the open process
1893    //fPreemptInProgress = false;
1894
1895#if JLOG
1896	kprintf("IOSerialBSDClient::open\n");
1897#endif
1898
1899checkBusy:
1900    if (isInactive()) {
1901        error = ENXIO;
1902        goto exitOpen;
1903    }
1904
1905    // Check to see if the currently active device has been pre-empted.
1906    // If the device has been preempted then we have to wait for the
1907    // current owner to close the port.  And THAT means we have to return
1908    // from this open otherwise UNIX doesn't deign to inform us when the
1909    // other process DOES close the port.  Welcome to UNIX being helpful.
1910    sp = &fSessions[IS_TTY_OUTWARD(dev)];
1911	if (sp->ftty == NULL) {
1912#if JLOG
1913		kprintf("IOSerialBSDClient::open::ttymalloc'd\n");
1914#endif
1915		sp->ftty = ttymalloc();
1916		sp->ftty->t_iokit = sp;
1917	}
1918    if (sp->fErrno == EBUSY) {
1919        error = EBUSY;
1920        goto exitOpen;
1921    }
1922
1923    // Can't call startConnectTransit as we need to make sure that
1924    // the device hasn't been hot unplugged while we were waiting.
1925    if (!imPreempting && fConnectTransit) {
1926        tsleep((caddr_t) this, TTIPRI, "ttyopn", 0);
1927        goto checkBusy;
1928    }
1929    fConnectTransit = true;
1930
1931    // Check to see if the device is already open, which means we have an
1932    // active session
1933    if (fActiveSession) {
1934        tp = fActiveSession->ftty;
1935
1936        bool isCallout    = IS_TTY_OUTWARD(tp->t_dev);
1937		fisCallout = isCallout;
1938        bool isPreempt    = fPreemptAllowed;
1939        bool isExclusive  = ISSET(tp->t_state, TS_XCLUDE);
1940        bool isOpen       = ISSET(tp->t_state, TS_ISOPEN);
1941        bool wantCallout  = IS_TTY_OUTWARD(dev);
1942		fwantCallout = wantCallout;
1943        // kauth_cred_issuser returns opposite of suser used in Leopard
1944        bool wantSuser    = kauth_cred_issuser(kauth_cred_get());
1945
1946        if (isCallout) {
1947            // Is Callout and must be open
1948            if (wantCallout) {
1949                if (isExclusive && !wantSuser) {
1950                    //
1951                    // @@@ - UNIX doesn't allow us to block the open
1952                    // until the current session idles if they have the
1953                    // same dev_t.  The opens are reference counted
1954                    // this means that I must return an error and tell
1955                    // the users to use IOKit.
1956                    //
1957                    error = EBUSY;
1958                    goto exitOpen;
1959                }
1960//                else
1961//                    ; // Success - use current session
1962            }
1963            else {
1964checkAndWaitForIdle:
1965                if (wantNonBlock) {
1966                    error = EBUSY;
1967                    goto exitOpen;
1968                } else {
1969                    endConnectTransit();
1970                    error = waitForIdle();
1971                    if (error)
1972                        return error;	// No transition to clean up
1973                    goto checkBusy;
1974                }
1975            }
1976        }
1977        else if (isOpen) {
1978            // Is dial in and open
1979            if (wantCallout) {
1980                if (isPreempt) {
1981                    imPreempting = true;
1982                    preemptActive();
1983                    goto checkBusy;
1984                }
1985                else if (!wantSuser)
1986                    goto checkAndWaitForIdle;
1987//                else
1988//                    ; // Success - use current session (root override)
1989            }
1990            else {
1991                // Want dial in connection
1992                if (isExclusive) {
1993                    //
1994                    // @@@ - UNIX doesn't allow us to block the open
1995                    // until the current session idles if they have the
1996                    // same dev_t.  The opens are reference counted
1997                    // this means that I must return an error and tell
1998                    // the users to use IOKit.
1999                    //
2000                    error = EBUSY;
2001                    goto exitOpen;
2002                }
2003//                else
2004//                    ; // Success - use current session
2005            }
2006        }
2007        else {
2008            // Is dial in and blocking for carrier, i.e. not open
2009            if (wantCallout) {
2010                imPreempting = true;
2011                preemptActive();
2012                goto checkBusy;
2013            }
2014//            else
2015//                ; // Successful, will wait for carrier later
2016        }
2017    }
2018
2019    // If we are here then we have successfully run the open gauntlet.
2020    tp = sp->ftty;
2021
2022    // If there is no active session that means that we have to acquire
2023    // the serial port.
2024    if (!fActiveSession) {
2025        IOReturn rtn = fProvider->acquirePort(/* sleep */ false);
2026	fAcquired = (kIOReturnSuccess == rtn);
2027
2028	// Check for a unplug while we blocked acquiring the port
2029	if (isInactive()) {
2030	    SAFE_PORTRELEASE(fProvider);
2031	    error = ENXIO;
2032	    goto exitOpen;
2033	}
2034	else if (kIOReturnSuccess != rtn) {
2035            error = EBUSY;
2036            goto exitOpen;
2037        }
2038
2039	// We acquired the port successfully
2040	fActiveSession = sp;
2041    }
2042
2043    /*
2044     * Initialize Unix's tty struct,
2045     * set device parameters and RS232 state
2046     */
2047    if ( !ISSET(tp->t_state, TS_ISOPEN) ) {
2048        initSession(sp);
2049        // racey, racey - and initSession doesn't return/set anything useful
2050        if (!fActiveSession || isInactive()) {
2051            SAFE_PORTRELEASE(fProvider);
2052            error = ENXIO;
2053            goto exitOpen;
2054        }
2055
2056        // Initialise the line state
2057        iossparam(tp, &tp->t_termios);
2058    }
2059
2060    /*
2061     * Handle DCD:
2062     * If outgoing or not hw dcd or dcd is asserted, then continue.
2063     * Otherwise, block till dcd is asserted or open fPreempt.
2064     */
2065    if (IS_TTY_OUTWARD(dev)
2066    ||  ISSET(sessionGetState(sp), PD_RS232_S_CAR) ) {
2067		tty_lock(tp);
2068        bsdld_modem(tp, true);
2069		tty_unlock(tp);
2070    }
2071
2072    if (!IS_TTY_OUTWARD(dev) && !ISSET(flags, FNONBLOCK)
2073    &&  !ISSET(tp->t_state, TS_CARR_ON) && !ISSET(tp->t_cflag, CLOCAL)) {
2074
2075        // Drop transit while we wait for the carrier
2076        fInOpensPending++;	// Note we are sleeping
2077        endConnectTransit();
2078
2079        /* Track DCD Transistion to high */
2080        UInt32 pd_state = PD_RS232_S_CAR;
2081        IOReturn rtn = sessionWatchState(sp, &pd_state, PD_RS232_S_CAR);
2082
2083	// Rely on the funnel for atomicicity
2084	int wasPreempted = (EBUSY == sp->fErrno);
2085        fInOpensPending--;
2086	if (!fInOpensPending)
2087	    wakeup(&fInOpensPending);
2088
2089        startConnectTransit(); 	// Sync with the pre-emptor here
2090	if (wasPreempted)	{
2091	    endConnectTransit();
2092	    goto checkBusy;	// Try again
2093	}
2094	else if (kIOReturnSuccess != rtn) {
2095
2096	    // We were probably interrupted
2097	    if (!fInOpensPending) {
2098		// clean up if we are the last opener
2099		SAFE_PORTRELEASE(fProvider);
2100                fActiveSession = 0;
2101
2102		if (fDeferTerminate && isInactive()) {
2103		    bool defer = false;
2104		    super::didTerminate(fProvider, 0, &defer);
2105		}
2106            }
2107
2108            // End the connect transit lock and return the error
2109            endConnectTransit();
2110	    if (isInactive())
2111		return ENXIO;
2112	    else switch (rtn) {
2113	    case kIOReturnAborted:
2114	    case kIOReturnIPCError:	return EINTR;
2115
2116	    case kIOReturnNotOpen:
2117	    case kIOReturnIOError:
2118	    case kIOReturnOffline:	return ENXIO;
2119
2120	    default:
2121					return EIO;
2122	    }
2123	}
2124
2125		// To be here we must be transiting and have DCD
2126		tty_lock(tp);
2127		bsdld_modem(tp, true);
2128		tty_unlock(tp);
2129
2130    }
2131
2132    tty_lock(tp);
2133    if ( !ISSET(tp->t_state, TS_ISOPEN) ) {
2134        firstOpen = true;
2135    }
2136    error = bsdld_open(dev, tp);    // sets TS_ISOPEN
2137    if (error) {
2138	tty_unlock(tp);
2139    } else {
2140	tty_unlock(tp);
2141	if (firstOpen) {
2142	    retain();	// Hold a reference until the port is closed
2143		// because we can still get caught up if we get yanked late
2144		if (!fActiveSession || isInactive()) {
2145			SAFE_PORTRELEASE(fProvider);
2146            error = ENXIO;
2147            goto exitOpen;
2148		}
2149            launchThreads(); // launch the transmit and receive threads
2150		// and we got caught in launchThreads once
2151		if (!fActiveSession || isInactive()) {
2152			SAFE_PORTRELEASE(fProvider);
2153            error = ENXIO;
2154            goto exitOpen;
2155		}
2156	}
2157    }
2158
2159exitOpen:
2160    endConnectTransit();
2161
2162    return error;
2163}
2164
2165void IOSerialBSDClient::
2166close(dev_t dev, int flags, int /* devtype */, struct proc * /* p */)
2167{
2168    struct tty *tp;
2169    Session *sp;
2170    IOReturn rtn;
2171#if JLOG
2172	kprintf("IOSerialBSDClient::close\n");
2173#endif
2174
2175    startConnectTransit();
2176
2177    sp = &fSessions[IS_TTY_OUTWARD(dev)];
2178    tp = sp->ftty;
2179
2180    if (!tp->t_dev && fInOpensPending) {
2181        // Never really opened - time to give up on this device
2182        (void) fProvider->executeEvent(PD_E_ACTIVE, false);
2183        endConnectTransit();
2184        while (fInOpensPending)
2185            tsleep((caddr_t) &fInOpensPending, TTIPRI, "ttyrev", 0);
2186		retain();	// Hold a reference for iossclose to release()
2187        return;
2188    }
2189    /* We are closing, it doesn't matter now about holding back ... */
2190	tty_lock(tp);
2191    CLR(tp->t_state, TS_TTSTOP);
2192	tty_unlock(tp);
2193
2194    if (!sp->fErrno) {
2195        (void) sessionExecuteEvent(sp, PD_E_FLOW_CONTROL, 0);
2196        (void) sessionSetState(sp, -1U, PD_S_RX_ENABLE | PD_S_TX_ENABLE);
2197
2198        // Clear any outstanding line breaks
2199        rtn = sessionEnqueueEvent(sp, PD_RS232_E_LINE_BREAK, false, true);
2200        assert(!rtn || rtn == kIOReturnOffline || rtn == kIOReturnNotOpen);
2201    }
2202	tty_lock(tp);
2203    bsdld_close(tp, flags);
2204	tty_unlock(tp);
2205    if (!sp->fErrno) {
2206        if (ISSET(tp->t_cflag, HUPCL) || !ISSET(tp->t_state, TS_ISOPEN)
2207            || (IS_TTY_PREEMPT(dev, sp->fInitTerm.c_cflag)
2208                && !ISSET(sessionGetState(sp), PD_RS232_S_CAR)) ) {
2209                /*
2210                 * XXX we will miss any carrier drop between here and the
2211                 * next open.  Perhaps we should watch DCD even when the
2212                 * port is closed; it is not sufficient to check it at
2213                 * the next open because it might go up and down while
2214                 * we're not watching.
2215                 */
2216                (void) mctl(RS232_S_OFF, DMSET);
2217            }
2218    }
2219	tty_lock(tp);
2220    ttyclose(tp);	// Drops TS_ISOPEN flag
2221    assert(!tp->t_outq.c_cc);
2222
2223    tty_unlock(tp);
2224    // Shut down the port, this will cause the RX && TX threads to terminate
2225    // Then wait for threads to terminate, this should be over very quickly.
2226
2227
2228    if (!sp->fErrno)
2229        killThreads(); // Disable the chip
2230
2231    if (sp == fActiveSession)
2232    {
2233        SAFE_PORTRELEASE(fProvider);
2234        fPreemptAllowed = false;
2235        fActiveSession = 0;
2236        wakeup(&fPreemptAllowed);	// Wakeup any pre-empters
2237    }
2238
2239    sp->fErrno = 0;	/* Clear the error condition on last close */
2240
2241    endConnectTransit();
2242}
2243/*
2244 * no lock is assumed
2245 */
2246void IOSerialBSDClient::
2247initSession(Session *sp)
2248{
2249    struct tty *tp = sp->ftty;
2250    IOReturn rtn;
2251
2252#if JLOG
2253	kprintf("IOSerialBSDClient::initSession\n");
2254#endif
2255
2256	tty_lock(tp);
2257    tp->t_oproc = iossstart;
2258    tp->t_param = iossparam;
2259    tp->t_termios = sp->fInitTerm;
2260    ttsetwater(tp);
2261	tty_unlock(tp);
2262    /* Activate the session's port */
2263#if JLOG
2264	kprintf("IOSerialBSDClient::initSession::sessionExecuteEvent::PD_E_ACTIVE\n");
2265#endif
2266
2267    rtn = sessionExecuteEvent(sp, PD_E_ACTIVE, true);
2268    if (rtn)
2269        IOLog("ttyioss%04x: ACTIVE failed (%x)\n", tp->t_dev, rtn);
2270#if JLOG
2271	kprintf("IOSerialBSDClient::initSession::sessionExecuteEvent::PD_E_TXQ_FLUSH, 0\n");
2272#endif
2273
2274    rtn  = sessionExecuteEvent(sp, PD_E_TXQ_FLUSH, 0);
2275#if JLOG
2276	kprintf("IOSerialBSDClient::initSession::sessionExecuteEvent::PD_E_RXQ_FLUSH, 0\n");
2277#endif
2278
2279    rtn |= sessionExecuteEvent(sp, PD_E_RXQ_FLUSH, 0);
2280    assert(!rtn || rtn == kIOReturnOffline || rtn == kIOReturnNotOpen);
2281
2282	tty_lock(tp);
2283    CLR(tp->t_state, TS_CARR_ON | TS_BUSY);
2284	tty_unlock(tp);
2285
2286    fKillThreads = false;
2287
2288	if (!fDCDThreadCall) {
2289		debug(DCDTRD, "DCDThread is allocated");
2290		fDCDThreadCall =
2291			thread_call_allocate(&IOSerialBSDClient::iossdcddelay, this);
2292	}
2293    // racey again
2294    // if the early part of initSession takes too long to complete
2295    // we could have been unplugged (or reset) so we should check
2296    // we wait until here because this is the first place we're
2297    // touching the hardware semi-directly
2298    if(sp->fErrno || !fActiveSession || isInactive()) {
2299		debug(DCDTRD, "and then we return offline");
2300        rtn = kIOReturnOffline;
2301        return;
2302    }
2303    // Cycle the PD_RS232_S_DTR line if necessary
2304    if ( !ISSET(fProvider->getState(), PD_RS232_S_DTR) ) {
2305        (void) waitOutDelay(0, &fDTRDownTime, &kDTRDownDelay);
2306        // racey, racey
2307        if(sp->fErrno || !fActiveSession || isInactive()) {
2308            rtn = kIOReturnOffline;
2309            return;
2310        } else
2311            (void) mctl(RS232_S_ON, DMSET);
2312	}
2313
2314    // Disable all flow control  & data movement initially
2315#if JLOG
2316	kprintf("IOSerialBSDClient::initSession::sessionExecuteEvent::PD_E_FLOW_CONTROL, 0\n");
2317#endif
2318    rtn  = sessionExecuteEvent(sp, PD_E_FLOW_CONTROL, 0);
2319#if JLOG
2320	kprintf("IOSerialBSDClient::initSession::sessionSetState::0, PD_S_RX_ENABLE | PD_S_TX_ENABLE\n");
2321#endif
2322
2323    rtn |= sessionSetState(sp, 0, PD_S_RX_ENABLE | PD_S_TX_ENABLE);
2324    assert(!rtn || rtn == kIOReturnOffline || rtn == kIOReturnNotOpen);
2325
2326    /* Raise RTS */
2327#if JLOG
2328	kprintf("IOSerialBSDClient::initSession::sessionSetState::PD_RS232_S_RTS, PD_RS232_S_RTS\n");
2329#endif
2330
2331    rtn = sessionSetState(sp,  PD_RS232_S_RTS, PD_RS232_S_RTS);
2332
2333    assert(!rtn || rtn == kIOReturnOffline || rtn == kIOReturnNotOpen);
2334}
2335
2336bool IOSerialBSDClient::
2337waitOutDelay(void *event,
2338             const struct timeval *start, const struct timeval *duration)
2339{
2340
2341    struct timeval delta;
2342#if JLOG
2343	kprintf("IOSerialBSDClient::waitOutDelay\n");
2344#endif
2345
2346    timeradd(start, duration, &delta); // Delay Till = start + duration
2347
2348    {
2349	struct timeval now;
2350
2351	microuptime(&now);
2352	timersub(&delta, &now, &delta);    // Delay Duration = Delay Till - now
2353    }
2354
2355    if ( delta.tv_sec < 0 || !timerisset(&delta) )
2356        return false;	// Delay expired
2357    else if (event) {
2358        unsigned int delayTicks;
2359
2360        delayTicks = MUSEC2TICK(delta.tv_sec * 1000000 + delta.tv_usec);
2361        tsleep((caddr_t) event, TTIPRI, "ttydelay", delayTicks);
2362    }
2363    else {
2364        unsigned int delayMS;
2365
2366        /* Calculate the required delay in milliseconds, rounded up */
2367        delayMS =  delta.tv_sec * 1000 + (delta.tv_usec + 999) / 1000;
2368
2369        IOSleep(delayMS);
2370    }
2371    return true;	// We did sleep
2372}
2373
2374int IOSerialBSDClient::
2375waitForIdle()
2376{
2377#if JLOG
2378	kprintf("IOSerialBSDClient::waitForIdle\n");
2379#endif
2380
2381    while (fActiveSession || fConnectTransit) {
2382        if (isInactive())
2383            return ENXIO;
2384
2385        int error = tsleep((caddr_t) this, TTIPRI | PCATCH, "ttyidl", 0);
2386        if (error)
2387            return error;
2388    }
2389
2390    return 0;
2391}
2392
2393void IOSerialBSDClient::
2394preemptActive()
2395{
2396#if JLOG
2397	kprintf("IOSerialBSDClient::preemptActive\n");
2398#endif
2399    //
2400    // We are not allowed to pre-empt if the current port has been
2401    // active recently.  So wait out the delay and if we sleep
2402    // then we will need to return to check the open conditions again.
2403    //
2404    if (waitOutDelay(&fPreemptAllowed, &fLastUsedTime, &kPreemptIdle))
2405        return;
2406
2407    Session *sp = fActiveSession;
2408    struct tty *tp = sp->ftty;
2409
2410    sp->fErrno = EBUSY;
2411
2412    // This flag gets reset once we actually take over the session
2413    // this is done by the open code where it acquires the port
2414    // obviously we don't need to re-acquire the port as we didn't
2415    // release it in this case.
2416    //
2417    // setting fPreemptAllowed false here effectively locks other
2418    // preemption out...
2419    fPreemptAllowed = false;
2420    // set fPreemptInProgress to keep the EBUSY condition held high
2421    // during termination of the Preempted open
2422    // --- manifested in txfunc and rxfunc
2423    //
2424    // side effect of locking around the thread start/stop code
2425    fPreemptInProgress = true;
2426
2427    // Enforce a zombie and unconnected state on the discipline
2428	tty_lock(tp);
2429    CLR(tp->t_cflag, CLOCAL);		// Fake up a carrier drop
2430    (void) bsdld_modem(tp, false);
2431	tty_unlock(tp);
2432
2433    // Wakeup all possible sleepers
2434    wakeup(TSA_CARR_ON(tp));
2435	tty_lock(tp);
2436    ttwakeup(tp);
2437	ttwwakeup(tp);
2438    tty_unlock(tp);
2439
2440    killThreads();
2441
2442    // Shutdown the open connection - complicated hand shaking
2443    if (fInOpensPending) {
2444	// Wait for the openers to finish up - still connectTransit
2445	while (fInOpensPending)
2446	    tsleep((caddr_t) &fInOpensPending, TTIPRI, "ttypre", 0);
2447	// Once the sleepers have all woken up it is safe to reset the
2448	// errno and continue on.
2449	sp->fErrno = 0;
2450    }
2451    // Preemption is over (it has occurred)
2452    fPreemptInProgress = false;
2453    fActiveSession = 0;
2454    SAFE_PORTRELEASE(fProvider);
2455}
2456
2457void IOSerialBSDClient::
2458startConnectTransit()
2459{
2460#if JLOG
2461	kprintf("IOSerialBSDClient::startConnectTransit\n");
2462#endif
2463    // Wait for the connection (open()/close()) engine to stabilise
2464    while (fConnectTransit)
2465        tsleep((caddr_t) this, TTIPRI, "ttyctr", 0);
2466    fConnectTransit = true;
2467}
2468
2469void IOSerialBSDClient::
2470endConnectTransit()
2471{
2472#if JLOG
2473	kprintf("IOSerialBSDClient::endConnectTransit\n");
2474#endif
2475    // Clear up the transit while we are waiting for carrier
2476    fConnectTransit = false;
2477    wakeup(this);
2478}
2479/*
2480 * convertFlowCtrl
2481 */
2482void
2483IOSerialBSDClient::convertFlowCtrl(Session *sp, struct termios *t)
2484{
2485    IOReturn rtn;
2486    UInt32 flowCtrl = 0;
2487#if JLOG
2488	kprintf("IOSerialBSDClient::convertFlowCtrl\n");
2489#endif
2490    //
2491    // Have to reconstruct the flow control bits
2492    //
2493    rtn = sessionRequestEvent(sp, PD_E_FLOW_CONTROL, &flowCtrl);
2494    assert(!rtn);
2495
2496    if ( ISSET(flowCtrl, PD_RS232_A_TXO) )
2497        SET(t->c_iflag, IXON);
2498    if ( ISSET(flowCtrl, PD_RS232_A_XANY) )
2499        SET(t->c_iflag, IXANY);
2500    if ( ISSET(flowCtrl, PD_RS232_A_RXO) )
2501        SET(t->c_iflag, IXOFF);
2502
2503    if ( ISSET(flowCtrl, PD_RS232_A_RFR) )
2504        SET(t->c_cflag, CRTS_IFLOW);
2505    if ( ISSET(flowCtrl, PD_RS232_A_CTS) )
2506        SET(t->c_cflag, CCTS_OFLOW);
2507    if ( ISSET(flowCtrl, PD_RS232_A_DTR) )
2508        SET(t->c_cflag, CDTR_IFLOW);
2509
2510}
2511
2512// XXX gvdl: Must only call when session is valid, check isInActive as well
2513/*
2514 * mctl assumes lock isn't held
2515 */
2516int IOSerialBSDClient::
2517mctl(u_int bits, int how)
2518{
2519    u_long oldBits, mbits;
2520    IOReturn rtn;
2521#if JLOG
2522	kprintf("IOSerialBSDClient::mctl\n");
2523#endif
2524    if ( ISSET(bits, PD_RS232_S_BRK) && (how == DMBIS || how == DMBIC) ) {
2525	oldBits = (how == DMBIS);
2526	rtn = fProvider->enqueueEvent(PD_RS232_E_LINE_BREAK, oldBits, true);
2527	if (!rtn && oldBits)
2528	    rtn = fProvider->enqueueEvent(PD_E_DELAY, BRK_DELAY, true);
2529	assert(!rtn || rtn == kIOReturnOffline || rtn == kIOReturnNotOpen);
2530	return oldBits;
2531    }
2532
2533    bits &= RS232_S_OUTPUTS;
2534    oldBits = fProvider->getState();
2535
2536    mbits = oldBits;
2537    switch (how)
2538    {
2539    case DMSET:
2540	mbits = bits | (mbits & RS232_S_INPUTS);
2541	break;
2542
2543    case DMBIS:
2544	SET(mbits, bits);
2545	break;
2546
2547    case DMBIC:
2548	CLR(mbits, bits);
2549	break;
2550
2551    case DMGET:
2552	return mbits;
2553    }
2554
2555    /* Check for a transition of DTR to low and record the down time */
2556    if ( ISSET(oldBits & ~mbits, PD_RS232_S_DTR) )
2557	microuptime(&fDTRDownTime);
2558
2559    rtn = fProvider->setState(mbits, RS232_S_OUTPUTS);
2560    if (rtn)
2561	IOLog("ttyioss%04x: mctl RS232_S_OUTPUTS failed %x\n",
2562	    fBaseDev, rtn);
2563
2564
2565    return mbits;
2566}
2567
2568/*
2569 * Support routines
2570 */
2571#define NOBYPASS_IFLAG_MASK   (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON)
2572#define NOBYPASS_PAR_MASK     (IGNPAR | IGNBRK)
2573#define NOBYPASS_LFLAG_MASK   (ECHO | ICANON | IEXTEN | ISIG)
2574/*
2575 * optimiseInput assumes lock is held
2576 */
2577void IOSerialBSDClient::
2578optimiseInput(struct termios *t)
2579{
2580    Session *sp = fActiveSession;
2581#if JLOG
2582	kprintf("IOSerialBSDClient::optimiseInput\n");
2583#endif
2584    if (!sp)	// Check for a hot unplug
2585	return;
2586
2587    struct tty *tp = sp->ftty;
2588    UInt32 slipEvent, pppEvent;
2589
2590    bool cantByPass =
2591        (ISSET(t->c_iflag, NOBYPASS_IFLAG_MASK)
2592          || ( ISSET(t->c_iflag, BRKINT) && !ISSET(t->c_iflag, IGNBRK) )
2593          || ( ISSET(t->c_iflag, PARMRK)
2594               && ISSET(t->c_iflag, NOBYPASS_PAR_MASK) != NOBYPASS_PAR_MASK)
2595          || ISSET(t->c_lflag, NOBYPASS_LFLAG_MASK)
2596          || linesw[tp->t_line].l_rint != ttyinput);
2597
2598	tty_lock(tp);
2599    if (cantByPass)
2600        CLR(tp->t_state, TS_CAN_BYPASS_L_RINT);
2601    else
2602        SET(tp->t_state, TS_CAN_BYPASS_L_RINT);
2603	tty_unlock(tp);
2604
2605    /*
2606     * Prepare to reduce input latency for packet
2607     * disciplines with a end of packet character.
2608     */
2609    if (tp->t_line == SLIPDISC) {
2610        slipEvent = PD_E_SPECIAL_BYTE;
2611        pppEvent  = PD_E_VALID_DATA_BYTE;
2612    }
2613    else if (tp->t_line == PPPDISC) {
2614        slipEvent = PD_E_VALID_DATA_BYTE;
2615        pppEvent  = PD_E_SPECIAL_BYTE;
2616    }
2617    else {
2618        slipEvent = PD_E_VALID_DATA_BYTE;
2619        pppEvent  = PD_E_VALID_DATA_BYTE;
2620    }
2621    (void) sessionExecuteEvent(sp, slipEvent, 0xc0);
2622    (void) sessionExecuteEvent(sp, pppEvent, 0xc0);
2623}
2624
2625void IOSerialBSDClient::
2626iossdcddelay(thread_call_param_t vSelf, thread_call_param_t vSp)
2627{
2628#if JLOG
2629	kprintf("IOSerialBSDClient::iossdcddelay\n");
2630#endif
2631
2632    IOSerialBSDClient *self = (IOSerialBSDClient *) vSelf;
2633    Session *sp = (Session *) vSp;
2634    struct tty *tp = sp->ftty;
2635
2636    assert(self->fDCDTimerDue);
2637
2638    if (!sp->fErrno && ISSET(tp->t_state, TS_ISOPEN)) {
2639
2640	bool pd_state = ISSET(self->sessionGetState(sp), PD_RS232_S_CAR);
2641	tty_lock(tp);
2642	(void) bsdld_modem(tp, (int) pd_state);
2643	tty_unlock(tp);
2644    }
2645
2646    self->fDCDTimerDue = false;
2647    self->release();
2648}
2649
2650
2651/*
2652 * The three functions below make up the recieve thread of the
2653 * Port Devices Line Discipline interface.
2654 *
2655 *	getData		// Main sleeper function
2656 *	procEvent	// Event processing
2657 *	rxFunc		// Thread main loop
2658*/
2659
2660#define VALID_DATA (PD_E_VALID_DATA_BYTE & PD_E_MASK)
2661
2662void IOSerialBSDClient::
2663getData(Session *sp)
2664{
2665    struct tty *tp = sp->ftty;
2666    UInt32 transferCount, bufferSize, minCount;
2667    UInt8 rx_buf[1024];
2668    IOReturn rtn;
2669
2670#if JLOG
2671	kprintf("IOSerialBSDClient::getData\n");
2672#endif
2673    if (fKillThreads)
2674        return;
2675
2676    bufferSize = TTY_HIGHWATER - TTY_QUEUESIZE(tp);
2677    bufferSize = MIN(bufferSize, (uint32_t)sizeof(rx_buf));
2678    if (bufferSize <= 0) {
2679        frxBlocked = true;	// No buffer space so block ourselves
2680        return;			// Will try again if data present
2681    }
2682    if (frxBlocked) {
2683        frxBlocked = false;
2684    }
2685
2686    // minCount = (delay_usecs)? bufferSize : 1;
2687    minCount = 1;
2688
2689    rtn = sessionDequeueData(sp, rx_buf, bufferSize, &transferCount, minCount);
2690    if (rtn) {
2691	if (rtn == kIOReturnOffline || rtn == kIOReturnNotOpen)
2692	    frxBlocked = true;	// Force a session condition check
2693	else if (rtn != kIOReturnIOError)
2694	    IOLog("ttyioss%04x: dequeueData ret %x\n", tp->t_dev, rtn);
2695        return;
2696    }
2697
2698    if (!transferCount)
2699        return;
2700
2701    // Track last in bound data time
2702    if (fPreemptAllowed)
2703	microuptime(&fLastUsedTime);
2704
2705    /*
2706     * Avoid the grotesquely inefficient lineswitch routine
2707     * (ttyinput) in "raw" mode.  It usually takes about 450
2708     * instructions (that's without canonical processing or echo!).
2709     * slinput is reasonably fast (usually 40 instructions plus
2710     * call overhead).
2711     */
2712    if ( ISSET(tp->t_state, TS_CAN_BYPASS_L_RINT)
2713    &&  !ISSET(tp->t_lflag, PENDIN) ) {
2714		tty_lock(tp);
2715		/* Update statistics */
2716        tk_nin += transferCount;
2717        tk_rawcc += transferCount;
2718        tp->t_rawcc += transferCount;
2719
2720        /* update the rawq and tell recieve waiters to wakeup */
2721		(void) b_to_q(rx_buf, transferCount, &tp->t_rawq);
2722        ttwakeup(tp);
2723		tty_unlock(tp);
2724    }
2725    else {
2726
2727        for (minCount = 0; minCount < transferCount; minCount++) {
2728			tty_lock(tp);
2729            bsdld_rint(rx_buf[minCount], tp);
2730			tty_unlock(tp);
2731		}
2732    }
2733}
2734
2735void IOSerialBSDClient::
2736procEvent(Session *sp)
2737{
2738    struct tty *tp = sp->ftty;
2739    UInt32 event, data;
2740    IOReturn rtn;
2741#if JLOG
2742	kprintf("IOSerialBSDClient::procEvent\n");
2743#endif
2744    if (frxBlocked) {
2745        frxBlocked = false;
2746    }
2747
2748    rtn = sessionDequeueEvent(sp, &event, &data, false);
2749    if (kIOReturnOffline == rtn)
2750	return;
2751
2752    assert(!rtn && event != PD_E_EOQ && (event & PD_E_MASK) != VALID_DATA);
2753
2754    switch(event) {
2755    case PD_E_SPECIAL_BYTE:
2756	break;	// Pass on the character to tty layer
2757
2758    case PD_RS232_E_LINE_BREAK:	data  = 0;	   /* no_break */
2759    case PD_E_FRAMING_ERROR:	SET(data, TTY_FE);	break;
2760    case PD_E_INTEGRITY_ERROR:	SET(data, TTY_PE);	break;
2761
2762    case PD_E_HW_OVERRUN_ERROR:
2763    case PD_E_SW_OVERRUN_ERROR:
2764	IOLog("ttyioss%04x: %sware Overflow\n", tp->t_dev,
2765	    (event == PD_E_SW_OVERRUN_ERROR) ? "Soft" : "Hard" );
2766	event = 0;
2767	break;
2768
2769    case PD_E_DATA_LATENCY:
2770	/* no_break */
2771
2772    case PD_E_FLOW_CONTROL:
2773    default:	/* Ignore */
2774	event = 0;
2775	break;
2776    }
2777
2778    if (event) {
2779        // Track last in bound event time
2780        if (fPreemptAllowed)
2781		microuptime(&fLastUsedTime);
2782	tty_lock(tp);
2783	bsdld_rint(data, tp);
2784	tty_unlock(tp);
2785    }
2786}
2787
2788void IOSerialBSDClient::
2789rxFunc()
2790{
2791    Session *sp;
2792    struct tty *tp;
2793    int event;
2794    UInt32 wakeup_with;	// states
2795    IOReturn rtn;
2796#if JLOG
2797	kprintf("IOSerialBSDClient::rxFunc\n");
2798#endif
2799    IOLockLock(fThreadLock);
2800    sp = fActiveSession;
2801    if (!sp || !(tp=sp->ftty) || fKillThreads) {
2802        fThreadState |= THREAD_RX_STARTED | THREAD_RX_FINISHED;
2803        IOLockWakeup(fThreadLock, &fThreadState, true);
2804        IOLockUnlock(fThreadLock);
2805        (void) thread_terminate(current_thread());
2806        return;
2807    }
2808
2809    fThreadState |= THREAD_RX_STARTED;
2810
2811    IOLockWakeup(fThreadLock, &fThreadState, true);	// wakeup the thread launcher
2812    IOLockUnlock(fThreadLock);
2813
2814    frxBlocked = false;
2815
2816    while ( !fKillThreads ) {
2817        if (frxBlocked) {
2818            wakeup_with = PD_S_RX_EVENT;
2819            rtn = sessionWatchState(sp, &wakeup_with, PD_S_RX_EVENT);
2820            sessionSetState(sp, 0, PD_S_RX_EVENT);
2821            if ( kIOReturnOffline == rtn || kIOReturnNotOpen == rtn
2822                ||   fKillThreads)
2823                break;	// Terminate thread loop
2824        }
2825	event = (sessionNextEvent(sp) & PD_E_MASK);
2826	if (event == PD_E_EOQ || event == VALID_DATA)
2827	    getData(sp);
2828	else
2829	    procEvent(sp);
2830    }
2831
2832    // commit seppuku cleanly
2833#ifdef DEBUG
2834    debug(CONTROL, "%s\n%s\n%s", state2StringPD(sessionGetState(sp)),
2835          state2StringTTY(tp->t_state), state2StringTermios((int)tp->t_cflag));
2836#endif
2837
2838    IOLockLock(fThreadLock);
2839    fThreadState |= THREAD_RX_FINISHED;
2840    IOLockWakeup(fThreadLock, &fThreadState, true);	// wakeup the thread killer
2841	debug(FLOW, "fisCallout is: %d, fwantCallout is: %d, fisBlueTooth is: %d",
2842          fisCallout, fwantCallout, fisBlueTooth);
2843	debug(FLOW, "fPreemptAllowed is: %d", fPreemptAllowed);
2844
2845    if (fDeferTerminate && (fThreadState & THREAD_TX_FINISHED) && !fInOpensPending) {
2846        SAFE_PORTRELEASE(fProvider);
2847
2848        bool defer = false;
2849        super::didTerminate(fProvider, 0, &defer);
2850    }
2851    else // we shouldn't go down this path if we've already released the port
2852         // (and didTerminate handles the rest of the issues anyway)
2853    {
2854        debug(FLOW, "we're killing our thread");
2855        // because bluetooth leaves its /dev/tty entries around
2856        // we need to tell the bsd side that carrier has dropped
2857        // when bluetooth tells us kIOReturnNotOpen (which it does correctly)
2858        // other tty like driver stacks would also ask us to remove the
2859        // /dev/tty entries which would terminate us cleanly
2860        // so... this check should be benign except for bluetooth
2861        // it should also be pointed out that it may be a limitation of the CLOCAL
2862        // handling in ppp that contributes to this problem
2863        //
2864        // benign except for the preemption case - fixed...
2865        if ((fThreadState & THREAD_TX_FINISHED) && !fInOpensPending &&
2866            !fPreemptInProgress && fisBlueTooth)
2867        {
2868            // no transmit thread, we're about to kill the receive thread
2869            // tell the bsd side no more bytes (fErrno = 0)
2870            debug(FLOW, "no more threads, so we shouldn't be busy or have carrier");
2871            // Now kill any stream that may currently be running
2872            sp->fErrno = 0;
2873
2874            // Enforce a zombie and unconnected state on the discipline
2875#ifdef DEBUG
2876            debug(CONTROL, "%s\n%s\n%s", state2StringPD(sessionGetState(sp)),
2877                  state2StringTTY(tp->t_state),
2878                  state2StringTermios((int)tp->t_cflag));
2879#endif
2880            debug(FLOW, "faking a CLOCAL drop");
2881            tty_lock(tp);
2882            CLR(tp->t_cflag, CLOCAL);  // Fake up a carrier drop
2883            debug(FLOW, "faked a CLOCAL drop, about to fake a carrier drop");
2884#ifdef DEBUG
2885            debug(CONTROL, "%s\n%s\n%s", state2StringPD(sessionGetState(sp)),
2886                  state2StringTTY(tp->t_state),
2887                  state2StringTermios((int)tp->t_cflag));
2888#endif
2889
2890            (void) bsdld_modem(tp, false);
2891            tty_unlock(tp);
2892            debug(FLOW, "faked a carrier drop");
2893#ifdef DEBUG
2894            debug(CONTROL, "%s\n%s\n%s", state2StringPD(sessionGetState(sp)),
2895                  state2StringTTY(tp->t_state),
2896                  state2StringTermios((int)tp->t_cflag));
2897#endif
2898
2899        }
2900    }
2901    IOLockUnlock(fThreadLock);
2902    debug(FLOW, "thread be dead");
2903    (void) thread_terminate(current_thread());
2904}
2905
2906/*
2907 * The three functions below make up the status monitoring and transmition
2908 * part of the Port Devices Line Discipline interface.
2909 *
2910 *	txload		// TX data download to Port Device
2911 *	dcddelay	// DCD callout function for DCD transitions
2912 *	txFunc		// Thread main loop and sleeper
2913 *
2914 *  txload assumes the lock is not held when it is called...
2915 */
2916
2917void IOSerialBSDClient::
2918txload(Session *sp, UInt32 *wait_mask)
2919{
2920    struct tty *tp = sp->ftty;
2921    IOReturn rtn;
2922    UInt8 tx_buf[CBSIZE * 8];	// 1/2k buffer
2923    UInt32 data;
2924    UInt32 cc, size;
2925#if JLOG
2926	kprintf("IOSerialBSDClient::txload\n");
2927#endif
2928    if ( !tp->t_outq.c_cc )
2929		return;		// Nothing to do
2930    if ( !ISSET(tp->t_state, TS_BUSY) ) {
2931		tty_lock(tp);
2932        SET(tp->t_state, TS_BUSY);
2933        tty_unlock(tp);
2934		SET(*wait_mask, PD_S_TXQ_EMPTY); // Start tracking PD_S_TXQ_EMPTY
2935		CLR(*wait_mask, PD_S_TX_BUSY);
2936
2937    }
2938
2939    while ( (cc = tp->t_outq.c_cc) ) {
2940        rtn = sessionRequestEvent(sp, PD_E_TXQ_AVAILABLE, &data);
2941		if (kIOReturnOffline == rtn || kIOReturnNotOpen == rtn)
2942			return;
2943
2944		assert(!rtn);
2945
2946        size = data;
2947		if (size > 0)
2948			size = MIN(size, (uint32_t)sizeof(tx_buf));
2949		else {
2950			SET(*wait_mask, PD_S_TXQ_LOW_WATER); // Start tracking low water
2951			return;
2952		}
2953		tty_lock(tp);
2954		size = q_to_b(&tp->t_outq, tx_buf, MIN(cc, size));
2955		tty_unlock(tp);
2956		assert(size);
2957
2958	/* There was some data left over from the previous load */
2959        rtn = sessionEnqueueData(sp, tx_buf, size, &cc, false);
2960        if (fPreemptAllowed)
2961	    microuptime(&fLastUsedTime);
2962
2963		if (kIOReturnSuccess == rtn) {
2964			tty_lock(tp);
2965			bsdld_start(tp);
2966			tty_unlock(tp);
2967		}
2968        else
2969	    IOLog("ttyioss%04x: enqueueData rtn (%x)\n", tp->t_dev, rtn);
2970#ifdef DEBUG
2971        if ((u_int) cc != size)
2972            IOLog("ttyioss%04x: enqueueData didn't queue everything\n",
2973                  tp->t_dev);
2974#endif
2975    }
2976}
2977
2978void IOSerialBSDClient::
2979txFunc()
2980{
2981    Session *sp;
2982    struct tty *tp;
2983    UInt32 waitfor, waitfor_mask, wakeup_with;	// states
2984    UInt32 interesting_bits;
2985    IOReturn rtn;
2986#if JLOG
2987	kprintf("IOSerialBSDClient::txFunc\n");
2988#endif
2989
2990    IOLockLock(fThreadLock);
2991    sp = fActiveSession;
2992    if (!sp || !(tp=sp->ftty) || fKillThreads) {
2993        fThreadState |= THREAD_TX_STARTED | THREAD_TX_FINISHED;
2994        IOLockWakeup(fThreadLock, &fThreadState, true);
2995        IOLockUnlock(fThreadLock);
2996        (void) thread_terminate(current_thread());
2997        return;
2998    }
2999
3000    fThreadState |= THREAD_TX_STARTED;
3001
3002    IOLockWakeup(fThreadLock, &fThreadState, true);	// wakeup the thread launcher
3003    IOLockUnlock(fThreadLock);
3004
3005    /*
3006     * Register interest in transitions to high of the
3007     *  PD_S_TXQ_LOW_WATER, PD_S_TXQ_EMPTY, PD_S_TX_EVENT status bits
3008     * and all other bit's being low
3009     */
3010    waitfor_mask = (PD_S_TX_EVENT | PD_S_TX_BUSY       | PD_RS232_S_CAR);
3011    waitfor      = (PD_S_TX_EVENT | PD_S_TXQ_LOW_WATER | PD_S_TXQ_EMPTY);
3012
3013    // Get the current carrier state and toggle it
3014    SET(waitfor, ISSET(sessionGetState(sp), PD_RS232_S_CAR) ^ PD_RS232_S_CAR);
3015    for ( ;; ) {
3016		wakeup_with = waitfor;
3017		rtn  = sessionWatchState(sp, &wakeup_with, waitfor_mask);
3018		if ( rtn )
3019			break;	// Terminate thread loop
3020
3021		//
3022		// interesting_bits are set to true if the wait_for = wakeup_with
3023		// and we expressed an interest in the bit in waitfor_mask.
3024		//
3025		interesting_bits = waitfor_mask & (~waitfor ^ wakeup_with);
3026
3027		// Has iossstart been trying to get out attention
3028		if ( ISSET(PD_S_TX_EVENT, interesting_bits) ) {
3029			/* Clear PD_S_TX_EVENT bit in state register */
3030			rtn = sessionSetState(sp, 0, PD_S_TX_EVENT);
3031			assert(!rtn || rtn == kIOReturnOffline || rtn == kIOReturnNotOpen);
3032			txload(sp, &waitfor_mask);
3033		}
3034
3035		//
3036		// Now process the carriers current state if it has changed
3037		//
3038		if ( ISSET(PD_RS232_S_CAR, interesting_bits) ) {
3039			waitfor ^= PD_RS232_S_CAR;		/* toggle value */
3040
3041			if (fDCDTimerDue) {
3042				/* Stop dcd timer interval was too short */
3043				if (thread_call_cancel(fDCDThreadCall)) {
3044					debug(DCDTRD,"DCD thread canceled (interval too short)");
3045					release();
3046					fDCDTimerDue = false;
3047				}
3048			} else {
3049				AbsoluteTime dl;
3050
3051				clock_interval_to_deadline(DCD_DELAY, kMicrosecondScale, &dl);
3052				thread_call_enter1_delayed(fDCDThreadCall, sp, dl);
3053				debug(DCDTRD,"DCD thread enter1 delayed");
3054				retain();
3055				fDCDTimerDue = true;
3056			}
3057		}
3058
3059		//
3060		// Check to see if we can unblock the data transmission
3061		//
3062
3063		if ( ISSET(PD_S_TXQ_LOW_WATER, interesting_bits) ) {
3064			CLR(waitfor_mask, PD_S_TXQ_LOW_WATER); // Not interested any more
3065			txload(sp, &waitfor_mask);
3066		}
3067
3068		//
3069		// 2 stage test for transmitter being no longer busy.
3070		// Stage 1: TXQ_EMPTY high, register interest in TX_BUSY bit
3071		//
3072		if ( ISSET(PD_S_TXQ_EMPTY, interesting_bits) ) {
3073			CLR(waitfor_mask, PD_S_TXQ_EMPTY); /* Not interested */
3074			SET(waitfor_mask, PD_S_TX_BUSY);   // But I want to know about chip
3075		}
3076
3077		//
3078		// Stage 2 TX_BUSY dropping.
3079		// NB don't want to use interesting_bits as the TX_BUSY mask may
3080		// have just been set.  Instead here we simply check for a low.
3081		//
3082		if (PD_S_TX_BUSY & waitfor_mask & ~wakeup_with) {
3083			CLR(waitfor_mask, PD_S_TX_BUSY); /* No longer interested */
3084			tty_lock(tp);
3085			CLR(tp->t_state,  TS_BUSY);
3086
3087			/* Notify disc, not busy anymore */
3088			bsdld_start(tp);
3089			tty_unlock(tp);
3090		}
3091
3092    }
3093
3094    // Clear the DCD timeout
3095    if (fDCDTimerDue && thread_call_cancel(fDCDThreadCall)) {
3096		debug(DCDTRD,"DCD thread canceled (clear timeout)");
3097		release();
3098		fDCDTimerDue = false;
3099    }
3100
3101    IOLockLock(fThreadLock);
3102    fThreadState |= THREAD_TX_FINISHED;
3103    IOLockWakeup(fThreadLock, &fThreadState, true);	// wakeup the thread killer
3104    debug(FLOW, "fisCallout is: %d, fwantCallout is: %d, fisBlueTooth is: %d",
3105          fisCallout, fwantCallout, fisBlueTooth);
3106    debug(FLOW, "fPreemptAllowed is: %d", fPreemptAllowed);
3107
3108    if (fDeferTerminate && (fThreadState & THREAD_RX_FINISHED) && !fInOpensPending) {
3109		SAFE_PORTRELEASE(fProvider);
3110
3111		bool defer = false;
3112		super::didTerminate(fProvider, 0, &defer);
3113    }
3114    else // we shouldn't go down this path if we've already released the port
3115         // (and didTerminate handles the rest of the issues anyway)
3116    {
3117        debug(FLOW, "we're killing our thread");
3118        // because bluetooth leaves its /dev/tty entries around
3119        // we need to tell the bsd side that carrier has dropped
3120        // when bluetooth tells us kIOReturnNotOpen (which it does correctly)
3121        // other tty like driver stacks would also ask us to remove the
3122        // /dev/tty entries which would terminate us cleanly
3123        // so... this check should be benign except for bluetooth
3124        //
3125        // it should also be pointed out that it may be a limitation of the CLOCAL
3126        // handling in ppp that contributes to this problem
3127        //
3128        // benign except in the preemption case - fixed...
3129        if ((fThreadState & THREAD_RX_FINISHED) && !fInOpensPending &&
3130            !fPreemptInProgress && fisBlueTooth)
3131        {
3132            // no receive thread, we're about to kill the transmit thread
3133            // tell the bsd side no more bytes (fErrno = 0)
3134            debug(FLOW, "no more threads, so we shouldn't be busy or have carrier");
3135            // Now kill any stream that may currently be running
3136            sp->fErrno = 0;
3137
3138            // Enforce a zombie and unconnected state on the discipline
3139#ifdef DEBUG
3140            debug(CONTROL, "%s\n%s\n%s", state2StringPD(sessionGetState(sp)),
3141                  state2StringTTY(tp->t_state),
3142                  state2StringTermios((int)tp->t_cflag));
3143#endif
3144            debug(FLOW, "faking a CLOCAL drop");
3145            tty_lock(tp);
3146            CLR(tp->t_cflag, CLOCAL);  // Fake up a carrier drop
3147            debug(FLOW, "faked a CLOCAL drop, about to fake a carrier drop");
3148#ifdef DEBUG
3149            debug(CONTROL, "%s\n%s\n%s", state2StringPD(sessionGetState(sp)),
3150                  state2StringTTY(tp->t_state),
3151                  state2StringTermios((int)tp->t_cflag));
3152#endif
3153
3154            (void) bsdld_modem(tp, false);
3155            tty_unlock(tp);
3156            debug(FLOW, "faked a carrier drop");
3157#ifdef DEBUG
3158            debug(CONTROL, "%s\n%s\n%s", state2StringPD(sessionGetState(sp)),
3159                  state2StringTTY(tp->t_state),
3160                  state2StringTermios((int)tp->t_cflag));
3161#endif
3162        }
3163    }
3164    IOLockUnlock(fThreadLock);
3165
3166    debug(FLOW, "thread be dead");
3167    (void) thread_terminate(current_thread());
3168}
3169
3170void IOSerialBSDClient::
3171launchThreads()
3172{
3173    // Clear the have launched flags
3174#if JLOG
3175	kprintf("IOSerialBSDClient::launchThreads\n");
3176#endif
3177
3178    if (fThreadState) {
3179        // state should be zero
3180        return;
3181    }
3182
3183    fThreadLock = IOLockAlloc();
3184    if (!fThreadLock) {
3185        // here, fThreadState is not protected by fThreadLock,
3186        // this is to signal to killThreads that it can proceed
3187        fThreadState = (THREAD_LAUNCH_FINISHED |
3188                        THREAD_RX_FINISHED |
3189                        THREAD_TX_FINISHED);
3190        return;
3191    }
3192
3193    IOLockLock(fThreadLock);
3194    fThreadState = THREAD_LAUNCH_STARTED;
3195
3196    // Now launch the receive and transmitter threads
3197#if JLOG
3198	kprintf("IOSerialBSDClient::createThread::rxFunc\n");
3199#endif
3200
3201    createThread(
3202	OSMemberFunctionCast(IOThreadFunc, this, &IOSerialBSDClient::rxFunc),
3203	this);
3204#if JLOG
3205	kprintf("IOSerialBSDClient::createThread::txFunc\n");
3206#endif
3207    createThread(
3208	OSMemberFunctionCast(IOThreadFunc, this, &IOSerialBSDClient::txFunc),
3209	this);
3210
3211    // Now wait for the threads to actually launch
3212    while (!(fThreadState & THREAD_RX_MASK))
3213        IOLockSleep(fThreadLock, &fThreadState, THREAD_UNINT);
3214    while (!(fThreadState & THREAD_TX_MASK))
3215        IOLockSleep(fThreadLock, &fThreadState, THREAD_UNINT);
3216
3217    fThreadState |= THREAD_LAUNCH_FINISHED;
3218
3219    // possibly need to wake up thread killer
3220    IOLockWakeup(fThreadLock, &fThreadState, true);
3221
3222    IOLockUnlock(fThreadLock);
3223}
3224
3225/* killThreads()
3226 * killThreads is responsible for killing:
3227 * - rx thread ("rxFunc"),
3228 * - tx thread ("txFunc").
3229 * It also has to make sure the launch thread ("launchThreads") has completed.
3230 * Before exiting, killThreads frees fThreadLock and sets fThreadState = 0x0000.
3231 * Note: killThreads can be called only if launchThreads was called previously.
3232 */
3233void IOSerialBSDClient::
3234killThreads()
3235{
3236#if JLOG
3237	kprintf("IOSerialBSDClient::killThreads\n");
3238#endif
3239    int count = 0;
3240    fKillThreads = true;
3241
3242    // Waiting for launchThreads to start
3243    while (!fThreadState && count < 10) {
3244        IOSleep(10);
3245        count ++;
3246    }
3247    if (!fThreadState || !fThreadLock) {
3248        fThreadState = 0x0000;
3249        return;
3250    }
3251
3252    // now we are sure that fThreadLock exists
3253    IOLockLock(fThreadLock);
3254
3255    // waiting for rx and tx to start
3256    while(!(fThreadState & THREAD_RX_MASK)) {
3257        IOLockSleep(fThreadLock, &fThreadState, THREAD_UNINT);
3258    }
3259    while(!(fThreadState & THREAD_TX_MASK)) {
3260        IOLockSleep(fThreadLock, &fThreadState, THREAD_UNINT);
3261    }
3262
3263    if (!(fThreadState & THREAD_RX_FINISHED) ||
3264        !(fThreadState & THREAD_TX_FINISHED) ||
3265        fInOpensPending) {
3266        fProvider->executeEvent(PD_E_ACTIVE, false);
3267    }
3268
3269    // waiting for rx and tx to finish
3270    while(!(fThreadState & THREAD_LAUNCH_FINISHED)) {
3271        IOLockSleep(fThreadLock, &fThreadState, THREAD_UNINT);
3272    }
3273    while(!(fThreadState & THREAD_RX_FINISHED)) {
3274        IOLockSleep(fThreadLock, &fThreadState, THREAD_UNINT);
3275    }
3276    while(!(fThreadState & THREAD_TX_FINISHED)) {
3277        IOLockSleep(fThreadLock, &fThreadState, THREAD_UNINT);
3278    }
3279
3280    IOLockUnlock(fThreadLock);
3281#ifdef TARGET_OS_EMBEDDED
3282	// bluetooth, modem and fax team need to validate change
3283	// to remove this ifdef
3284	if (fDCDThreadCall) {
3285		debug(DCDTRD,"DCD Thread Freed in killThreads");
3286		thread_call_cancel(fDCDThreadCall);
3287		thread_call_free(fDCDThreadCall);
3288		fDCDTimerDue = false;
3289		fDCDThreadCall = 0;
3290	}
3291#endif
3292
3293    if (fThreadLock) {
3294        IOLockFree(fThreadLock);
3295        fThreadLock = NULL;
3296    }
3297    fThreadState = 0x0000;
3298}
3299
3300void IOSerialBSDClient::
3301cleanupResources()
3302{
3303#if JLOG
3304	kprintf("IOSerialBSDClient::cleanupResources\n");
3305#endif
3306    // Remove our device name from the devfs
3307    if ((dev_t) -1 != fBaseDev) {
3308	sBSDGlobals.takefFunnelLock();
3309	sBSDGlobals.releaseUniqueTTYSuffix(
3310		(const OSSymbol *) getProperty(gIOTTYBaseNameKey),
3311		(const OSSymbol *) getProperty(gIOTTYSuffixKey));
3312	sBSDGlobals.releasefFunnelLock();
3313    }
3314
3315    if (fSessions[TTY_CALLOUT_INDEX].fCDevNode)
3316	devfs_remove(fSessions[TTY_CALLOUT_INDEX].fCDevNode);
3317    if (fSessions[TTY_DIALIN_INDEX].fCDevNode)
3318	devfs_remove(fSessions[TTY_DIALIN_INDEX].fCDevNode);
3319}
3320
3321//
3322// session based accessors to Serial Stream Sync
3323//
3324IOReturn IOSerialBSDClient::
3325sessionSetState(Session *sp, UInt32 state, UInt32 mask)
3326{
3327#if JLOG
3328	kprintf("IOSerialBSDClient::sessionSetState\n");
3329#endif
3330    if (sp->fErrno)
3331        return kIOReturnOffline;
3332    else
3333        return fProvider->setState(state, mask);
3334}
3335
3336UInt32 IOSerialBSDClient::
3337sessionGetState(Session *sp)
3338{
3339#if JLOG
3340	kprintf("IOSerialBSDClient::sessionGetState\n");
3341#endif
3342
3343    if (sp->fErrno)
3344        return 0;
3345    else
3346        return fProvider->getState();
3347}
3348
3349IOReturn IOSerialBSDClient::
3350sessionWatchState(Session *sp, UInt32 *state, UInt32 mask)
3351{
3352#if JLOG
3353	kprintf("IOSerialBSDClient::sessionWatchState\n");
3354#endif
3355
3356    if (sp->fErrno)
3357        return kIOReturnOffline;
3358    else
3359        return fProvider->watchState(state, mask);
3360}
3361
3362UInt32 IOSerialBSDClient::
3363sessionNextEvent(Session *sp)
3364{
3365#if JLOG
3366	kprintf("IOSerialBSDClient::sessionNextEvent\n");
3367#endif
3368
3369    if (sp->fErrno)
3370        return PD_E_EOQ;
3371    else
3372        return fProvider->nextEvent();
3373}
3374
3375IOReturn IOSerialBSDClient::
3376sessionExecuteEvent(Session *sp, UInt32 event, UInt32 data)
3377{
3378#if JLOG
3379	kprintf("IOSerialBSDClient::sessionExecuteEvent\n");
3380#endif
3381
3382    if (sp->fErrno)
3383        return kIOReturnOffline;
3384    else
3385        return fProvider->executeEvent(event, data);
3386}
3387
3388IOReturn IOSerialBSDClient::
3389sessionRequestEvent(Session *sp, UInt32 event, UInt32 *data)
3390{
3391#if JLOG
3392	kprintf("IOSerialBSDClient::sessionRequestEvent\n");
3393#endif
3394
3395    if (sp->fErrno)
3396        return kIOReturnOffline;
3397    else
3398        return fProvider->requestEvent(event, data);
3399}
3400
3401IOReturn IOSerialBSDClient::
3402sessionEnqueueEvent(Session *sp, UInt32 event, UInt32 data, bool sleep)
3403{
3404#if JLOG
3405	kprintf("IOSerialBSDClient::sessionEnqueueEvent\n");
3406#endif
3407
3408    if (sp->fErrno)
3409        return kIOReturnOffline;
3410    else
3411        return fProvider->enqueueEvent(event, data, sleep);
3412}
3413
3414IOReturn IOSerialBSDClient::
3415sessionDequeueEvent(Session *sp, UInt32 *event, UInt32 *data, bool sleep)
3416{
3417#if JLOG
3418	kprintf("IOSerialBSDClient::sessionDequeueEvent\n");
3419#endif
3420
3421    if (sp->fErrno)
3422        return kIOReturnOffline;
3423    else
3424        return fProvider->dequeueEvent(event, data, sleep);
3425}
3426
3427IOReturn IOSerialBSDClient::
3428sessionEnqueueData(Session *sp, UInt8 *buffer, UInt32 size, UInt32 *count, bool sleep)
3429{
3430#if JLOG
3431	kprintf("IOSerialBSDClient::sessionEnqueueData\n");
3432#endif
3433
3434    if (sp->fErrno)
3435        return kIOReturnOffline;
3436    else
3437        return fProvider->enqueueData(buffer, size, count, sleep);
3438}
3439
3440IOReturn IOSerialBSDClient::
3441sessionDequeueData(Session *sp, UInt8 *buffer, UInt32 size, UInt32 *count, UInt32 min)
3442{
3443#if JLOG
3444	kprintf("IOSerialBSDClient::sessionDequeueData\n");
3445#endif
3446
3447    if (sp->fErrno)
3448        return kIOReturnOffline;
3449    else
3450        return fProvider->dequeueData(buffer, size, count, min);
3451}
3452
3453IOReturn IOSerialBSDClient::
3454createThread(IOThreadFunc fcn, void *arg)
3455{
3456    kern_return_t result;
3457    thread_t thread;
3458#if JLOG
3459    kprintf("IOSerialBSDClient::createThread\n");
3460#endif
3461
3462    result = kernel_thread_start((thread_continue_t)fcn, arg, &thread);
3463
3464    if (result == KERN_SUCCESS) {
3465        thread_deallocate(thread);
3466    }
3467    return result;
3468}
3469
3470#ifdef DEBUG
3471char * IOSerialBSDClient::state2StringTermios(UInt32 state)
3472    {
3473    static char stateDescription[1024];
3474
3475    // Nulls the string:
3476    stateDescription[0] = 0;
3477
3478    // reads the state and appends values:
3479    if (state & CIGNORE)
3480        strncat(stateDescription, "CIGNORE ", sizeof(stateDescription) - 9);
3481
3482
3483    if (state & CSIZE)
3484    strncat(stateDescription, "CSIZE ", sizeof(stateDescription) - 7);
3485
3486    if (state & CSTOPB)
3487    strncat(stateDescription, "CSTOPB ", sizeof(stateDescription) - 8);
3488
3489    if (state & CREAD)
3490    strncat(stateDescription, "CREAD ", sizeof(stateDescription) - 7);
3491
3492    if (state & PARENB)
3493    strncat(stateDescription, "PARENB ", sizeof(stateDescription) - 8);
3494
3495    if (state & PARODD)
3496    strncat(stateDescription, "PARODD ", sizeof(stateDescription) - 8);
3497
3498    if (state & HUPCL)
3499    strncat(stateDescription, "HUPCL ", sizeof(stateDescription) - 7);
3500
3501    if (state & CLOCAL)
3502    strncat(stateDescription, "CLOCAL ", sizeof(stateDescription) - 8);
3503
3504    if (state & CCTS_OFLOW)
3505    strncat(stateDescription, "CCTS_OFLOW ", sizeof(stateDescription) - 12);
3506
3507    if (state & CRTSCTS)
3508    strncat(stateDescription, "CRTSCTS ", sizeof(stateDescription) - 9);
3509
3510    if (state & CRTS_IFLOW)
3511    strncat(stateDescription, "CRTS_IFLOW ", sizeof(stateDescription) - 12);
3512
3513    if (state & CDTR_IFLOW)
3514    strncat(stateDescription, "CDTR_IFLOW ", sizeof(stateDescription) - 12);
3515
3516    if (state & CDSR_OFLOW)
3517    strncat(stateDescription, "CDSR_OFLOW ", sizeof(stateDescription) - 12);
3518
3519    if (state & CCAR_OFLOW)
3520    strncat(stateDescription, "CCAR_OFLOW ", sizeof(stateDescription) - 12);
3521
3522    if (state & MDMBUF)
3523    strncat(stateDescription, "MDMBUF ", sizeof(stateDescription) - 8);
3524
3525    return (stateDescription);
3526    }
3527
3528char * IOSerialBSDClient::state2StringPD(UInt32 state)
3529    {
3530    static char stateDescription[1024];
3531
3532    // Nulls the string:
3533    stateDescription[0] = 0;
3534
3535    // reads the state and appends values:
3536    // reads the state and appends values:
3537    if (state & PD_RS232_S_CAR)
3538        strncat(stateDescription, "PD_RS232_S_CAR ", sizeof(stateDescription) - 16);
3539    else
3540        strncat(stateDescription, "^PD_RS232_S_CAR ", sizeof(stateDescription) - 17);
3541
3542    if (state & PD_S_ACQUIRED)
3543    strncat(stateDescription, "PD_S_ACQUIRED ", sizeof(stateDescription) - 16);
3544
3545    if (state & PD_S_ACTIVE)
3546    strncat(stateDescription, "PD_S_ACTIVE ", sizeof(stateDescription) - 13);
3547
3548    if (state & PD_S_TX_ENABLE)
3549    strncat(stateDescription, "PD_S_TX_ENABLE ", sizeof(stateDescription) - 16);
3550
3551    if (state & PD_S_TX_BUSY)
3552    strncat(stateDescription, "PD_S_TX_BUSY ", sizeof(stateDescription) - 14);
3553
3554    if (state & PD_S_TX_EVENT)
3555    strncat(stateDescription, "PD_S_TX_EVENT ", sizeof(stateDescription) - 15);
3556
3557    if (state & PD_S_TXQ_EMPTY)
3558    strncat(stateDescription, "PD_S_TXQ_EMPTY ", sizeof(stateDescription) - 16);
3559
3560    if (state & PD_S_TXQ_LOW_WATER)
3561    strncat(stateDescription, "PD_S_TXQ_LOW_WATER ", sizeof(stateDescription) - 20);
3562
3563    if (state & PD_S_TXQ_HIGH_WATER)
3564    strncat(stateDescription, "PD_S_TXQ_HIGH_WATER ", sizeof(stateDescription) - 21);
3565
3566    if (state & PD_S_TXQ_FULL)
3567    strncat(stateDescription, "PD_S_TXQ_FULL ", sizeof(stateDescription) - 15);
3568
3569    if (state & PD_S_TXQ_MASK)
3570    strncat(stateDescription, "(PD_S_TXQ_MASK) ", sizeof(stateDescription) - 17);
3571
3572    if (state & PD_S_RX_ENABLE)
3573    strncat(stateDescription, "PD_S_RX_ENABLE ", sizeof(stateDescription) - 16);
3574
3575    if (state & PD_S_RX_BUSY)
3576    strncat(stateDescription, "PD_S_RX_BUSY ", sizeof(stateDescription) - 14);
3577
3578    if (state & PD_S_RX_EVENT)
3579    strncat(stateDescription, "PD_S_RX_EVENT ", sizeof(stateDescription) - 15);
3580
3581    if (state & PD_S_RXQ_EMPTY)
3582    strncat(stateDescription, "PD_S_RXQ_EMPTY ", sizeof(stateDescription) - 16);
3583
3584    if (state & PD_S_RXQ_LOW_WATER)
3585    strncat(stateDescription, "PD_S_RXQ_LOW_WATER ", sizeof(stateDescription) - 20);
3586
3587    if (state & PD_S_RXQ_HIGH_WATER)
3588    strncat(stateDescription, "PD_S_RXQ_HIGH_WATER ", sizeof(stateDescription) - 21);
3589
3590    if (state & PD_S_RXQ_FULL)
3591    strncat(stateDescription, "PD_S_RXQ_FULL ", sizeof(stateDescription) - 15);
3592
3593    if (state & PD_S_RXQ_MASK)
3594    strncat(stateDescription, "(PD_S_RXQ_MASK) ", sizeof(stateDescription) - 17);
3595
3596    return (stateDescription);
3597    }
3598
3599char * IOSerialBSDClient::state2StringTTY(UInt32 state)
3600    {
3601    static char stateDescription[2048];
3602
3603    // Nulls the string:
3604    stateDescription[0] = 0;
3605
3606    // reads the state and appends values:
3607    if (state & TS_SO_OLOWAT)
3608    strncat(stateDescription, "TS_SO_OLOWAT ", sizeof(stateDescription) - 14);
3609
3610    if (state & TS_ASYNC)
3611    strncat(stateDescription, "TS_ASYNC ", sizeof(stateDescription) - 10);
3612
3613    if (state & TS_BUSY)
3614    strncat(stateDescription, "TS_BUSY ", sizeof(stateDescription) - 9);
3615
3616    if (state & TS_CARR_ON)
3617    strncat(stateDescription, "TS_CARR_ON ", sizeof(stateDescription) - 12);
3618
3619    if (state & TS_FLUSH)
3620    strncat(stateDescription, "TS_FLUSH ", sizeof(stateDescription) - 10);
3621
3622    if (state & TS_ISOPEN)
3623    strncat(stateDescription, "TS_ISOPEN ", sizeof(stateDescription) - 11);
3624
3625    if (state & TS_TBLOCK)
3626    strncat(stateDescription, "TS_TBLOCK ", sizeof(stateDescription) - 11);
3627
3628    if (state & TS_TIMEOUT)
3629    strncat(stateDescription, "TS_TIMEOUT ", sizeof(stateDescription) - 12);
3630
3631    if (state & TS_TTSTOP)
3632    strncat(stateDescription, "TS_TTSTOP ", sizeof(stateDescription) - 11);
3633
3634    // needs to pull in the notyet definition from tty.h
3635    //if (state & TS_WOPEN)
3636    //strncat(stateDescription, "TS_WOPEN ", sizeof(stateDescription) - 10);
3637
3638    if (state & TS_XCLUDE)
3639    strncat(stateDescription, "TS_XCLUDE ", sizeof(stateDescription) - 11);
3640
3641    if (state & TS_LOCAL)
3642    strncat(stateDescription, "TS_LOCAL ", sizeof(stateDescription) - 10);
3643
3644    if (state & TS_ZOMBIE)
3645    strncat(stateDescription, "TS_ZOMBIE ", sizeof(stateDescription) - 11);
3646
3647    if (state & TS_CONNECTED)
3648    strncat(stateDescription, "TS_CONNECTED ", sizeof(stateDescription) - 14);
3649
3650    if (state & TS_CAN_BYPASS_L_RINT)
3651    strncat(stateDescription, "TS_CAN_BYPASS_L_RINT ", sizeof(stateDescription) - 22);
3652
3653    if (state & TS_SNOOP)
3654    strncat(stateDescription, "TS_SNOOP ", sizeof(stateDescription) - 10);
3655
3656    if (state & TS_SO_OCOMPLETE)
3657    strncat(stateDescription, "TS_SO_OCOMPLETE ", sizeof(stateDescription) - 17);
3658
3659    if (state & TS_CAR_OFLOW)
3660    strncat(stateDescription, "TS_CAR_OFLOW ", sizeof(stateDescription) - 14);
3661
3662    // needs to pull in the notyet definition from tty.h
3663    //if (state & TS_CTS_OFLOW)
3664    //strncat(stateDescription, "TS_CTS_OFLOW ", sizeof(stateDescription) - 14);
3665
3666    // needs to pull in the notyet definition from tty.h
3667    //if (state & TS_DSR_OFLOW)
3668    //strncat(stateDescription, "TS_DSR_OFLOW ", sizeof(stateDescription) - 14);
3669
3670    return (stateDescription);
3671    }
3672#endif
3673