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