includes: AROS_UFIxx -> AROS_INTxx change
[AROS.git] / arch / all-unix / hidd / serial / SerialUnitClass.c
blob571e86b3d84e105fad95284e8f0c5f905be894b6
1 /*
2 Copyright © 1995-2006, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Serial Unit hidd class implementation.
6 Lang: english
7 */
9 /* Some POSIX includes */
10 #include <stdio.h>
11 #include <termios.h>
12 #include <unistd.h>
14 #include "unix_funcs.h"
17 /* the rest are Amiga includes */
18 #define timeval aros_timeval
19 #include <proto/exec.h>
20 #include <proto/utility.h>
21 #include <proto/oop.h>
22 #include <proto/alib.h>
23 #include <proto/intuition.h>
24 #include <exec/libraries.h>
25 #include <exec/ports.h>
26 #include <exec/memory.h>
27 #include <exec/interrupts.h>
28 #include <exec/lists.h>
30 #include <utility/tagitem.h>
31 #include <hidd/serial.h>
32 #include <hidd/unixio.h>
33 #include <hidd/unixio_inline.h>
35 #include <devices/serial.h>
36 #include <intuition/preferences.h>
38 #include <aros/symbolsets.h>
41 #include "serial_intern.h"
43 #include LC_LIBDEFS_FILE
44 #undef timeval
46 #undef SDEBUG
47 #undef DEBUG
48 #define SDEBUG 0
49 #define DEBUG 0
50 #include <aros/debug.h>
52 void serialunit_receive_data();
53 void serialunit_write_more_data();
55 /* Some utility functions */
56 static void settermios(struct HIDDSerialUnitData * data);
57 static void adapt_termios(struct termios * termios,
58 struct Preferences * prefs);
60 static char * unitname[] =
62 "/dev/ttyS0",
63 "/dev/ttyS1",
64 "/dev/ttyS2",
65 "/dev/ttyS3"
68 /*************************** Classes *****************************/
70 /******* SerialUnit::New() ***********************************/
71 OOP_Object *UXSerUnit__Root__New(OOP_Class *cl, OOP_Object *obj, struct pRoot_New *msg)
73 struct HIDDSerialUnitData * data;
74 #if 0
75 static const struct TagItem tags[] = {{ TAG_END, 0}};
76 #endif
77 struct TagItem *tag, *tstate;
78 ULONG unitnum = 0;
80 EnterFunc(bug("SerialUnit::New()\n"));
81 D(bug("SerialUnit created on %s at %s.\n",__DATE__,__TIME__));
83 tstate = msg->attrList;
84 while ((tag = NextTagItem(&tstate)))
86 ULONG idx;
88 #define csd CSD(cl)
89 if (IS_HIDDSERIALUNIT_ATTR(tag->ti_Tag, idx))
90 #undef csd
92 switch (idx)
94 case aoHidd_SerialUnit_Unit:
95 unitnum = (ULONG)tag->ti_Data;
96 break;
100 } /* while (tags to process) */
102 D(bug("!!!!Request for unit number %d\n",unitnum));
104 obj = (OOP_Object *)OOP_DoSuperMethod(cl, obj, (OOP_Msg)msg);
106 if (obj)
108 struct termios _termios;
109 const struct TagItem tags[] = {
110 {aHidd_UnixIO_Opener , (IPTR)"serial.hidd"},
111 {aHidd_UnixIO_Architecture, (IPTR)AROS_ARCHITECTURE},
112 {TAG_END}
115 data = OOP_INST_DATA(cl, obj);
117 data->unitnum = unitnum;
119 data->unixio = OOP_NewObject(NULL, CLID_Hidd_UnixIO, (struct TagItem *)tags);
120 if (!data->unixio) {
121 OOP_DisposeObject(obj);
122 obj = NULL;
123 goto exit;
126 D(bug("Opening %s.\n",unitname[data->unitnum]));
128 data->filedescriptor = Hidd_UnixIO_OpenFile(data->unixio, unitname[data->unitnum], O_NONBLOCK|O_RDWR, 0, NULL);
130 D(bug("Opened %s on handle %d\n",unitname[data->unitnum], data->filedescriptor));
132 if (-1 != data->filedescriptor)
134 struct IntuitionBase * IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",0);
136 #if 0
138 ** Configure the tty driver
140 tcgetattr(data->filedescriptor, &data->orig_termios);
141 tcgetattr(data->filedescriptor, &_termios);
142 cfmakeraw(&_termios);
143 #endif
146 * Get the preferences information from intuition library.
147 * If intuition could not be opened (?) then I will just
148 * use the default termios.
150 if (NULL != IntuitionBase) {
151 struct Preferences prefs;
152 GetPrefs(&prefs,sizeof(prefs));
153 data->baudrate = prefs.BaudRate;
154 adapt_termios(&_termios, &prefs);
155 CloseLibrary((struct Library *)IntuitionBase);
156 } else {
157 // data->baudrate =
159 D(bug("Setting baudrate to %d.\n",data->baudrate));
161 #if 0
162 if (tcsetattr(data->filedescriptor, TCSANOW, &_termios) >=0)
164 data->replyport_read = AllocMem(sizeof(struct MsgPort), MEMF_PUBLIC|MEMF_CLEAR);
165 data->replyport_write= AllocMem(sizeof(struct MsgPort), MEMF_PUBLIC|MEMF_CLEAR);
167 if (data->replyport_read && data->replyport_write)
170 ** Init the msg ports. They don't need a signal to be allocated
172 NEWLIST(&data->replyport_read->mp_MsgList);
173 data->replyport_read ->mp_Node.ln_Type = NT_MSGPORT;
175 NEWLIST(&data->replyport_write->mp_MsgList);
176 data->replyport_write->mp_Node.ln_Type = NT_MSGPORT;
178 data->softint_read = AllocMem(sizeof(struct Interrupt), MEMF_CLEAR);
179 data->softint_write = AllocMem(sizeof(struct Interrupt), MEMF_CLEAR);
181 if (data->softint_read && data->softint_write)
183 data->softint_read->is_Data = data;
184 data->softint_read->is_Code = serialunit_receive_data;
186 data->softint_write->is_Data = data;
187 data->softint_write->is_Code = serialunit_write_more_data;
189 data->replyport_read->mp_Flags = PA_SOFTINT;
190 data->replyport_read->mp_SoftInt = data->softint_read;
192 data->replyport_write->mp_Flags = PA_SOFTINT;
193 data->replyport_write->mp_SoftInt = data->softint_write;
195 data->unixio_read = OOP_NewObject(NULL, CLID_Hidd_UnixIO, (struct TagItem *)tags);
196 data->unixio_write = OOP_NewObject(NULL, CLID_Hidd_UnixIO, (struct TagItem *)tags);
198 if (NULL != data->unixio_read && NULL != data->unixio_write)
200 ULONG error;
201 D(bug("Creating UnixIO AsyncIO command!\n"));
203 error = Hidd_UnixIO_AsyncIO(data->unixio_read,
204 data->filedescriptor,
205 vHidd_UnixIO_Terminal,
206 data->replyport_read,
207 vHidd_UnixIO_Read | vHidd_UnixIO_Keep,
208 SysBase);
210 error = Hidd_UnixIO_AsyncIO(data->unixio_write,
211 data->filedescriptor,
212 vHidd_UnixIO_Terminal,
213 data->replyport_write,
214 vHidd_UnixIO_Write | vHidd_UnixIO_Keep,
215 SysBase);
216 goto exit;
220 if (NULL != data->unixio_read)
221 OOP_DisposeObject(data->unixio_read);
223 if (NULL != data->unixio_write)
224 OOP_DisposeObject(data->unixio_write);
227 if (data->softint_read)
228 FreeMem(data->softint_read, sizeof(struct Interrupt));
229 if (data->softint_write)
230 FreeMem(data->softint_write, sizeof(struct Interrupt));
233 if (data->replyport_read)
234 FreeMem(data->replyport_read , sizeof(struct MsgPort));
235 if (data->replyport_write)
236 FreeMem(data->replyport_write, sizeof(struct MsgPort));
238 #else
239 goto exit;
240 #endif
242 Hidd_UnixIO_CloseFile(data->unixio, data->filedescriptor, NULL);
245 OOP_DisposeObject(obj);
246 obj = NULL;
247 } /* if (obj) */
249 D(bug("%s - an error occurred!\n",__FUNCTION__));
251 exit:
252 ReturnPtr("SerialUnit::New()", OOP_Object *, obj);
255 /******* SerialUnit::Dispose() ***********************************/
256 OOP_Object *UXSerUnit__Root__Dispose(OOP_Class *cl, OOP_Object *obj, OOP_Msg msg)
258 struct HIDDSerialUnitData * data;
259 EnterFunc(bug("SerialUnit::Dispose()\n"));
261 data = OOP_INST_DATA(cl, obj);
262 D(bug("Freeing filedescriptor (%d)!\n",data->filedescriptor));
264 if (-1 != data->filedescriptor)
266 #if 0
267 tcsetattr(data->filedescriptor, TCSANOW, &data->orig_termios);
268 Hidd_UnixIO_AbortAsyncIO(data->unixio_read,
269 data->filedescriptor,
270 SysBase);
271 #endif
273 Hidd_UnixIO_CloseFile(data->unixio, data->filedescriptor, NULL);
275 #if 0
276 FreeMem(data->replyport_read, sizeof(struct MsgPort));
277 FreeMem(data->replyport_write, sizeof(struct MsgPort));
279 FreeMem(data->softint_read , sizeof(struct Interrupt));
280 FreeMem(data->softint_write, sizeof(struct Interrupt));
282 OOP_DisposeObject(data->unixio_read);
283 OOP_DisposeObject(data->unixio_write);
284 #endif
286 OOP_DoSuperMethod(cl, obj, (OOP_Msg)msg);
287 ReturnPtr("SerialUnit::Dispose()", OOP_Object *, obj);
292 /******* SerialUnit::Init() **********************************/
293 BOOL UXSerUnit__Hidd_SerialUnit__Init(OOP_Class *cl, OOP_Object *o, struct pHidd_SerialUnit_Init *msg)
295 struct HIDDSerialUnitData * data = OOP_INST_DATA(cl, o);
297 EnterFunc(bug("SerialUnit::Init()\n"));
299 data->DataReceivedCallBack = msg->DataReceived;
300 data->DataReceivedUserData = msg->DataReceivedUserData;
301 data->DataWriteCallBack = msg->WriteData;
302 data->DataWriteUserData = msg->WriteDataUserData;
304 ReturnBool("SerialUnit::Init()", TRUE);
307 /******* SerialUnit::Write() **********************************/
308 ULONG UXSerUnit__Hidd_SerialUnit__Write(OOP_Class *cl, OOP_Object *o, struct pHidd_SerialUnit_Write *msg)
310 struct HIDDSerialUnitData * data = OOP_INST_DATA(cl, o);
311 ULONG len = 0;
313 EnterFunc(bug("SerialUnit::Write()\n"));
315 * If the output is currently suspended then I don't do anything...
318 if (TRUE == data->stopped)
319 return 0;
321 D(bug("Writing %d bytes to fd %d (stream: %s)\n",
322 msg->Length,
323 data->filedescriptor,
324 msg->Outbuffer));
326 len = Hidd_UnixIO_WriteFile(data->unixio, data->filedescriptor,
327 msg->Outbuffer,
328 msg->Length, NULL);
331 ReturnInt("SerialUnit::Write()",ULONG, len);
334 /***************************************************************************/
336 static ULONG valid_baudrates[] =
341 110,
342 134,
343 150,
344 200,
345 300,
346 600,
347 1200,
348 1800,
349 2400,
350 4800,
351 9600,
352 19200,
353 38400,
354 57600,
355 115200,
359 /*** unused due to cfsetspeed ***
361 static LONG unix_baudrates[] =
364 B50,
365 B75,
366 B110
367 B134,
368 B150,
369 B200,
370 B300,
371 B600,
372 B1200,
373 B1800,
374 B2400,
375 B4800,
376 B9600,
377 B19200,
378 B38400,
379 B57600,
380 B115200
383 ********************************/
385 /******* SerialUnit::SetBaudrate() **********************************/
386 ULONG UXSerUnit__Hidd_SerialUnit__SetBaudrate(OOP_Class *cl, OOP_Object *o, struct pHidd_SerialUnit_SetBaudrate *msg)
388 struct HIDDSerialUnitData * data = OOP_INST_DATA(cl, o);
389 BOOL valid = FALSE;
391 if (msg->baudrate != data->baudrate)
393 int i = 0;
394 D(bug("Trying to adjust the baudrate to %d\n",msg->baudrate));
395 while (FALSE == valid && ~0 != valid_baudrates[i])
397 if (msg->baudrate == valid_baudrates[i])
399 #if 0
400 struct termios _termios;
401 tcgetattr(data->filedescriptor, &_termios);
402 cfsetspeed(&_termios, msg->baudrate);
404 if (tcsetattr(data->filedescriptor, TCSANOW, &_termios) <0)
406 D(bug("Failed to set to new baudrate %d\n",msg->baudrate));
408 else
410 data->baudrate = msg->baudrate;
411 D(bug("Adjusted to new baudrate %d!\n",msg->baudrate));
412 valid = TRUE;
414 #else
415 valid = TRUE;
416 #endif
418 i++;
419 } /* while */
420 } /* if */
421 return valid;
424 static UBYTE valid_datalengths[] =
433 static UBYTE unix_datalengths[] =
435 CS5,
436 CS6,
437 CS7,
441 /******* SerialUnit::SetParameters() **********************************/
442 ULONG UXSerUnit__Hidd_SerialUnit__SetParameters(OOP_Class *cl, OOP_Object *o, struct pHidd_SerialUnit_SetParameters *msg)
444 struct HIDDSerialUnitData * data = OOP_INST_DATA(cl, o);
445 BOOL valid = TRUE;
446 int i = 0;
447 struct TagItem * tags = msg->tags;
449 while (TAG_END != tags[i].ti_Tag && TRUE == valid)
451 switch (tags[i].ti_Tag)
453 case TAG_DATALENGTH:
454 if ((UBYTE)tags[i].ti_Data != data->datalength)
456 int j = 0;
457 BOOL found = FALSE;
458 while (0 != valid_datalengths[j])
460 if ((UBYTE)tags[i].ti_Data == valid_datalengths[j])
462 found = TRUE;
463 data->datalength = unix_datalengths[j];
464 break;
467 j++;
469 valid = found;
472 break;
474 case TAG_STOP_BITS:
475 if (2 == tags[i].ti_Data) {
476 data->stopbits = 2;
477 } else
478 data->stopbits = 1;
479 break;
481 case TAG_PARITY:
482 if ( /* PARITY_0 == tags[i].ti_Data ||
483 PARITY_1 == tags[i].ti_Data || */
484 PARITY_EVEN == tags[i].ti_Data ||
485 PARITY_ODD == tags[i].ti_Data)
487 data->parity = TRUE;
488 data->paritytype = tags[i].ti_Data;
490 else
491 valid = FALSE;
492 break;
494 case TAG_PARITY_OFF:
495 data->parity = FALSE;
496 break;
498 case TAG_SKIP:
499 case TAG_IGNORE:
500 break;
502 default:
503 valid = FALSE;
505 i++;
508 settermios(data);
510 return valid;
513 /******* SerialUnit::SendBreak() **********************************/
514 BYTE UXSerUnit__Hidd_SerialUnit__SendBreak(OOP_Class *cl, OOP_Object *o, struct pHidd_SerialUnit_SendBreak *msg)
516 #if 0
517 struct HIDDSerialUnitData * data = OOP_INST_DATA(cl, o);
518 if (0 == tcsendbreak(data->filedescriptor, msg->duration))
519 #endif
520 return 0;
522 return SerErr_LineErr;
525 /******* SerialUnit::Start() **********************************/
526 VOID UXSerUnit__Hidd_SerialUnit__Start(OOP_Class *cl, OOP_Object *o, struct pHidd_SerialUnit_Start *msg)
528 struct HIDDSerialUnitData * data = OOP_INST_DATA(cl, o);
531 * Allow or start feeding the UART with data. Get the data
532 * from upper layer.
534 if (TRUE == data->stopped) {
535 if (NULL != data->DataWriteCallBack)
536 data->DataWriteCallBack(data->unitnum, data->DataWriteUserData);
538 * Also mark the stopped flag as FALSE.
540 data->stopped = FALSE;
545 /******* SerialUnit::Stop() **********************************/
546 VOID UXSerUnit__Hidd_SerialUnit__Stop(OOP_Class *cl, OOP_Object *o, struct pHidd_SerialUnit_Stop *msg)
548 struct HIDDSerialUnitData * data = OOP_INST_DATA(cl, o);
551 * The next time the interrupt comes along and asks for
552 * more data we just don't do anything...
554 data->stopped = TRUE;
557 /****** SerialUnit::GetCapabilities ********************************/
558 VOID UXSerUnit__Hidd_SerialUnit__GetCapabilities(OOP_Class * cl, OOP_Object *o, struct TagItem * tags)
560 if (NULL != tags)
562 int i = 0;
563 BOOL end = FALSE;
564 while (FALSE == end)
566 switch (tags[i].ti_Tag)
568 case HIDDA_SerialUnit_BPSRate:
569 tags[i].ti_Data = (STACKIPTR)valid_baudrates;
570 break;
572 case HIDDA_SerialUnit_DataLength:
573 tags[i].ti_Data = (STACKIPTR)valid_datalengths;
574 break;
576 case TAG_DONE:
577 end = TRUE;
578 break;
580 i++;
585 /****** SerialUnit::GetStatus ********************************/
586 UWORD UXSerUnit__Hidd_SerialUnit__GetStatus(OOP_Class *cl, OOP_Object *o, struct pHidd_SerialUnit_GetStatus *msg)
588 // struct HIDDSerialUnitData * data = OOP_INST_DATA(cl, o);
590 return 0;
593 /************* The software interrupt handler that gets data from UART *****/
596 #define READBUFFER_SIZE 513
598 AROS_INTH1(serialunit_receive_data, struct HIDDSerialUnitData *, data)
600 AROS_INTFUNC_INIT
602 ssize_t len;
603 UBYTE buffer[READBUFFER_SIZE];
604 // struct Message * msg;
607 ** Get the unixio message from my port but don't free it
609 // msg = GetMsg(data->replyport_read);
610 // FreeMem(msg, sizeof(struct uioMessage));
613 ** Read the data from the port ...
615 len = Hidd_UnixIO_ReadFile(data->unixio, data->filedescriptor, buffer, READBUFFER_SIZE, NULL);
617 ** ... and deliver them to whoever is interested.
620 if (NULL != data->DataReceivedCallBack)
621 data->DataReceivedCallBack(buffer, len, data->unitnum, data->DataReceivedUserData);
623 return FALSE;
625 AROS_INTFUNC_EXIT
628 AROS_INTH1(serialunit_write_more_data, struct HIDDSerialUnitData *, data)
630 AROS_INTFUNC_INIT
632 // struct Message * msg;
635 ** Get the unixio message from my port but don't free it
637 // msg = GetMsg(data->replyport_write);
638 // FreeMem(msg, sizeof(struct uioMessage));
641 ** Ask for more data be written to the unit
642 ** but only if output is not currently suspended.
644 if (TRUE == data->stopped)
645 return;
646 D(bug("Asking for more data to be written to unit %d\n",data->unitnum));
648 if (NULL != data->DataWriteCallBack)
649 data->DataWriteCallBack(data->unitnum, data->DataWriteUserData);
651 return FALSE;
653 AROS_INTFUNC_EXIT
657 /******* init_serialunitclass ********************************/
659 #undef __IHidd_SerialUnitAB
660 #define __IHidd_SerialUnitAB (LIBBASE->hdg_csd.hiddSerialUnitAB)
662 #undef __IHidd_UnixIO
663 #define __IHidd_UnixIO (LIBBASE->hdg_csd.hiddUnixIOAttrBase)
665 static int UXSerUnit_InitAttrBase(LIBBASETYPEPTR LIBBASE)
667 EnterFunc(bug(" UXSerUnit_InitAttrBase(LIBBASE=%p)\n", LIBBASE));
669 __IHidd_SerialUnitAB = OOP_ObtainAttrBase(IID_Hidd_SerialUnit);
671 __IHidd_UnixIO = OOP_ObtainAttrBase(IID_Hidd_UnixIO);
673 ReturnInt("UXSerUnit_InitAttrBase", ULONG, __IHidd_SerialUnitAB != 0 && __IHidd_UnixIO != 0);
676 ADD2INITLIB(UXSerUnit_InitAttrBase, 0)
679 /**************************************************************/
681 static void settermios(struct HIDDSerialUnitData * data)
683 #if 0
684 struct termios _termios;
685 tcgetattr(data->filedescriptor, &_termios);
687 _termios.c_cflag &= ~CSIZE;
688 _termios.c_cflag |= data->datalength;
691 * Parity
693 if (FALSE == data->parity)
694 _termios.c_cflag &= ~(PARENB|PARODD);
695 else
697 _termios.c_cflag |= PARENB;
698 switch (data->paritytype)
700 case PARITY_EVEN:
701 _termios.c_cflag &= ~PARODD;
702 break;
704 case PARITY_ODD:
705 _termios.c_cflag |= PARODD;
706 break;
711 * Stop Bits
713 _termios.c_cflag &= ~CSTOPB;
714 if (2 == data->stopbits)
715 _termios.c_cflag |= CSTOPB;
717 if (tcsetattr(data->filedescriptor, TCSADRAIN, &_termios) < 0)
719 // D(bug("Failed to set new termios\n"));
721 else
723 // D(bug("Adjusted to new termios!\n"));
725 #endif
726 } /* settermios */
728 /**************************************************************/
731 * Adapt the termios structure to the preferences
733 static void adapt_termios(struct termios * termios,
734 struct Preferences * prefs)
736 #if 0
737 cfmakeraw(termios);
739 * Parity.
741 termios->c_cflag &= ~(PARENB|PARODD);
742 switch ((prefs->SerParShk >> 4) & 0x0f) {
743 case SPARITY_NONE:
744 termios->c_cflag &= ~(PARENB|PARODD);
745 break;
747 case SPARITY_EVEN:
748 termios->c_cflag |= PARENB;
749 break;
751 case SPARITY_ODD:
752 termios->c_cflag |= (PARODD|PARENB);
753 break;
755 case SPARITY_MARK:
756 case SPARITY_SPACE:
757 default:
758 break;
762 * Bit per character
764 termios->c_cflag &= ~CSIZE;
765 switch ((prefs->SerRWBits & 0x0f)) {
766 default: /* 8 bit */
767 case 0:
768 termios->c_cflag |= CS8;
769 break;
771 case 1: /* 7 bit */
772 termios->c_cflag |= CS7;
773 break;
775 case 2: /* 6 bit */
776 termios->c_cflag |= CS6;
777 break;
779 case 3: /* 5 bit */
780 termios->c_cflag |= CS5;
781 break;
785 * 2 stop bits ? default is '1'.
787 if (1 == (prefs->SerStopBuf >> 4))
788 termios->c_cflag |= CSTOPB;
789 else
790 termios->c_cflag &= ~CSTOPB;
793 * Handshake to be used.
795 termios->c_iflag &= ~(IXON|IXOFF);
796 termios->c_cflag &= ~CRTSCTS;
797 switch((prefs->SerParShk & 0x0f)) {
798 case SHSHAKE_XON:
799 termios->c_iflag |= (IXON|IXOFF);
800 break;
802 case SHSHAKE_RTS:
803 termios->c_cflag |= CRTSCTS;
804 break;
806 default:
807 break;
810 cfsetspeed(termios, prefs->BaudRate);
811 #endif
813 } /* adapt_termios */