source: trunk/csctapi/io_serial.c@ 3953

Last change on this file since 3953 was 3953, checked in by _network, 10 years ago

remove cs_debug_nolf (not threadsafe) and fix some debug messages

File size: 16.8 KB
Line 
1 /*
2 io_serial.c
3 Serial port input/output functions
4
5 This file is part of the Unix driver for Towitoko smartcard readers
6 Copyright (C) 2000 2001 Carlos Prados <cprados@yahoo.com>
7
8 This version is modified by doz21 to work in a special manner ;)
9
10 This library is free software; you can redistribute it and/or
11 modify it under the terms of the GNU Lesser General Public
12 License as published by the Free Software Foundation; either
13 version 2 of the License, or (at your option) any later version.
14
15 This library is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 Lesser General Public License for more details.
19
20 You should have received a copy of the GNU Lesser General Public
21 License along with this library; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23*/
24#include <stdio.h>
25#include <string.h>
26#include <stdlib.h>
27#include <errno.h>
28#ifdef OS_HPUX
29#include <sys/modem.h>
30#endif
31#include <unistd.h>
32#include <sys/stat.h>
33#include <fcntl.h>
34#ifdef HAVE_POLL
35#include <sys/poll.h>
36#else
37#include <sys/signal.h>
38#include <sys/types.h>
39#endif
40#include <sys/time.h>
41#include <sys/ioctl.h>
42#include <time.h>
43
44#ifdef OS_LINUX
45#include <linux/serial.h>
46#endif
47
48#include "../globals.h"
49#include "defines.h"
50#include "io_serial.h"
51#include "mc_global.h"
52#include "icc_async.h"
53
54#define IO_SERIAL_FILENAME_LENGTH 32
55
56/*
57 * Internal functions declaration
58 */
59
60static int IO_Serial_Bitrate(int bitrate);
61
62static bool IO_Serial_WaitToRead (struct s_reader * reader, unsigned delay_ms, unsigned timeout_ms);
63
64static bool IO_Serial_WaitToWrite (struct s_reader * reader, unsigned delay_ms, unsigned timeout_ms);
65
66#if defined(TUXBOX) && defined(PPC)
67void IO_Serial_Ioctl_Lock(struct s_reader * reader, int flag)
68{
69 static int oscam_sem=0;
70 if ((reader->typ != R_DB2COM1) && (reader->typ != R_DB2COM2)) return;
71 if (!flag)
72 oscam_sem=0;
73 else while (oscam_sem!=reader->typ)
74 {
75 while (oscam_sem)
76 if (reader->typ == R_DB2COM1)
77 cs_sleepms(6);
78 else
79 cs_sleepms(8);
80 oscam_sem=reader->typ;
81 cs_sleepms(1);
82 }
83}
84
85static bool IO_Serial_DTR_RTS_dbox2(struct s_reader * reader, int * dtr, int * rts)
86{
87 int rc;
88 unsigned short msr;
89 unsigned int mbit;
90 unsigned short rts_bits[2]={ 0x10, 0x800};
91 unsigned short dtr_bits[2]={0x100, 0};
92 int mcport = (reader->typ == R_DB2COM2);
93
94 if ((rc=ioctl(reader->fdmc, GET_PCDAT, &msr))>=0)
95 {
96 if (dtr) // DTR
97 {
98 cs_debug("IO: multicam.o DTR:%s\n", *dtr ? "set" : "clear"); fflush(stdout);
99 if (dtr_bits[mcport])
100 {
101 if (*dtr)
102 msr&=(unsigned short)(~dtr_bits[mcport]);
103 else
104 msr|=dtr_bits[mcport];
105 rc=ioctl(reader->fdmc, SET_PCDAT, &msr);
106 }
107 else
108 rc=0; // Dummy, can't handle using multicam.o
109 }
110 if (rts) // RTS
111 {
112 cs_debug("IO: multicam.o RTS:%s\n", *rts ? "set" : "clear"); fflush(stdout);
113 if (*rts)
114 msr&=(unsigned short)(~rts_bits[mcport]);
115 else
116 msr|=rts_bits[mcport];
117 rc=ioctl(reader->fdmc, SET_PCDAT, &msr);
118 }
119 }
120 if (rc<0)
121 return ERROR;
122 return OK;
123}
124#endif
125
126bool IO_Serial_DTR_RTS(struct s_reader * reader, int * dtr, int * rts)
127{
128#if defined(TUXBOX) && defined(PPC)
129 if ((reader->typ == R_DB2COM1) || (reader->typ == R_DB2COM2))
130 return(IO_Serial_DTR_RTS_dbox2(reader, dtr, rts));
131#endif
132
133 unsigned int msr;
134 unsigned int mbit;
135
136 if(dtr)
137 {
138 mbit = TIOCM_DTR;
139#if defined(TIOCMBIS) && defined(TIOBMBIC)
140 if (ioctl (reader->handle, *dtr ? TIOCMBIS : TIOCMBIC, &mbit) < 0)
141 return ERROR;
142#else
143 if (ioctl(reader->handle, TIOCMGET, &msr) < 0)
144 return ERROR;
145 if (*dtr)
146 msr|=mbit;
147 else
148 msr&=~mbit;
149 if (ioctl(reader->handle, TIOCMSET, &msr)<0)
150 return ERROR;
151#endif
152 cs_debug("IO: Setting %s=%i","DTR", *dtr);
153 }
154
155 if(rts)
156 {
157 mbit = TIOCM_RTS;
158#if defined(TIOCMBIS) && defined(TIOBMBIC)
159 if (ioctl (reader->handle, *rts ? TIOCMBIS : TIOCMBIC, &mbit) < 0)
160 return ERROR;
161#else
162 if (ioctl(reader->handle, TIOCMGET, &msr) < 0)
163 return ERROR;
164 if (*rts)
165 msr|=mbit;
166 else
167 msr&=~mbit;
168 if (ioctl(reader->handle, TIOCMSET, &msr)<0)
169 return ERROR;
170#endif
171 cs_debug("IO: Setting %s=%i","RTS", *rts);
172 }
173
174 return OK;
175}
176
177/*
178 * Public functions definition
179 */
180
181bool IO_Serial_SetBitrate (struct s_reader * reader, unsigned long bitrate, struct termios * tio)
182{
183 /* Set the bitrate */
184#ifdef OS_LINUX
185 //FIXME workaround for Smargo until native mode works
186 if ((reader->mhz == reader->cardmhz) && (reader->smargopatch != 1) && IO_Serial_Bitrate(bitrate) != B0)
187#else
188 if(IO_Serial_Bitrate(bitrate) == B0)
189 {
190 cs_log("Baudrate %lu not supported", bitrate);
191 return ERROR;
192 }
193 else
194#endif
195 { //no overclocking
196 cfsetospeed(tio, IO_Serial_Bitrate(bitrate));
197 cfsetispeed(tio, IO_Serial_Bitrate(bitrate));
198 cs_debug("standard baudrate: cardmhz=%d mhz=%d -> effective baudrate %lu", reader->cardmhz, reader->mhz, bitrate);
199 }
200#ifdef OS_LINUX
201 else
202 { //over or underclocking
203 /* these structures are only available on linux as fas as we know so limit this code to OS_LINUX */
204 struct serial_struct nuts;
205 ioctl(reader->handle, TIOCGSERIAL, &nuts);
206 int custom_baud_asked = bitrate * reader->mhz / reader->cardmhz;
207 nuts.custom_divisor = (nuts.baud_base + (custom_baud_asked/2))/ custom_baud_asked;
208 int custom_baud_delivered = nuts.baud_base / nuts.custom_divisor;
209 cs_debug("custom baudrate: cardmhz=%d mhz=%d custom_baud=%d baud_base=%d divisor=%d -> effective baudrate %d",
210 reader->cardmhz, reader->mhz, custom_baud_asked, nuts.baud_base, nuts.custom_divisor, custom_baud_delivered);
211 int baud_diff = custom_baud_delivered - custom_baud_asked;
212 if (baud_diff < 0)
213 baud_diff = (-baud_diff);
214 if (baud_diff > 0.05 * custom_baud_asked) {
215 cs_log("WARNING: your card is asking for custom_baudrate = %i, but your configuration can only deliver custom_baudrate = %i",custom_baud_asked, custom_baud_delivered);
216 cs_log("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.");
217 if (nuts.baud_base <= 115200)
218 cs_log("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.");
219 }
220 nuts.flags &= ~ASYNC_SPD_MASK;
221 nuts.flags |= ASYNC_SPD_CUST;
222 ioctl(reader->handle, TIOCSSERIAL, &nuts);
223 cfsetospeed(tio, IO_Serial_Bitrate(38400));
224 cfsetispeed(tio, IO_Serial_Bitrate(38400));
225 }
226#endif
227 return OK;
228}
229
230bool IO_Serial_SetParams (struct s_reader * reader, unsigned long bitrate, unsigned bits, int parity, unsigned stopbits, int dtr, int rts)
231{
232 struct termios newtio;
233
234 if(reader->typ == R_INTERNAL)
235 return ERROR;
236
237 memset (&newtio, 0, sizeof (newtio));
238
239 if (IO_Serial_SetBitrate (reader, bitrate, & newtio))
240 return ERROR;
241
242 /* Set the character size */
243 switch (bits)
244 {
245 case 5:
246 newtio.c_cflag |= CS5;
247 break;
248
249 case 6:
250 newtio.c_cflag |= CS6;
251 break;
252
253 case 7:
254 newtio.c_cflag |= CS7;
255 break;
256
257 case 8:
258 newtio.c_cflag |= CS8;
259 break;
260 }
261
262 /* Set the parity */
263 switch (parity)
264 {
265 case PARITY_ODD:
266 newtio.c_cflag |= PARENB;
267 newtio.c_cflag |= PARODD;
268 break;
269
270 case PARITY_EVEN:
271 newtio.c_cflag |= PARENB;
272 newtio.c_cflag &= ~PARODD;
273 break;
274
275 case PARITY_NONE:
276 newtio.c_cflag &= ~PARENB;
277 break;
278 }
279
280 /* Set the number of stop bits */
281 switch (stopbits)
282 {
283 case 1:
284 newtio.c_cflag &= (~CSTOPB);
285 break;
286 case 2:
287 newtio.c_cflag |= CSTOPB;
288 break;
289 }
290
291 /* Selects raw (non-canonical) input and output */
292 newtio.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
293 newtio.c_oflag &= ~OPOST;
294#if 1
295 newtio.c_iflag |= IGNPAR;
296 /* Ignore parity errors!!! Windows driver does so why shouldn't I? */
297#endif
298 /* Enable receiver, hang on close, ignore control line */
299 newtio.c_cflag |= CREAD | HUPCL | CLOCAL;
300
301 /* Read 1 byte minimun, no timeout specified */
302 newtio.c_cc[VMIN] = 1;
303 newtio.c_cc[VTIME] = 0;
304
305 if (IO_Serial_SetProperties(reader, newtio))
306 return ERROR;
307
308 reader->current_baudrate = bitrate;
309
310 IO_Serial_Ioctl_Lock(reader, 1);
311 IO_Serial_DTR_RTS(reader, &dtr, &rts);
312 IO_Serial_Ioctl_Lock(reader, 0);
313 return OK;
314}
315
316bool IO_Serial_SetProperties (struct s_reader * reader, struct termios newtio)
317{
318 if(reader->typ == R_INTERNAL)
319 return ERROR;
320
321 if (tcsetattr (reader->handle, TCSANOW, &newtio) < 0)
322 return ERROR;
323// tcflush(reader->handle, TCIOFLUSH);
324// if (tcsetattr (reader->handle, TCSAFLUSH, &newtio) < 0)
325// return ERROR;
326
327 int mctl;
328 if (ioctl (reader->handle, TIOCMGET, &mctl) >= 0) {
329 mctl &= ~TIOCM_RTS; //should be mctl |= TIOCM_RTS; for readers with reversed polarity reset
330 ioctl (reader->handle, TIOCMSET, &mctl);
331 }
332 else
333 cs_log("WARNING: Failed to reset reader %s", reader->label);
334
335 cs_debug("IO: Setting properties\n");
336 return OK;
337}
338
339int IO_Serial_SetParity (struct s_reader * reader, BYTE parity)
340{
341 if(reader->typ == R_INTERNAL)
342 return OK;
343
344 if ((parity != PARITY_EVEN) && (parity != PARITY_ODD) && (parity != PARITY_NONE))
345 return ERROR;
346
347 struct termios tio;
348 int current_parity;
349 // Get current parity
350 if (tcgetattr (reader->handle, &tio) != 0)
351 return ERROR;
352
353 if (((tio.c_cflag) & PARENB) == PARENB)
354 {
355 if (((tio.c_cflag) & PARODD) == PARODD)
356 current_parity = PARITY_ODD;
357 else
358 current_parity = PARITY_EVEN;
359 }
360 else
361 {
362 current_parity = PARITY_NONE;
363 }
364
365 cs_debug ("IFD: Setting parity from %s to %s\n",
366 current_parity == PARITY_ODD ? "Odd" :
367 current_parity == PARITY_NONE ? "None" :
368 current_parity == PARITY_EVEN ? "Even" : "Invalid",
369 parity == PARITY_ODD ? "Odd" :
370 parity == PARITY_NONE ? "None" :
371 parity == PARITY_EVEN ? "Even" : "Invalid");
372
373 if (current_parity != parity)
374 {
375
376 // Set the parity
377 switch (parity)
378 {
379 case PARITY_ODD:
380 tio.c_cflag |= PARENB;
381 tio.c_cflag |= PARODD;
382 break;
383
384 case PARITY_EVEN:
385 tio.c_cflag |= PARENB;
386 tio.c_cflag &= ~PARODD;
387 break;
388
389 case PARITY_NONE:
390 tio.c_cflag &= ~PARENB;
391 break;
392 }
393 if (IO_Serial_SetProperties (reader, tio))
394 return ERROR;
395 }
396
397 return OK;
398}
399
400void IO_Serial_Flush (struct s_reader * reader)
401{
402 BYTE b;
403
404 tcflush(reader->handle, TCIOFLUSH);
405 while(!IO_Serial_Read(reader, 1000, 1, &b));
406}
407
408void IO_Serial_Sendbreak(struct s_reader * reader, int duration)
409{
410 tcsendbreak (reader->handle, duration);
411}
412
413bool IO_Serial_Read (struct s_reader * reader, unsigned timeout, unsigned size, BYTE * data)
414{
415 BYTE c;
416 uint count = 0;
417#ifdef SH4
418 bool readed;
419 struct timeval tv, tv_spent;
420#endif
421
422 if((reader->typ != R_INTERNAL) && (reader->written>0))
423 {
424 BYTE buf[256];
425 int n = reader->written;
426 reader->written = 0;
427
428 if(IO_Serial_Read (reader, timeout, n, buf))
429 return ERROR;
430 }
431
432 for (count = 0; count < size ; count++)
433 {
434#ifdef SH4
435 gettimeofday(&tv,0);
436 memcpy(&tv_spent,&tv,sizeof(struct timeval));
437 readed=FALSE;
438 while( (((tv_spent.tv_sec-tv.tv_sec)*1000) + ((tv_spent.tv_usec-tv.tv_usec)/1000L))<timeout )
439 {
440 if (read (reader->handle, &c, 1) == 1)
441 {
442 readed=TRUE;
443 break;
444 }
445 gettimeofday(&tv_spent,0);
446 }
447 if(!readed) {
448 cs_ddump(data, count, "IO: Receiving:");
449 return ERROR;
450 }
451#else
452 if (!IO_Serial_WaitToRead (reader, 0, timeout))
453 {
454 if (read (reader->handle, &c, 1) != 1)
455 {
456 cs_ddump(data, count, "IO: Receiving:");
457 cs_log("ERROR in IO_Serial_Read errno=%d", errno);
458 tcflush (reader->handle, TCIFLUSH);
459 return ERROR;
460 }
461 }
462 else
463 {
464 cs_ddump(data, count, "IO: Receiving:");
465 cs_debug("TIMEOUT in IO_Serial_Read");
466 tcflush (reader->handle, TCIFLUSH);
467 return ERROR;
468 }
469#endif
470 data[count] = c;
471 }
472 cs_ddump(data, count, "IO: Receiving:");
473 return OK;
474}
475
476bool IO_Serial_Write (struct s_reader * reader, unsigned delay, unsigned size, const BYTE * data)
477{
478 unsigned count, to_send, i_w;
479 BYTE data_w[512];
480
481 /* Discard input data from previous commands */
482// tcflush (reader->handle, TCIFLUSH);
483
484 for (count = 0; count < size; count += to_send)
485 {
486// if(reader->typ == R_INTERNAL)
487// to_send = 1;
488// else
489 to_send = (delay? 1: size);
490
491 if (!IO_Serial_WaitToWrite (reader, delay, 1000))
492 {
493 for (i_w=0; i_w < to_send; i_w++)
494 data_w [i_w] = data [count + i_w];
495 unsigned int u = write (reader->handle, data_w, to_send);
496 if (u != to_send)
497 {
498 cs_log("ERROR in IO_Serial_Write u=%d to_send=%d errno=%d", u, to_send, errno);
499 if(reader->typ != R_INTERNAL)
500 reader->written += u;
501 tcflush (reader->handle, TCIFLUSH);
502 return ERROR;
503 }
504
505 if(reader->typ != R_INTERNAL)
506 reader->written += to_send;
507
508 cs_ddump (data_w+count, to_send, "IO: Sending: ");
509 }
510 else
511 {
512 cs_log("TIMEOUT in IO_Serial_Write");
513 tcflush (reader->handle, TCIFLUSH);
514 return ERROR;
515 }
516 }
517 return OK;
518}
519
520bool IO_Serial_Close (struct s_reader * reader)
521{
522
523 cs_debug ("IO: Closing serial port %s\n", reader->device);
524
525#if defined(TUXBOX) && defined(PPC)
526 close(reader->fdmc);
527#endif
528 if (close (reader->handle) != 0)
529 return ERROR;
530
531 reader->written = 0;
532
533 return OK;
534}
535
536/*
537 * Internal functions definition
538 */
539
540static int IO_Serial_Bitrate(int bitrate)
541{
542 static const struct BaudRates { int real; speed_t apival; } BaudRateTab[] = {
543#ifdef B230400
544 { 230400, B230400 },
545#endif
546#ifdef B115200
547 { 115200, B115200 },
548#endif
549#ifdef B76800
550 { 76800, B76800 },
551#endif
552#ifdef B57600
553 { 57600, B57600 },
554#endif
555#ifdef B38400
556 { 38400, B38400 },
557#endif
558#ifdef B28800
559 { 28800, B28800 },
560#endif
561#ifdef B19200
562 { 19200, B19200 },
563#endif
564#ifdef B14400
565 { 14400, B14400 },
566#endif
567#ifdef B9600
568 { 9600, B9600 },
569#endif
570#ifdef B7200
571 { 7200, B7200 },
572#endif
573#ifdef B4800
574 { 4800, B4800 },
575#endif
576#ifdef B2400
577 { 2400, B2400 },
578#endif
579#ifdef B1200
580 { 1200, B1200 },
581#endif
582#ifdef B600
583 { 600, B600 },
584#endif
585#ifdef B300
586 { 300, B300 },
587#endif
588#ifdef B200
589 { 200, B200 },
590#endif
591#ifdef B150
592 { 150, B150 },
593#endif
594#ifdef B134
595 { 134, B134 },
596#endif
597#ifdef B110
598 { 110, B110 },
599#endif
600#ifdef B75
601 { 75, B75 },
602#endif
603#ifdef B50
604 { 50, B50 },
605#endif
606 };
607
608 int i;
609
610 for(i=0; i<(int)(sizeof(BaudRateTab)/sizeof(struct BaudRates)); i++)
611 {
612 int b=BaudRateTab[i].real;
613 int d=((b-bitrate)*10000)/b;
614 if(abs(d)<=350)
615 {
616 return BaudRateTab[i].apival;
617 }
618 }
619 return B0;
620}
621
622static bool IO_Serial_WaitToRead (struct s_reader * reader, unsigned delay_ms, unsigned timeout_ms)
623{
624 fd_set rfds;
625 fd_set erfds;
626 struct timeval tv;
627 int select_ret;
628 int in_fd;
629
630 if (delay_ms > 0)
631 cs_sleepms (delay_ms);
632
633 in_fd=reader->handle;
634
635 FD_ZERO(&rfds);
636 FD_SET(in_fd, &rfds);
637
638 FD_ZERO(&erfds);
639 FD_SET(in_fd, &erfds);
640
641 tv.tv_sec = timeout_ms/1000;
642 tv.tv_usec = (timeout_ms % 1000) * 1000L;
643 select_ret = select(in_fd+1, &rfds, NULL, &erfds, &tv);
644 if(select_ret==-1)
645 {
646 cs_log("ERROR in IO_Serial_WaitToRead: select_ret=%i, errno=%d", select_ret, errno);
647 if (errno==4) {
648 //FIXME
649 // try again in case of Interrupted system call
650 select_ret = select(in_fd+1, &rfds, NULL, &erfds, &tv);
651 if(select_ret==-1) {
652 cs_log("ERROR in IO_Serial_WaitToRead(2): select_ret=%i, errno=%d", select_ret, errno);
653 return ERROR;
654 }
655
656 } else
657 return ERROR;
658 }
659
660 if (FD_ISSET(in_fd, &erfds))
661 {
662 cs_log("ERROR in IO_Serial_WaitToRead: fd is in error fds, errno=%d", errno);
663 return ERROR;
664 }
665 if (FD_ISSET(in_fd,&rfds))
666 return OK;
667 else
668 return ERROR;
669}
670
671static bool IO_Serial_WaitToWrite (struct s_reader * reader, unsigned delay_ms, unsigned timeout_ms)
672{
673 fd_set wfds;
674 fd_set ewfds;
675 struct timeval tv;
676 int select_ret;
677 int out_fd;
678
679#ifdef SCI_DEV
680 if(reader->typ == R_INTERNAL)
681 return OK;
682#endif
683
684 if (delay_ms > 0)
685 cs_sleepms(delay_ms);
686
687 out_fd=reader->handle;
688
689 FD_ZERO(&wfds);
690 FD_SET(out_fd, &wfds);
691
692 FD_ZERO(&ewfds);
693 FD_SET(out_fd, &ewfds);
694
695 tv.tv_sec = timeout_ms/1000L;
696 tv.tv_usec = (timeout_ms % 1000) * 1000L;
697
698 select_ret = select(out_fd+1, NULL, &wfds, &ewfds, &tv);
699
700 if(select_ret==-1)
701 {
702 cs_log("ERROR in IO_Serial_WaitToWrite: select_ret=%i, errno=%d", select_ret, errno);
703 return ERROR;
704 }
705
706 if (FD_ISSET(out_fd, &ewfds))
707 {
708 cs_log("ERROR in IO_Serial_WaitToWrite: fd is in error fds, errno=%d", errno);
709 return ERROR;
710 }
711
712 if (FD_ISSET(out_fd,&wfds))
713 return OK;
714 else
715 return ERROR;
716}
717
718bool IO_Serial_InitPnP (struct s_reader * reader)
719{
720 unsigned int PnP_id_size = 0;
721 BYTE PnP_id[IO_SERIAL_PNPID_SIZE]; /* PnP Id of the serial device */
722
723 if (IO_Serial_SetParams (reader, 1200, 7, PARITY_NONE, 1, IO_SERIAL_HIGH, IO_SERIAL_LOW))
724 return ERROR;
725
726 while ((PnP_id_size < IO_SERIAL_PNPID_SIZE) && !IO_Serial_Read (reader, 200, 1, &(PnP_id[PnP_id_size])))
727 PnP_id_size++;
728
729 return OK;
730}
Note: See TracBrowser for help on using the repository browser.