/* io_serial.c Serial port input/output functions This file is part of the Unix driver for Towitoko smartcard readers Copyright (C) 2000 2001 Carlos Prados This version is modified by doz21 to work in a special manner ;) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "../globals.h" #ifdef WITH_CARDREADER #if defined(__HPUX__) #include #endif #include #if defined(__linux__) && !defined(__ANDROID__) #include #endif #if defined(__ANDROID__) #include "../extapi/linux/serial.h" #endif #include "../oscam-time.h" #include "icc_async.h" #include "io_serial.h" #if defined(__APPLE__) #include #endif #define OK 0 #define ERROR 1 #define IO_SERIAL_FILENAME_LENGTH 32 /* * Internal functions declaration */ static int32_t IO_Serial_Bitrate(int32_t bitrate); static bool IO_Serial_WaitToWrite(struct s_reader *reader, uint32_t delay_us, uint32_t timeout_us); static int32_t oscam_sem; void IO_Serial_Ioctl_Lock(struct s_reader *reader, int32_t flag) { if((reader->typ != R_DB2COM1) && (reader->typ != R_DB2COM2)) { return; } if(!flag) { oscam_sem = 0; } else while(oscam_sem != reader->typ) { while(oscam_sem) if(reader->typ == R_DB2COM1) { cs_sleepms(6); } else { cs_sleepms(8); } oscam_sem = reader->typ; cs_sleepms(1); } } bool IO_Serial_DTR_RTS(struct s_reader *reader, int32_t *dtr, int32_t *rts) { const struct s_cardreader *crdr_ops = reader->crdr; if (!crdr_ops) return ERROR; if(crdr_ops->set_DTS_RTS) { return crdr_ops->set_DTS_RTS(reader, dtr, rts); } uint32_t msr; uint32_t mbit; if(dtr) { mbit = TIOCM_DTR; #if defined(TIOCMBIS) && defined(TIOBMBIC) if(ioctl(reader->handle, *dtr ? TIOCMBIS : TIOCMBIC, &mbit) < 0) { return ERROR; } #else if(ioctl(reader->handle, TIOCMGET, &msr) < 0) { return ERROR; } if(*dtr) { msr |= mbit; } else { msr &= ~mbit; } if(ioctl(reader->handle, TIOCMSET, &msr) < 0) { return ERROR; } #endif rdr_log_dbg(reader, D_DEVICE, "Setting %s=%i", "DTR", *dtr); } if(rts) { mbit = TIOCM_RTS; #if defined(TIOCMBIS) && defined(TIOBMBIC) if(ioctl(reader->handle, *rts ? TIOCMBIS : TIOCMBIC, &mbit) < 0) { return ERROR; } #else if(ioctl(reader->handle, TIOCMGET, &msr) < 0) { return ERROR; } if(*rts) { msr |= mbit; } else { msr &= ~mbit; } if(ioctl(reader->handle, TIOCMSET, &msr) < 0) { return ERROR; } #endif rdr_log_dbg(reader, D_DEVICE, "Setting %s=%i", "RTS", *rts); } return OK; } /* * Public functions definition */ bool IO_Serial_SetBitrate(struct s_reader *reader, uint32_t bitrate, struct termios *tio) { /* Set the bitrate */ #if !defined(__linux__) #if !defined(__APPLE__) if(IO_Serial_Bitrate(bitrate) == B0) { rdr_log(reader, "Baudrate %u not supported", bitrate); return ERROR; } else { //no overclocking cfsetospeed(tio, IO_Serial_Bitrate(bitrate)); cfsetispeed(tio, IO_Serial_Bitrate(bitrate)); rdr_log_dbg(reader, D_DEVICE, "standard baudrate: cardmhz=%d mhz=%d -> effective baudrate %u", reader->cardmhz, reader->mhz, bitrate); } #endif #endif /* Set the bitrate */ #if defined(__linux__) //FIXME workaround for Smargo until native mode works if((reader->mhz == reader->cardmhz) && (reader->smargopatch != 1) && IO_Serial_Bitrate(bitrate) != B0) { //no overclocking cfsetospeed(tio, IO_Serial_Bitrate(bitrate)); cfsetispeed(tio, IO_Serial_Bitrate(bitrate)); rdr_log_dbg(reader, D_DEVICE, "standard baudrate: cardmhz=%d mhz=%d -> effective baudrate %u", reader->cardmhz, reader->mhz, bitrate); } else { //over or underclocking /* these structures are only available on linux */ struct serial_struct nuts; // This makes valgrind happy, because it doesn't know what TIOCGSERIAL does // Without this there are lots of misleading errors of type: // "Conditional jump or move depends on uninitialised value(s)" nuts.baud_base = 0; nuts.custom_divisor = 0; ioctl(reader->handle, TIOCGSERIAL, &nuts); int32_t custom_baud_asked = bitrate * reader->mhz / reader->cardmhz; nuts.custom_divisor = (nuts.baud_base + (custom_baud_asked / 2)) / custom_baud_asked; int32_t custom_baud_delivered = nuts.baud_base / nuts.custom_divisor; rdr_log_dbg(reader, D_DEVICE, "custom baudrate: cardmhz=%d mhz=%d custom_baud=%d baud_base=%d divisor=%d -> effective baudrate %d", reader->cardmhz, reader->mhz, custom_baud_asked, nuts.baud_base, nuts.custom_divisor, custom_baud_delivered); int32_t baud_diff = custom_baud_delivered - custom_baud_asked; if(baud_diff < 0) { baud_diff = (-baud_diff); } if(baud_diff > 0.05 * custom_baud_asked) { rdr_log(reader, "WARNING: your card is asking for custom_baudrate = %i, but your configuration can only deliver custom_baudrate = %i", custom_baud_asked, custom_baud_delivered); rdr_log(reader, "You are over- or underclocking, try OSCam when running your reader at normal clockspeed as required by your card, and setting mhz and cardmhz parameters accordingly."); if(nuts.baud_base <= 115200) { rdr_log(reader, "You are probably connecting your reader via a serial port, OSCam has more flexibility switching to custom_baudrates when using an USB->serial converter, preferably based on FTDI chip."); } } nuts.flags &= ~ASYNC_SPD_MASK; nuts.flags |= ASYNC_SPD_CUST; ioctl(reader->handle, TIOCSSERIAL, &nuts); cfsetospeed(tio, IO_Serial_Bitrate(38400)); cfsetispeed(tio, IO_Serial_Bitrate(38400)); } #endif /* Set the bitrate */ #if defined(__APPLE__) if(IO_Serial_Bitrate(bitrate) == B0) { int32_t custom_baud_rate = bitrate * reader->mhz / reader->cardmhz; if(ioctl(reader->handle, IOSSIOSPEED, &custom_baud_rate) < 0) { rdr_log(reader, "Baudrate %u not supported", custom_baud_rate); return ERROR; } else { rdr_log_dbg(reader, D_DEVICE, "custom baudrate: cardmhz=%d mhz=%d -> effective baudrate %u", reader->cardmhz, reader->mhz, custom_baud_rate); } } else { //no overclocking cfsetospeed(tio, IO_Serial_Bitrate(bitrate)); cfsetispeed(tio, IO_Serial_Bitrate(bitrate)); rdr_log_dbg(reader, D_DEVICE, "standard baudrate: cardmhz=%d mhz=%d -> effective baudrate %u", reader->cardmhz, reader->mhz, bitrate); } #endif return OK; } bool IO_Serial_SetParams(struct s_reader *reader, uint32_t bitrate, uint32_t bits, int32_t parity, uint32_t stopbits, int32_t *dtr, int32_t *rts) { struct termios newtio; if(reader->typ == R_INTERNAL) { return ERROR; } memset(&newtio, 0, sizeof(newtio)); if(IO_Serial_SetBitrate(reader, bitrate, & newtio)) { return ERROR; } /* Set the character size */ switch(bits) { case 5: newtio.c_cflag |= CS5; break; case 6: newtio.c_cflag |= CS6; break; case 7: newtio.c_cflag |= CS7; break; case 8: newtio.c_cflag |= CS8; break; } /* Set the parity */ switch(parity) { case PARITY_ODD: newtio.c_cflag |= PARENB; newtio.c_cflag |= PARODD; break; case PARITY_EVEN: newtio.c_cflag |= PARENB; newtio.c_cflag &= ~PARODD; break; case PARITY_NONE: newtio.c_cflag &= ~PARENB; break; } /* Set the number of stop bits */ switch(stopbits) { case 1: newtio.c_cflag &= (~CSTOPB); break; case 2: newtio.c_cflag |= CSTOPB; break; } /* Selects raw (non-canonical) input and output */ newtio.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); newtio.c_oflag &= ~OPOST; #if 1 newtio.c_iflag |= IGNPAR; /* Ignore parity errors!!! Windows driver does so why shouldn't I? */ #endif /* Enable receiver, hang on close, ignore control line */ newtio.c_cflag |= CREAD | HUPCL | CLOCAL; /* Read 1 byte minimun, no timeout specified */ newtio.c_cc[VMIN] = 1; newtio.c_cc[VTIME] = 0; if(IO_Serial_SetProperties(reader, newtio)) { return ERROR; } reader->current_baudrate = bitrate; IO_Serial_Ioctl_Lock(reader, 1); IO_Serial_DTR_RTS(reader, dtr, rts); IO_Serial_Ioctl_Lock(reader, 0); return OK; } bool IO_Serial_SetProperties(struct s_reader *reader, struct termios newtio) { if(reader->typ == R_INTERNAL) { return OK; } if(tcsetattr(reader->handle, TCSANOW, &newtio) < 0) // set terminal attributes. { return ERROR; } int32_t mctl; rdr_log_dbg(reader, D_DEVICE, "Getting readerstatus..."); if(ioctl(reader->handle, TIOCMGET, &mctl) >= 0) // get reader statusbits { mctl &= ~TIOCM_RTS; rdr_log_dbg(reader, D_DEVICE, "Set reader ready to Send"); ioctl(reader->handle, TIOCMSET, &mctl); // set reader ready to send. } else { rdr_log(reader, "WARNING: Cant get readerstatus!"); } return OK; } int32_t IO_Serial_SetParity(struct s_reader *reader, unsigned char parity) { struct termios tio; int32_t current_parity; // Get current parity if(tcgetattr(reader->handle, &tio) != 0) { rdr_log(reader, "ERROR: Could not get current parity, %s (errno=%d %s)", __func__, errno, strerror(errno)); current_parity = 5; // set to unknown (5 is not predefined!) } else { if(((tio.c_cflag) & PARENB) == PARENB) { if(((tio.c_cflag) & PARODD) == PARODD) { current_parity = PARITY_ODD; } else { current_parity = PARITY_EVEN; } } else { current_parity = PARITY_NONE; } } if(current_parity != parity) { rdr_log_dbg(reader, D_IFD, "Setting parity from %s to %s", current_parity == PARITY_ODD ? "Odd" : current_parity == PARITY_NONE ? "None" : current_parity == PARITY_EVEN ? "Even" : "Unknown", parity == PARITY_ODD ? "Odd" : parity == PARITY_NONE ? "None" : parity == PARITY_EVEN ? "Even" : "Invalid"); // Set the parity switch(parity) { case PARITY_ODD: tio.c_cflag |= PARENB; tio.c_cflag |= PARODD; break; case PARITY_EVEN: tio.c_cflag |= PARENB; tio.c_cflag &= ~PARODD; break; case PARITY_NONE: tio.c_cflag &= ~PARENB; break; } if(IO_Serial_SetProperties(reader, tio)) { rdr_log_dbg(reader, D_IFD, "ERROR: could set parity!"); return ERROR; } } return OK; } void IO_Serial_Flush(struct s_reader *reader) { unsigned char b; uint8_t n = 0; tcflush(reader->handle, TCIOFLUSH); struct timeb starttotal, endtotal; struct timeb start, end; cs_ftimeus(&starttotal); endtotal = starttotal; cs_ftimeus(&start); end = start; int64_t gone = 0; while(!IO_Serial_Read(reader, 0, 75000, 1, &b)) // first appears between 9~75ms { n++; cs_ftimeus(&end); gone = comp_timebus(&end, &start); rdr_log_dbg(reader, D_DEVICE, "Flush readed byte Nr %d value %.2x time_us %"PRId64, n, b, gone); cs_ftimeus(&start); // Reset timer end = start; } cs_ftimeus(&endtotal); gone = comp_timebus(&endtotal, &starttotal); rdr_log_dbg(reader, D_DEVICE, "Buffers readed %d bytes total time_us %"PRId64, n, gone); } void IO_Serial_Sendbreak(struct s_reader *reader, int32_t duration) { tcsendbreak(reader->handle, duration / 1000); } bool IO_Serial_Read(struct s_reader *reader, uint32_t delay, uint32_t timeout, uint32_t size, unsigned char *data) { uint32_t count = 0; if(timeout == 0) // General fix for readers not communicating timeout and delay { if(reader->read_timeout != 0) { timeout = reader->read_timeout; } else { timeout = 9999000; } // hope 9999000 is long enough! rdr_log_dbg(reader, D_DEVICE, "Warning: read timeout 0 changed to %d us", timeout); } rdr_log_dbg(reader, D_DEVICE, "Read timeout %d us, read delay %d us, to read %d char(s), chunksize %d char(s)", timeout, delay, size, size); #if defined(WITH_STAPI) || defined(WITH_STAPI5) || defined(__SH4__) //internal stapi and sh4 readers need special treatment as they don't respond correctly to poll and some sh4 boxes only can read 1 byte at once if(reader->typ == R_INTERNAL) { int32_t readed; #if defined(WITH_STAPI) || defined(WITH_STAPI5) const uint32_t chunksize = INT_MAX; #elif defined(__SH4__) const uint32_t chunksize = 1; #endif struct timeb start, end; cs_ftime(&start); end = start; int64_t gone = 0; int32_t timeout_ms = timeout / 1000; readed = 0; while(gone < timeout_ms) { readed = read(reader->handle, &data[count], size - count >= chunksize ? chunksize : size - count); cs_ftime(&end); if(readed > 0) { count += readed; cs_ftime(&start); // Reset timer end = start; } gone = comp_timeb(&end, &start); if(count < size) { if(readed < (int32_t)chunksize) { cs_sleepus(1); } continue; } else { break; } } if(count < size) { rdr_log_dump_dbg(reader, D_DEVICE, data, count, "Receiving:"); return ERROR; } } else #endif // read all chars at once for all other boxes { while(count < size) { int32_t readed = -1, errorcount = 0; AGAIN: if(IO_Serial_WaitToRead(reader, delay, timeout)) { rdr_log_dbg(reader, D_DEVICE, "Timeout in IO_Serial_WaitToRead, timeout=%d us", timeout); return ERROR; } while(readed < 0 && errorcount < 10) { readed = read(reader->handle, &data[count], size - count); if(readed < 0) { if(errno == EINTR) { continue; } // try again in case of interrupt if(errno == EAGAIN) { goto AGAIN; } //EAGAIN needs select procedure again rdr_log(reader, "ERROR: %s (errno=%d %s)", __func__, errno, strerror(errno)); errorcount++; } } if(readed == 0) { rdr_log_dump_dbg(reader, D_DEVICE, data, count, "Receiving:"); rdr_log_dbg(reader, D_DEVICE, "Received End of transmission"); return ERROR; } count += readed; } } rdr_log_dump_dbg(reader, D_DEVICE, data, count, "Receiving:"); return OK; } int32_t IO_Serial_Receive(struct s_reader *reader, unsigned char *buffer, uint32_t size, uint32_t delay, uint32_t timeout) { return IO_Serial_Read(reader, delay, timeout, size, buffer); } bool IO_Serial_Write(struct s_reader *reader, uint32_t delay, uint32_t timeout, uint32_t size, const unsigned char *data) { const struct s_cardreader *crdr_ops = reader->crdr; if (!crdr_ops) return ERROR; if(timeout == 0) // General fix for readers not communicating timeout and delay { if(reader->char_delay != 0) { timeout = reader->char_delay; } else { timeout = 1000000; } rdr_log_dbg(reader, D_DEVICE, "Warning: write timeout 0 changed to %d us", timeout); } uint32_t count, to_send, i_w; unsigned char data_w[MAX_ECM_SIZE]; to_send = (delay ? 1 : size); // calculate chars to send at one rdr_log_dbg(reader, D_DEVICE, "Write timeout %d us, write delay %d us, to send %d char(s), chunksize %d char(s)", timeout, delay, size, to_send); for(count = 0; count < size; count += to_send) { if(count + to_send > size) { to_send = size - count; } uint16_t errorcount = 0, to_do = to_send; for(i_w = 0; i_w < to_send; i_w++) { data_w [i_w] = data [count + i_w]; } rdr_log_dump_dbg(reader, D_DEVICE, data_w + (to_send - to_do), to_do, "Sending:"); AGAIN: if(!IO_Serial_WaitToWrite(reader, delay, timeout)) { while(to_do != 0) { int32_t u = write(reader->handle, data_w + (to_send - to_do), to_do); if(u < 1) { if(errno == EINTR) { continue; } //try again in case of Interrupted system call if(errno == EAGAIN) { goto AGAIN; } //EAGAIN needs a select procedure again errorcount++; int16_t written = count + to_send - to_do; if(u != 0) { rdr_log(reader, "ERROR: %s: Written=%d of %d (errno=%d %s)", __func__, written , size, errno, strerror(errno)); } if(errorcount > 10) //exit if more than 10 errors { return ERROR; } } else { to_do -= u; errorcount = 0; if(crdr_ops->read_written) { reader->written += u; } // these readers echo transmitted chars } } } else { rdr_log(reader, "Timeout in IO_Serial_WaitToWrite, delay=%d us, timeout=%d us", delay, timeout); if(crdr_ops->read_written && reader->written > 0) // these readers need to read all transmitted chars before they can receive! { unsigned char buf[256]; rdr_log_dbg(reader, D_DEVICE, "Reading %d echoed transmitted chars...", reader->written); int32_t n = reader->written; if(IO_Serial_Read(reader, 0, 9990000, n, buf)) // use 9990000 = aprox 10 seconds (since written chars could be hughe!) { return ERROR; } reader->written = 0; rdr_log_dbg(reader, D_DEVICE, "Reading of echoed transmitted chars done!"); } return ERROR; } } if(crdr_ops->read_written && reader->written > 0) // these readers need to read all transmitted chars before they can receive! { unsigned char buf[256]; rdr_log_dbg(reader, D_DEVICE, "Reading %d echoed transmitted chars...", reader->written); int32_t n = reader->written; if(IO_Serial_Read(reader, 0, 9990000, n, buf)) // use 9990000 = aprox 10 seconds (since written chars could be hughe!) { return ERROR; } reader->written = 0; rdr_log_dbg(reader, D_DEVICE, "Reading of echoed transmitted chars done!"); } return OK; } #define MAX_TRANSMIT 255 int32_t IO_Serial_Transmit(struct s_reader *reader, unsigned char *buffer, uint32_t size, uint32_t UNUSED(expectedlen), uint32_t delay, uint32_t timeout) { uint32_t sent, to_send; for(sent = 0; sent < size; sent = sent + to_send) { to_send = MIN(size, MAX_TRANSMIT); if(IO_Serial_Write(reader, delay, timeout , to_send, buffer + sent)) { return ERROR; } } return OK; } int32_t IO_Serial_Close(struct s_reader *reader) { rdr_log_dbg(reader, D_DEVICE, "Closing serial port %s", reader->device); cs_sleepms(100); // maybe a dirty fix for the restart problem posted by wonderdoc if(reader->fdmc >= 0) { close(reader->fdmc); } if(reader->handle >= 0 && close(reader->handle) != 0) { return ERROR; } reader->written = 0; return OK; } /* * Internal functions definition */ static int32_t IO_Serial_Bitrate(int32_t bitrate) { static const struct BaudRates { int32_t real; speed_t apival; } BaudRateTab[] = { #ifdef B230400 { 230400, B230400 }, #endif #ifdef B115200 { 115200, B115200 }, #endif #ifdef B76800 { 76800, B76800 }, #endif #ifdef B57600 { 57600, B57600 }, #endif #ifdef B38400 { 38400, B38400 }, #endif #ifdef B28800 { 28800, B28800 }, #endif #ifdef B19200 { 19200, B19200 }, #endif #ifdef B14400 { 14400, B14400 }, #endif #ifdef B9600 { 9600, B9600 }, #endif #ifdef B7200 { 7200, B7200 }, #endif #ifdef B4800 { 4800, B4800 }, #endif #ifdef B2400 { 2400, B2400 }, #endif #ifdef B1200 { 1200, B1200 }, #endif #ifdef B600 { 600, B600 }, #endif #ifdef B300 { 300, B300 }, #endif #ifdef B200 { 200, B200 }, #endif #ifdef B150 { 150, B150 }, #endif #ifdef B134 { 134, B134 }, #endif #ifdef B110 { 110, B110 }, #endif #ifdef B75 { 75, B75 }, #endif #ifdef B50 { 50, B50 }, #endif }; int32_t i; for(i = 0; i < (int)(sizeof(BaudRateTab) / sizeof(struct BaudRates)); i++) { int32_t b = BaudRateTab[i].real; int32_t d = ((b - bitrate) * 10000) / b; if(abs(d) <= 350) { return BaudRateTab[i].apival; } } return B0; } bool IO_Serial_WaitToRead(struct s_reader *reader, uint32_t delay_us, uint32_t timeout_us) { struct pollfd ufds; struct timeb start, end; int32_t ret_val; int32_t in_fd; int64_t polltimeout = timeout_us / 1000; if(delay_us > 0) { cs_sleepus(delay_us); } // wait in us in_fd = reader->handle; ufds.fd = in_fd; ufds.events = POLLIN | POLLPRI; ufds.revents = 0x0000; cs_ftime(&start); // register start time while(1) { ret_val = poll(&ufds, 1, polltimeout); cs_ftime(&end); // register end time switch(ret_val) { case -1: if(errno == EINTR || errno == EAGAIN) { cs_sleepus(1); if(timeout_us > 0) { polltimeout = (timeout_us / 1000) - comp_timeb(&end, &start); if(polltimeout < 0) { polltimeout = 0; } } continue; } rdr_log(reader, "ERROR: %s: timeout=%"PRId64" ms (errno=%d %s)", __func__, comp_timeb(&end, &start), errno, strerror(errno)); return ERROR; default: if(ufds.revents & (POLLIN | POLLPRI)) { return OK; } else { return ERROR; } } } } static bool IO_Serial_WaitToWrite(struct s_reader *reader, uint32_t delay_us, uint32_t timeout_us) { struct pollfd ufds; struct timeb start, end; int32_t ret_val; int32_t out_fd; int64_t polltimeout = timeout_us / 1000; #if !defined(WITH_COOLAPI) && !defined(WITH_COOLAPI2) if(reader->typ == R_INTERNAL) { return OK; } // needed for internal readers, otherwise error! #endif if(delay_us > 0) { cs_sleepus(delay_us); } // wait in us out_fd = reader->handle; ufds.fd = out_fd; ufds.events = POLLOUT; ufds.revents = 0x0000; cs_ftime(&start); // register start time while(1) { ret_val = poll(&ufds, 1, polltimeout); cs_ftime(&end); // register end time switch(ret_val) { case 0: rdr_log(reader, "ERROR: not ready to write, timeout=%"PRId64" ms", comp_timeb(&end, &start)); return ERROR; case -1: if(errno == EINTR || errno == EAGAIN) { cs_sleepus(1); if(timeout_us > 0) { polltimeout = (timeout_us / 1000) - comp_timeb(&end, &start); if(polltimeout < 0) { polltimeout = 0; } } continue; } rdr_log(reader, "ERROR: %s: timeout=%"PRId64" ms (errno=%d %s)", __func__, comp_timeb(&end, &start), errno, strerror(errno)); return ERROR; default: if(((ufds.revents) & POLLOUT) == POLLOUT) { return OK; } else { return ERROR; } } } } bool IO_Serial_InitPnP(struct s_reader *reader) { uint32_t PnP_id_size = 0; unsigned char PnP_id[IO_SERIAL_PNPID_SIZE]; /* PnP Id of the serial device */ int32_t dtr = IO_SERIAL_HIGH; int32_t cts = IO_SERIAL_LOW; if(IO_Serial_SetParams(reader, 1200, 7, PARITY_NONE, 1, &dtr, &cts)) { return ERROR; } while((PnP_id_size < IO_SERIAL_PNPID_SIZE) && !IO_Serial_Read(reader, 0, 200000, 1, &(PnP_id[PnP_id_size]))) { PnP_id_size++; } return OK; } int32_t IO_Serial_GetStatus(struct s_reader *reader, int32_t *status) { uint32_t modembits = 0; if(ioctl(reader->handle, TIOCMGET, &modembits) == -1) { rdr_log(reader, "ERROR: %s: ioctl(TIOCMGET): %s", __func__, strerror(errno)); return ERROR; } *status = 0; switch(reader->detect & 0x7f) { case 0: *status = modembits & TIOCM_CAR; break; case 1: *status = modembits & TIOCM_DSR; break; case 2: *status = modembits & TIOCM_CTS; break; case 3: *status = modembits & TIOCM_RNG; break; } if(!(reader->detect & 0x80)) { *status = !*status; } return OK; } int32_t IO_Serial_SetBaudrate(struct s_reader *reader, uint32_t baudrate) { rdr_log_dbg(reader, D_IFD, "Setting baudrate to %u", baudrate); // Get current settings struct termios tio; call(tcgetattr(reader->handle, &tio) != 0); // Set new baudrate call(IO_Serial_SetBitrate(reader, baudrate, &tio)); call(IO_Serial_SetProperties(reader, tio)); reader->current_baudrate = baudrate; //so if update fails, reader->current_baudrate is not changed either return OK; } #endif