source: trunk/csctapi/io_serial.c@ 3181

Last change on this file since 3181 was 3181, checked in by dingo35, 10 years ago

Adding threadsafety FIXMEs, feel free to join checking..

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