1 /* 2 * Copyright 2002, Jack Burton. 3 * Copyright 2002, Marcus Overhagen. 4 * All rights reserved. 5 * Distributed under the terms of the MIT License. 6 */ 7 8 #include <Directory.h> 9 #include <Entry.h> 10 #include <List.h> 11 #include <SerialPort.h> 12 13 #include <errno.h> 14 #include <fcntl.h> 15 #include <malloc.h> 16 #include <stdio.h> 17 #include <string.h> 18 #include <unistd.h> 19 #include <termios.h> 20 21 /* The directory where the serial driver publishes its devices */ 22 #define SERIAL_DIR "/dev/ports" 23 24 25 /* Creates and initializes a BSerialPort object, */ 26 /* query the driver, and builds a list of available */ 27 /* serial ports. */ 28 29 /* The BSerialPort object is initialized to these */ 30 /* values: */ 31 /* 19200 BPS, */ 32 /* 8 Data Bits, */ 33 /* 1 Stop Bit, */ 34 /* No Parity, */ 35 /* Hardware Flow Control, */ 36 /* Infinite Timeout */ 37 /* and Blocking mode. */ 38 BSerialPort::BSerialPort() 39 : ffd(-1), 40 fBaudRate(B_19200_BPS), 41 fDataBits(B_DATA_BITS_8), 42 fStopBits(B_STOP_BIT_1), 43 fParityMode(B_NO_PARITY), 44 fFlow(B_HARDWARE_CONTROL), 45 fTimeout(B_INFINITE_TIMEOUT), 46 fBlocking(true), 47 _fDevices(new BList) 48 { 49 ScanDevices(); 50 } 51 52 53 /* Closes the port, if it's open, and deletes the devices list */ 54 BSerialPort::~BSerialPort() 55 { 56 if (ffd > 0) 57 close(ffd); 58 59 for (int32 count = _fDevices->CountItems() - 1; count >= 0; count--) 60 free(_fDevices->RemoveItem(count)); 61 62 delete _fDevices; 63 } 64 65 66 /* Opens a serial port. @param a valid port name */ 67 status_t 68 BSerialPort::Open(const char *portName) 69 { 70 char buf[64]; 71 72 //TODO: Check if portName is a valid name 73 sprintf(buf, SERIAL_DIR"/%s", portName); 74 75 if (ffd > 0) //If this port is already open, close it 76 close(ffd); 77 78 ffd = open(buf, O_RDWR|O_NONBLOCK); //R5 seem to use this mask 79 80 if (ffd > 0) 81 DriverControl(); //Setup the port 82 83 return (ffd < 0) ? ffd : B_OK; 84 } 85 86 87 /* Closes the port */ 88 void 89 BSerialPort::Close(void) 90 { 91 if (ffd > 0) 92 close(ffd); 93 ffd = -1; 94 } 95 96 97 /* Read some data from the serial port. */ 98 /* @param the buffer where to transfer the data */ 99 /* @param how many bytes to read */ 100 ssize_t 101 BSerialPort::Read(void *buf, size_t count) 102 { 103 if (ffd < 0) // We have no open port 104 return B_FILE_ERROR; 105 106 return read(ffd, buf, count); 107 } 108 109 110 /* Write some data to the serial port. */ 111 /* @param the buffer from which transfer the data */ 112 /* @param how many bytes to write */ 113 ssize_t 114 BSerialPort::Write(const void *buf, size_t count) 115 { 116 if (ffd < 0) // We have no open port 117 return B_FILE_ERROR; 118 119 return write(ffd, buf, count); 120 } 121 122 123 /* Set blocking mode */ 124 void 125 BSerialPort::SetBlocking(bool Blocking) 126 { 127 fBlocking = Blocking; 128 DriverControl(); 129 } 130 131 132 /* Set the timeout for the port */ 133 /* Valid values: B_INFINITE_TIMEOUT or any value between 0 and 25000000 */ 134 status_t 135 BSerialPort::SetTimeout(bigtime_t microSeconds) 136 { 137 status_t err = B_BAD_VALUE; 138 139 if (microSeconds == B_INFINITE_TIMEOUT || microSeconds <= 25000000) 140 { 141 fTimeout = microSeconds; 142 DriverControl(); 143 err = B_OK; 144 } 145 return err; 146 } 147 148 149 /* Set the data rate (Baud rate) for the port */ 150 status_t 151 BSerialPort::SetDataRate(data_rate bitsPerSecond) 152 { 153 fBaudRate = bitsPerSecond; 154 155 return DriverControl(); 156 } 157 158 159 /* Get the data rate (Baud Rate) */ 160 data_rate 161 BSerialPort::DataRate(void) 162 { 163 return fBaudRate; 164 } 165 166 167 /* Set the data bits (7 or 8) */ 168 void 169 BSerialPort::SetDataBits(data_bits numBits) 170 { 171 fDataBits = numBits; 172 DriverControl(); 173 } 174 175 176 /* Get the data bits */ 177 data_bits 178 BSerialPort::DataBits(void) 179 { 180 return fDataBits; 181 } 182 183 184 /* Set the stop bits (1 or 2) */ 185 void 186 BSerialPort::SetStopBits(stop_bits numBits) 187 { 188 fStopBits = numBits; 189 DriverControl(); 190 } 191 192 193 /* Get the stop bits */ 194 stop_bits 195 BSerialPort::StopBits(void) 196 { 197 return fStopBits; 198 } 199 200 201 /* Set the parity mode (ODD, PAIR, or NONE) */ 202 void 203 BSerialPort::SetParityMode(parity_mode which) 204 { 205 fParityMode = which; 206 DriverControl(); 207 } 208 209 210 /* Get the parity mode */ 211 parity_mode 212 BSerialPort::ParityMode(void) 213 { 214 return fParityMode; 215 } 216 217 218 /* Clear the input buffer */ 219 void 220 BSerialPort::ClearInput(void) 221 { 222 tcflush(ffd, TCIFLUSH); 223 } 224 225 226 /* Clear the output buffer */ 227 void 228 BSerialPort::ClearOutput(void) 229 { 230 tcflush(ffd, TCOFLUSH); 231 } 232 233 234 /* Set the flow control (HARDWARE, SOFTWARE, or NONE) */ 235 void 236 BSerialPort::SetFlowControl(uint32 method) 237 { 238 fFlow = method; 239 DriverControl(); 240 } 241 242 243 /* Get the flow control */ 244 uint32 245 BSerialPort::FlowControl(void) 246 { 247 return fFlow; 248 } 249 250 251 /* Set the DTR */ 252 status_t 253 BSerialPort::SetDTR(bool asserted) 254 { 255 status_t status = ioctl(ffd, TCSETDTR, &asserted); 256 257 return (status > 0) ? status : errno; 258 } 259 260 261 /* Set the RTS status */ 262 status_t 263 BSerialPort::SetRTS(bool asserted) 264 { 265 status_t status = ioctl(ffd, TCSETRTS, &asserted); 266 267 return (status > 0) ? status : errno; 268 } 269 270 271 /* See how many chars are queued on the serial port, */ 272 /* waiting to be read */ 273 status_t 274 BSerialPort::NumCharsAvailable(int32 *wait_until_this_many) 275 { 276 //No help from the BeBook... 277 if (ffd < 0) 278 return B_ERROR; 279 280 //TODO: Implement 281 return B_OK; 282 } 283 284 285 /* See if CTS is set */ 286 bool 287 BSerialPort::IsCTS(void) 288 { 289 unsigned int bits = ioctl(ffd, TCGETBITS, 0); 290 291 if (bits & TCGB_CTS) 292 return true; 293 294 return false; 295 } 296 297 298 /* See if DSR is set */ 299 bool 300 BSerialPort::IsDSR(void) 301 { 302 unsigned int bits = ioctl(ffd, TCGETBITS, 0); 303 304 if (bits & TCGB_DSR) 305 return true; 306 307 return false; 308 } 309 310 311 /* See if RI is set */ 312 bool 313 BSerialPort::IsRI(void) 314 { 315 unsigned int bits = ioctl(ffd, TCGETBITS, 0); 316 317 if (bits & TCGB_RI) 318 return true; 319 320 return false; 321 } 322 323 324 /* See if DCD is set */ 325 bool 326 BSerialPort::IsDCD(void) 327 { 328 unsigned int bits = ioctl(ffd, TCGETBITS, 0); 329 330 if (bits & TCGB_DCD) 331 return true; 332 333 return false; 334 } 335 336 337 /* Wait until there's something to read from the serial port. */ 338 /* If no data is ready, it will always block, ignoring the */ 339 /* value of SetBlocking(); however, it respects the timeout */ 340 /* set by SetTimeout(). */ 341 ssize_t 342 BSerialPort::WaitForInput(void) 343 { 344 ssize_t size; 345 int err = ioctl(ffd, TCWAITEVENT, &size, sizeof size); 346 347 return (err < B_OK) ? errno : size; 348 } 349 350 351 /* Returns the number of available Serial Ports. */ 352 int32 353 BSerialPort::CountDevices() 354 { 355 int32 count = 0; 356 357 if (_fDevices != NULL) 358 count = _fDevices->CountItems(); 359 360 return count; 361 } 362 363 364 /* Get the device name for the given device.*/ 365 /* The first parameter is the number of the device */ 366 /* you want to know the name, the second is the buffer */ 367 /* where you want to store the name, and the third is */ 368 /* the length of that buffer. */ 369 status_t 370 BSerialPort::GetDeviceName(int32 n, char *name, size_t bufSize) 371 { 372 status_t result = B_ERROR; 373 char *dev = NULL; 374 375 if (_fDevices != NULL) 376 dev = static_cast<char*>(_fDevices->ItemAt(n)); 377 378 if (dev != NULL && name != NULL) { 379 strncpy(name, dev, bufSize); 380 result = B_OK; 381 } 382 return result; 383 } 384 385 386 /* Private or Reserved */ 387 388 /* Query the serial driver about the available devices, */ 389 /* and build a list of them. */ 390 void 391 BSerialPort::ScanDevices() 392 { 393 BEntry entry; 394 BDirectory dir(SERIAL_DIR); 395 char buf[B_OS_NAME_LENGTH]; 396 397 //First, we empty the list 398 for (int32 count = _fDevices->CountItems() - 1; count >= 0; count--) 399 free(_fDevices->RemoveItem(count)); 400 401 //Then, add the devices to the list 402 while (dir.GetNextEntry(&entry) == B_OK) 403 { 404 entry.GetName(buf); 405 _fDevices->AddItem(strdup(buf)); 406 }; 407 } 408 409 410 /* Send the options to the serial driver. */ 411 /* Returns B_OK if all goes fine, an error code */ 412 /* if something goes wrong. */ 413 int 414 BSerialPort::DriverControl() 415 { 416 struct termio termioControl; 417 int err; 418 419 if (ffd < 0) 420 return B_NO_INIT; 421 422 //Load the current settings 423 err = ioctl(ffd, TCGETA, &termioControl); 424 if (err < 0) 425 return errno; 426 427 // Reset all flags 428 termioControl.c_cflag &= ~(CRTSCTS | CSIZE | CBAUD | CSTOPB | PARODD | PARENB); 429 termioControl.c_iflag &= ~(IXON | IXOFF | IXANY | INPCK); 430 termioControl.c_lflag &= ~(ECHO | ECHONL | ISIG | ICANON); 431 432 //Set the flags to the wanted values 433 if (fFlow & B_HARDWARE_CONTROL) 434 termioControl.c_cflag |= CRTSCTS; 435 436 if (fFlow & B_SOFTWARE_CONTROL) 437 termioControl.c_iflag |= (IXON | IXOFF); 438 439 if (fStopBits & B_STOP_BITS_2) 440 termioControl.c_cflag |= CSTOPB; // We want 2 stop bits 441 442 if (fDataBits == B_DATA_BITS_8) 443 termioControl.c_cflag |= CS8; // We want 8 data bits 444 445 //Ok, set the parity now 446 if (fParityMode != B_NO_PARITY) 447 { 448 termioControl.c_cflag |= PARENB; //Enable parity 449 if (fParityMode == B_ODD_PARITY) 450 termioControl.c_cflag |= PARODD; //Select odd parity 451 } 452 453 //Set the baud rate 454 termioControl.c_cflag |= (fBaudRate & CBAUD); 455 456 //Set the timeout 457 if (fBlocking) 458 { 459 if (fTimeout == B_INFINITE_TIMEOUT) 460 { 461 termioControl.c_cc[VTIME] = 0; 462 termioControl.c_cc[VMIN] = 1; 463 } 464 else if (fTimeout == 0) 465 termioControl.c_cc[VMIN] = 0; 466 else 467 { 468 int t = fTimeout / 100000; 469 termioControl.c_cc[VTIME] = (t == 0) ? 1 : t; 470 termioControl.c_cc[VMIN] = 1; 471 } 472 } else 473 termioControl.c_cc[VMIN] = 0; 474 475 //Ok, finished. Now tell the driver what we decided 476 err = ioctl(ffd, TCSETA, &termioControl); 477 478 return err > 0 ? err : errno; 479 } 480 481 482 /* These functions are here to maintain Binary Compatibility */ 483 void BSerialPort::_ReservedSerialPort1() {} 484 void BSerialPort::_ReservedSerialPort2() {} 485 void BSerialPort::_ReservedSerialPort3() {} 486 void BSerialPort::_ReservedSerialPort4() {} 487