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