1 /*
2  * Copyright (c) 2001 Tommy Bohlin <tommy@gatespace.com>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 /* unix.c
27  */
28 
29 #include <irda.h>
30 
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <errno.h>
35 #include <stdarg.h>
36 #include <syslog.h>
37 #include <sys/types.h>
38 #include <sys/ioctl.h>
39 #include <sys/time.h>
40 #include <unistd.h>
41 #include <fcntl.h>
42 #include <termios.h>
43 
44 /**********************************************************************
45  * Constants
46  **********************************************************************/
47 
48 #ifdef IRDA_KERNEL_DRIVER
49 
50 static const char id_kernel_framedevice[]="kernel frame device";
51 static const char id_kfdev_inbuffer[]="kernel frame device in buffer";
52 static const char id_kfdev_outbuffer[]="kernel frame device out buffer";
53 
54 static const char* defaultKernelPort = "/dev/irframe0";
55 
56 #endif /* IRDA_KERNEL_DRIVER */
57 
58 /**********************************************************************
59  * Data structures
60  **********************************************************************/
61 
62 typedef struct Memory {
63   struct Memory* next;
64   const char* id;
65   void* ptr;
66   int size;
67 } Memory;
68 
69 typedef struct Timer {
70   struct Timer* next;
71   struct timeval expire;
72   void (*func)(void*);
73   void* handle;
74 } Timer;
75 
76 typedef struct Source {
77   struct Source* next;
78   int fd;
79   void (*func)(void* handle);
80   void* handle;
81 } Source;
82 
83 typedef struct UNIXSerialPort {
84   SerialPort serial;
85   struct UNIXSerialPort* next;
86   int speedMask;
87   int fd;
88   u_char inBuf[1024];
89   int inHead;
90   int inFree;
91   int stopped;
92   u_char outBuf[1024];
93   int outFree;
94 } UNIXSerialPort;
95 
96 #ifdef IRDA_KERNEL_DRIVER
97 
98 typedef struct KernelFrameDevice {
99   FrameDevice frame;
100   char *devname;
101   int fdesc;
102   u_char* inBuf;
103   u_char* outBuf;
104   int maxSize;
105   int maxOutSize;
106   int maxspeed;
107 } KernelFrameDevice;
108 
109 #endif /* IRDA_KERNEL_DRIVER */
110 
111 /**********************************************************************
112  * State
113  **********************************************************************/
114 
115 int                    evtDebug;
116 
117 static bool            sysLog=FALSE;
118 static FILE*           logFile=NULL;
119 
120 static Source*         sources;
121 static UNIXSerialPort* ports;
122 static Timer*          timers;
123 static Memory*         allocs;
124 
125 /**********************************************************************
126  * Support functions
127  **********************************************************************/
128 
addTime(struct timeval * t,int ms)129 static void addTime(struct timeval* t, int ms)
130 {
131   t->tv_sec+=ms/1000;
132   t->tv_usec+=1000*(ms%1000);
133   if(t->tv_usec<0) {
134     t->tv_sec-=1;
135     t->tv_usec+=1000000;
136   } else if(t->tv_usec>=1000000) {
137     t->tv_sec+=1;
138     t->tv_usec-=1000000;
139   }
140 }
141 
cmpTime(const struct timeval * t1,const struct timeval * t2)142 static int cmpTime(const struct timeval* t1, const struct timeval* t2)
143 {
144   long t=t1->tv_sec-t2->tv_sec;
145   return t ? t : t1->tv_usec-t2->tv_usec;
146 }
147 
unlinkTimer(void (* func)(void * handle),void * handle)148 static Timer* unlinkTimer(void (*func)(void* handle), void* handle)
149 {
150   Timer** th=&timers;
151   Timer* t;
152 
153   while((t=*th)) {
154     if(t->func==func && t->handle==handle) {
155       *th=t->next;
156       return t;
157     }
158     th=&t->next;
159   }
160   return 0;
161 }
162 
linkTimer(Timer * e)163 static void linkTimer(Timer* e) {
164   Timer** th=&timers;
165   Timer* t;
166 
167   while((t=*th)) {
168     if(cmpTime(&e->expire,&t->expire)<0) break;
169     th=&t->next;
170   }
171   e->next=*th;
172   *th=e;
173 }
174 
evtRemoveSource(int fd)175 void evtRemoveSource(int fd)
176 {
177   Source** sh=&sources;
178   Source* s;
179 
180   while((s=*sh)) {
181     if(s->fd==fd) {
182       *sh=s->next;
183       free(s);
184       break;
185     }
186     sh=&s->next;
187   }
188 }
189 
evtAddSource(int fd,void (* func)(void * handle),void * handle)190 void evtAddSource(int fd, void (*func)(void* handle), void* handle)
191 {
192   Source* s;
193 
194   evtRemoveSource(fd);
195 
196   s=malloc(sizeof(Source));
197   s->fd=fd;
198   s->func=func;
199   s->handle=handle;
200   s->next=sources;
201   sources=s;
202 }
203 
204 /**********************************************************************
205  * Serial I/O
206  **********************************************************************/
207 
serialSetSpeed(SerialPort * sp,int speed)208 static void serialSetSpeed(SerialPort* sp, int speed) {
209   UNIXSerialPort* usp=(UNIXSerialPort*)sp;
210   struct termios t;
211   int speedcode;
212 
213   if(tcgetattr(usp->fd,&t)) {
214     birda_log("tcgetattr failed\n");
215     return;
216   }
217   switch(speed) {
218   case 115200: speedcode=B115200; break;
219   case 57600:  speedcode=B57600;  break;
220   case 38400:  speedcode=B38400;  break;
221   case 19200:  speedcode=B19200;  break;
222   case 9600:   speedcode=B9600;   break;
223   case 2400:   speedcode=B2400;   break;
224   default:
225     birda_log("unsupported speed\n");
226     return;
227   }
228   cfsetispeed(&t,speedcode);
229   cfsetospeed(&t,speedcode);
230   if(tcsetattr(usp->fd,TCSADRAIN,&t)) {
231     birda_log("tcsetattr failed\n");
232   }
233 }
234 
serialSetLine(SerialPort * sp,int line)235 static void serialSetLine(SerialPort* sp, int line) {
236   UNIXSerialPort* usp=(UNIXSerialPort*)sp;
237   int flags;
238 
239   if(ioctl(usp->fd,TIOCMGET,&flags)==-1) {
240     birda_log("ioctl failed %d\n", __LINE__);
241   }
242 
243   flags&=~(TIOCM_DTR|TIOCM_RTS);
244   if(line&LINE_DTR) flags|=TIOCM_DTR;
245   if(line&LINE_RTS) flags|=TIOCM_RTS;
246 
247   if(ioctl(usp->fd,TIOCMSET,&flags)==-1) {
248     birda_log("ioctl failed %d\n", __LINE__);
249   }
250 }
251 
serialGetSpeedMask(SerialPort * sp)252 static int serialGetSpeedMask(SerialPort* sp)
253 {
254   UNIXSerialPort* usp=(UNIXSerialPort*)sp;
255 
256   return usp->speedMask;
257 }
258 
serialInput(void * sp)259 static void serialInput(void* sp)
260 {
261   UNIXSerialPort* usp=(UNIXSerialPort*)sp;
262   int empty;
263 
264   int k=usp->inHead<=usp->inFree ?
265     sizeof usp->inBuf-usp->inFree : usp->inHead-usp->inFree-1;
266   int n=read(usp->fd,usp->inBuf+usp->inFree,k);
267 
268   if(usp->serial.debug&SP_DEBUG_INPUT) birda_log("serial port read %d bytes\n",n);
269   if(n<=0) return;
270   empty=usp->inHead==usp->inFree;
271   usp->inFree=(usp->inFree+n)%sizeof usp->inBuf;
272   if(((usp->inFree+1)%sizeof usp->inBuf)==usp->inHead) {
273     usp->stopped=1;
274     evtRemoveSource(usp->fd);
275   }
276   if(empty && usp->serial.status)
277     usp->serial.status(&usp->serial, SERIAL_INPUT_AVAILABLE);
278 }
279 
serialGetChar(SerialPort * sp)280 static int serialGetChar(SerialPort* sp)
281 {
282   UNIXSerialPort* usp=(UNIXSerialPort*)sp;
283   int c;
284   int nchars=usp->inFree-usp->inHead;
285   if(nchars<0) nchars+=sizeof usp->inBuf;
286 
287   if(nchars==0) {
288     usp->inHead=usp->inFree=0;
289     return SERIAL_INBUF_EMPTY;
290   }
291   if(usp->stopped && nchars<sizeof usp->inBuf/4) {
292     usp->stopped=0;
293     evtAddSource(usp->fd,serialInput,usp);
294   }
295   c=usp->inBuf[usp->inHead];
296   usp->inHead=(usp->inHead+1)%sizeof usp->inBuf;
297   return c;
298 }
299 
flush(UNIXSerialPort * usp)300 static void flush(UNIXSerialPort* usp)
301 {
302   int n=usp->outFree;
303   int k=0;
304   while(k<n) {
305     int i=write(usp->fd,usp->outBuf+k,n-k);
306     if(i>0) k+=i;
307     else if(i==0 || (errno!=EAGAIN && errno!=EINTR)) break;
308   }
309   usp->outFree=0;
310 }
311 
serialOutput(void * sp)312 static void serialOutput(void* sp)
313 {
314   UNIXSerialPort* usp=(UNIXSerialPort*)sp;
315   if(evtDebug&EVT_DEBUG_TIMERS) birda_log("serialOutput\n");
316   if(usp->outFree>0) flush(usp);
317 }
318 
serialPutChar(SerialPort * sp,int c)319 static void serialPutChar(SerialPort* sp, int c)
320 {
321   UNIXSerialPort* usp=(UNIXSerialPort*)sp;
322 
323   usp->outBuf[usp->outFree++]=c;
324   if(usp->outFree==sizeof usp->outBuf) flush(usp);
325   else evtSetTimer(0,serialOutput,usp);
326 }
327 
serialClose(SerialPort * sp)328 static void serialClose(SerialPort* sp)
329 {
330   UNIXSerialPort* usp=(UNIXSerialPort*)sp;
331   UNIXSerialPort** uh=&ports;
332   UNIXSerialPort* u;
333 
334   while((u=*uh)) {
335     if(u==usp) {
336       *uh=u->next;
337       break;
338     } else {
339       uh=&u->next;
340     }
341   }
342   if(!u) {
343     birda_log("ERROR: closing unallocated UNIX serial port\n");
344     return;
345   }
346 
347   evtCancelTimer(serialOutput,usp);
348   evtRemoveSource(usp->fd);
349   free(usp);
350 }
351 
352 /**********************************************************************
353  * External interface
354  **********************************************************************/
355 
setFileLog(const char * file)356 bool setFileLog(const char* file)
357 {
358   FILE* f=fopen(file,"a");
359 
360   if(!f) return FALSE;
361   logFile=f;
362   return TRUE;
363 }
364 
setSysLog(void)365 void setSysLog(void)
366 {
367   sysLog=TRUE;
368 }
369 
birda_log(const char * fmt,...)370 void birda_log(const char* fmt, ...)
371 {
372   va_list ap;
373 
374   va_start(ap,fmt);
375   if(sysLog) {
376     vsyslog(LOG_INFO,fmt,ap);
377   } else {
378     if(!logFile) logFile=stderr;
379     vfprintf(logFile,fmt,ap);
380     fflush(logFile);
381   }
382   va_end(ap);
383 }
384 
allocMem(const char * id,int size)385 void* allocMem(const char* id, int size)
386 {
387   void* ptr=malloc(size);
388   Memory* m=malloc(sizeof(Memory));
389 
390   if(!ptr || !m) {
391     birda_log("PANIC: malloc failed\n");
392     return 0;
393   }
394 
395   m->ptr=ptr;
396   m->id=id;
397   m->size=size;
398   m->next=allocs;
399   allocs=m;
400 
401   return ptr;
402 }
403 
growMem(void * ptr,int size)404 void* growMem(void* ptr, int size)
405 {
406   Memory* m=allocs;
407   void* nptr;
408 
409   while(m && m->ptr!=ptr) m=m->next;
410   if(!m) {
411     birda_log("ERROR: growing unallocated memory\n");
412     return 0;
413   }
414 
415   nptr=realloc(ptr,size);
416   if(!nptr) {
417     birda_log("PANIC: realloc failed\n");
418     return 0;
419   }
420 
421   m->ptr=nptr;
422   m->size=size;
423 
424   return nptr;
425 }
426 
freeMem(void * ptr)427 void freeMem(void *ptr)
428 {
429   Memory** mh=&allocs;
430   Memory* m;
431 
432   while((m=*mh)) {
433     if(m->ptr==ptr) {
434       *mh=m->next;
435       free(m);
436       free(ptr);
437       return;
438     } else {
439       mh=&m->next;
440     }
441   }
442   birda_log("ERROR: freeing unallocated memory\n");
443 }
444 
showResources(void)445 void showResources(void)
446 {
447   int n,b;
448   Source* s;
449   UNIXSerialPort* u;
450   Timer* t;
451   Memory* m;
452 
453   birda_log("-----------------\n");
454 
455   for(n=0,u=ports;u;u=u->next) n++;
456   birda_log("%d unixSerialPorts\n",n);
457 
458   for(n=0,s=sources;s;s=s->next) if(s->func!=serialInput) n++;
459   birda_log("%d other sources\n",n);
460 
461   for(n=0,t=timers;t;t=t->next) n++;
462   birda_log("%d timers\n",n);
463 
464   birda_log("Memory:\n");
465   for(n=0,b=0,m=allocs;m;m=m->next) {
466     birda_log("  addr=%p size=%5d id=%s\n",m->ptr,m->size,m->id);
467     n++;
468     b+=m->size;
469   }
470   birda_log("  total: %d blocks, %d bytes\n",n,b);
471   birda_log("-----------------\n");
472 }
473 
getRandom(unsigned max)474 unsigned getRandom(unsigned max)
475 {
476   static bool inited=FALSE;
477   unsigned mask;
478 
479   if(max==0) return 0;
480 
481   if(!inited) {
482     struct timeval t;
483     gettimeofday(&t,0);
484     srandom(t.tv_sec^t.tv_usec);
485     inited=TRUE;
486   }
487 
488   for(mask=1;mask<max;) mask=(mask<<1)|1;
489   for(;;) {
490     int val=random()&mask;
491     if(mask&0x80000000) val^=random()<<1;
492     if(val<=max) return val;
493   }
494 }
495 
createSerialPort(const char * dev,int maxspeed)496 SerialPort* createSerialPort(const char* dev, int maxspeed)
497 {
498   int fd;
499   struct termios t;
500   UNIXSerialPort* usp;
501   int speedMask=
502     SPEED_2400|SPEED_9600|SPEED_19200|SPEED_38400|SPEED_57600|SPEED_115200;
503 
504   if(maxspeed>0) {
505     if(maxspeed<115200) speedMask&=~SPEED_115200;
506     if(maxspeed< 57600) speedMask&=~SPEED_57600;
507     if(maxspeed< 38400) speedMask&=~SPEED_38400;
508     if(maxspeed< 19200) speedMask&=~SPEED_19200;
509     if(maxspeed<  9600) return 0;
510   }
511 
512   if((fd=open(dev,O_RDWR|O_NOCTTY|O_NONBLOCK))<0) return 0;
513 
514   t.c_iflag=0;
515   t.c_oflag=0;
516   t.c_cflag=CREAD|CS8|CLOCAL;
517   t.c_lflag=0;
518   t.c_cc[VMIN]=1;
519   t.c_cc[VTIME]=0;
520 
521   cfsetispeed(&t,B9600);
522   cfsetospeed(&t,B9600);
523   if(tcsetattr(fd,TCSANOW,&t) || fcntl(fd,F_SETFL,0)==-1) {
524     close(fd);
525     return 0;
526   }
527 
528   usp=malloc(sizeof(UNIXSerialPort));
529   usp->serial.close=serialClose;
530   usp->serial.setSpeed=serialSetSpeed;
531   usp->serial.setLine=serialSetLine;
532   usp->serial.getSpeedMask=serialGetSpeedMask;
533   usp->serial.getChar=serialGetChar;
534   usp->serial.putChar=serialPutChar;
535   usp->serial.debug=0;
536   usp->serial.handle=0;
537   usp->serial.status=0;
538   usp->speedMask=speedMask;
539   usp->fd=fd;
540 
541   usp->inHead=usp->inFree=0;
542   usp->outFree=0;
543   evtAddSource(usp->fd,serialInput,usp);
544 
545   usp->next=ports;
546   ports=usp;
547 
548   return &usp->serial;
549 }
550 
evtCancelTimer(void (* func)(void *),void * handle)551 void evtCancelTimer(void (*func)(void*), void* handle)
552 {
553   Timer* t=unlinkTimer(func,handle);
554   if(t) free(t);
555 }
556 
evtSetTimer(int delay,void (* func)(void *),void * handle)557 void evtSetTimer(int delay, void (*func)(void*), void* handle)
558 {
559   Timer* t=unlinkTimer(func,handle);
560   if(!t) {
561     t=malloc(sizeof(Timer));
562     t->func=func;
563     t->handle=handle;
564   }
565   gettimeofday(&t->expire,0);
566   addTime(&t->expire,delay);
567   linkTimer(t);
568 }
569 
evtLoop(void)570 void evtLoop(void)
571 {
572   while(timers || sources) {
573     int fdmax;
574     fd_set fds;
575     struct timeval t;
576     Source* s;
577 
578     if(timers) {
579       gettimeofday(&t,0);
580       t.tv_sec=timers->expire.tv_sec-t.tv_sec;
581       t.tv_usec=timers->expire.tv_usec-t.tv_usec;
582       if(t.tv_usec<0) {
583 	t.tv_sec-=1;
584 	t.tv_usec+=1000000;
585       }
586       if(t.tv_sec<0) {
587 	Timer* ti=timers;
588 	timers=ti->next;
589 	if(evtDebug&EVT_DEBUG_TIMERS)
590 	  birda_log("timer called %p %p\n",ti->func,ti->handle);
591 	ti->func(ti->handle);
592 	if(evtDebug&EVT_DEBUG_TIMERS) birda_log("timer completed\n");
593 	free(ti);
594 	continue;
595       }
596     }
597 
598     fdmax=0;
599     FD_ZERO(&fds);
600     for(s=sources;s;s=s->next) {
601       FD_SET(s->fd,&fds);
602       if(fdmax<=s->fd) fdmax=s->fd+1;
603     }
604 
605     if(evtDebug&EVT_DEBUG_SELECT)
606       birda_log("select %s timers\n",timers ? "with" : "without");
607 
608     if(select(fdmax,&fds,0,0,timers ? &t : 0)==-1 && errno!=EINTR)
609       perror("select");
610 
611     if(evtDebug&EVT_DEBUG_SELECT)
612       birda_log("wakeup\n");
613 
614     for(s=sources;s && !FD_ISSET(s->fd,&fds);s=s->next);
615     if(s) s->func(s->handle);
616   }
617 }
618 
619 /**********************************************************************
620  * Kernel frame device support
621  **********************************************************************/
622 
623 #ifdef IRDA_KERNEL_DRIVER
624 
kfd_close(FrameDevice * fd)625 static void kfd_close(FrameDevice* fd)
626 {
627   KernelFrameDevice* kfd = (KernelFrameDevice*)fd;
628   evtRemoveSource(kfd->fdesc);
629   close(kfd->fdesc);
630   freeMem(kfd);
631 }
632 
kfd_setParams(FrameDevice * fd,int baud,int ebofs,int maxSize)633 static int kfd_setParams(FrameDevice* fd, int baud, int ebofs, int maxSize)
634 {
635   KernelFrameDevice* kfd = (KernelFrameDevice*)fd;
636   struct irda_params params;
637   params.speed = baud;
638   params.ebofs = ebofs;
639   params.maxsize = maxSize;
640 
641   if (ioctl(kfd->fdesc, IRDA_SET_PARAMS, &params) == -1) {
642     birda_log("ioctl failed %d\n", __LINE__);
643   }
644 
645   if(kfd->maxSize != maxSize) {
646     kfd->maxSize = maxSize;
647     if (kfd->inBuf)
648       freeMem(kfd->inBuf);
649     kfd->inBuf = kfd->maxSize ? allocMem(id_kfdev_inbuffer, maxSize+2) : 0;
650   }
651 
652   return 0;
653 }
654 
kfd_resetParams(FrameDevice * fd)655 static void kfd_resetParams(FrameDevice* fd)
656 {
657   KernelFrameDevice* kfd = (KernelFrameDevice*)fd;
658 
659   if (ioctl(kfd->fdesc, IRDA_RESET_PARAMS) == -1) {
660     birda_log("ioctl failed %d\n", __LINE__);
661   }
662 }
663 
kfd_sendFrame(FrameDevice * fd,const void * buf0,int len)664 static void kfd_sendFrame(FrameDevice* fd, const void* buf0, int len)
665 {
666   KernelFrameDevice* kfd = (KernelFrameDevice*)fd;
667 #if 0
668   len = createSIRFrame(kfd->ebofs, buf0, len, kfd->outBuf, kfd->maxOutSize);
669   write(kfd->fdesc, kfd->outBuf, len);
670 #else
671   write(kfd->fdesc, buf0, len);
672 #endif
673 }
674 
kfd_getSpeedMask(FrameDevice * fd)675 static int kfd_getSpeedMask(FrameDevice* fd)
676 {
677   KernelFrameDevice* kfd = (KernelFrameDevice*)fd;
678   int maxspeed = kfd->maxspeed;
679   int speedmask;
680 
681   if (ioctl(kfd->fdesc, IRDA_GET_SPEEDMASK, &speedmask) == -1) {
682     birda_log("ioctl failed %d\n", __LINE__);
683   }
684 
685   if(maxspeed>0) {
686     if(maxspeed<16000000) speedmask&=~SPEED_16000000;
687     if(maxspeed<4000000) speedmask&=~SPEED_4000000;
688     if(maxspeed<1152000) speedmask&=~SPEED_1152000;
689     if(maxspeed<576000) speedmask&=~SPEED_576000;
690     if(maxspeed<115200) speedmask&=~SPEED_115200;
691     if(maxspeed< 57600) speedmask&=~SPEED_57600;
692     if(maxspeed< 38400) speedmask&=~SPEED_38400;
693     if(maxspeed< 19200) speedmask&=~SPEED_19200;
694     if(maxspeed<  9600) speedmask&=~SPEED_9600;
695   }
696   return speedmask;
697 }
698 
kfd_getMinTurnaroundMask(FrameDevice * fd)699 static int kfd_getMinTurnaroundMask(FrameDevice* fd)
700 {
701   KernelFrameDevice* kfd = (KernelFrameDevice*)fd;
702   int tamask;
703 
704   if (ioctl(kfd->fdesc, IRDA_GET_TURNAROUNDMASK, &tamask) == -1) {
705     birda_log("ioctl failed %d\n", __LINE__);
706   }
707 
708   return tamask;
709 }
710 
kfd_readFrame(void * handle)711 static void kfd_readFrame(void *handle)
712 {
713   KernelFrameDevice* kfd = (KernelFrameDevice*)handle;
714   ssize_t len = read(kfd->fdesc, kfd->inBuf, (ssize_t)kfd->maxSize);
715   if (len < 0) {
716     perror("kfd_read");
717   }
718   if (len > 0) { /* Must be? */
719     if (kfd->frame.frame)
720       kfd->frame.frame(&kfd->frame, kfd->inBuf, len); /* dev driver skip ck */
721   }
722 }
723 
createKernelFrameDevice(char * dev,int maxspeed)724 FrameDevice* createKernelFrameDevice(char *dev, int maxspeed)
725 {
726   KernelFrameDevice *kfd =
727     allocMem(id_kernel_framedevice, sizeof(KernelFrameDevice));
728 
729   if (!dev) {
730     dev = (char *)defaultKernelPort;
731   }
732   kfd->devname = dev;
733   kfd->maxSize = 4096;
734   kfd->maxspeed = maxspeed;
735 
736   if ((kfd->fdesc = open(kfd->devname, O_RDWR|O_NONBLOCK)) < 0) {
737     freeMem(kfd);
738     birda_log("Cannot open port %s\n", dev);
739     exit(-16);
740   }
741 
742   kfd->frame.close = kfd_close;
743   kfd->frame.setParams = kfd_setParams;
744   kfd->frame.resetParams = kfd_resetParams;
745   kfd->frame.sendFrame = kfd_sendFrame;
746   kfd->frame.getSpeedMask = kfd_getSpeedMask;
747   kfd->frame.getMinTurnaroundMask = kfd_getMinTurnaroundMask;
748   kfd->frame.debug = 0;
749   kfd->frame.handle = 0;
750   kfd->frame.frame = 0;
751 
752   kfd->maxOutSize = 8192;
753   kfd->inBuf = allocMem(id_kfdev_inbuffer, kfd->maxSize+2);
754   kfd->outBuf = allocMem(id_kfdev_outbuffer, kfd->maxOutSize);
755 
756   evtAddSource(kfd->fdesc, kfd_readFrame, kfd);
757 
758   return &kfd->frame;
759 }
760 
761 #endif /* IRDA_KERNEL_DRIVER */
762