make.tmpl: add missing compiler attribute to build_progs
[AROS.git] / arch / all-unix / hidd / serial / SerialUnitClass.c
blobcd443186115c71fa294f2e475d454283ec6b49f4
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>
34 #include <devices/serial.h>
35 #include <intuition/preferences.h>
37 #include <aros/symbolsets.h>
40 #include "serial_intern.h"
42 #include LC_LIBDEFS_FILE
43 #undef timeval
45 #undef SDEBUG
46 #undef DEBUG
47 #define SDEBUG 0
48 #define DEBUG 0
49 #include <aros/debug.h>
51 void serialunit_receive_data();
52 void serialunit_write_more_data();
54 /* Some utility functions */
55 static void settermios(struct HIDDSerialUnitData * data);
56 static void adapt_termios(struct termios * termios,
57 struct Preferences * prefs);
59 static char * unitname[] =
61 "/dev/ttyS0",
62 "/dev/ttyS1",
63 "/dev/ttyS2",
64 "/dev/ttyS3"
67 /*************************** Classes *****************************/
69 /******* SerialUnit::New() ***********************************/
70 OOP_Object *UXSerUnit__Root__New(OOP_Class *cl, OOP_Object *obj, struct pRoot_New *msg)
72 struct HIDDSerialUnitData * data;
73 #if 0
74 static const struct TagItem tags[] = {{ TAG_END, 0}};
75 #endif
76 struct TagItem *tag, *tstate;
77 ULONG unitnum = 0;
79 EnterFunc(bug("SerialUnit::New()\n"));
80 D(bug("SerialUnit created on %s at %s.\n",__DATE__,__TIME__));
82 tstate = msg->attrList;
83 while ((tag = NextTagItem(&tstate)))
85 ULONG idx;
87 #define csd CSD(cl)
88 if (IS_HIDDSERIALUNIT_ATTR(tag->ti_Tag, idx))
89 #undef csd
91 switch (idx)
93 case aoHidd_SerialUnit_Unit:
94 unitnum = (ULONG)tag->ti_Data;
95 break;
99 } /* while (tags to process) */
101 D(bug("!!!!Request for unit number %d\n",unitnum));
103 obj = (OOP_Object *)OOP_DoSuperMethod(cl, obj, (OOP_Msg)msg);
105 if (obj)
107 struct termios _termios;
108 const struct TagItem tags[] = {
109 {aHidd_UnixIO_Opener , (IPTR)"serial.hidd"},
110 {aHidd_UnixIO_Architecture, (IPTR)AROS_ARCHITECTURE},
111 {TAG_END}
114 data = OOP_INST_DATA(cl, obj);
116 data->unitnum = unitnum;
118 data->unixio = OOP_NewObject(NULL, CLID_Hidd_UnixIO, (struct TagItem *)tags);
119 if (!data->unixio) {
120 OOP_DisposeObject(obj);
121 obj = NULL;
122 goto exit;
125 D(bug("Opening %s.\n",unitname[data->unitnum]));
127 data->filedescriptor = Hidd_UnixIO_OpenFile(data->unixio, unitname[data->unitnum], O_NONBLOCK|O_RDWR, 0, NULL);
129 D(bug("Opened %s on handle %d\n",unitname[data->unitnum], data->filedescriptor));
131 if (-1 != data->filedescriptor)
133 struct IntuitionBase * IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",0);
135 #if 0
137 ** Configure the tty driver
139 tcgetattr(data->filedescriptor, &data->orig_termios);
140 tcgetattr(data->filedescriptor, &_termios);
141 cfmakeraw(&_termios);
142 #endif
145 * Get the preferences information from intuition library.
146 * If intuition could not be opened (?) then I will just
147 * use the default termios.
149 if (NULL != IntuitionBase) {
150 struct Preferences prefs;
151 GetPrefs(&prefs,sizeof(prefs));
152 data->baudrate = prefs.BaudRate;
153 adapt_termios(&_termios, &prefs);
154 CloseLibrary((struct Library *)IntuitionBase);
155 } else {
156 // data->baudrate =
158 D(bug("Setting baudrate to %d.\n",data->baudrate));
160 #if 0
161 if (tcsetattr(data->filedescriptor, TCSANOW, &_termios) >=0)
163 data->replyport_read = AllocMem(sizeof(struct MsgPort), MEMF_PUBLIC|MEMF_CLEAR);
164 data->replyport_write= AllocMem(sizeof(struct MsgPort), MEMF_PUBLIC|MEMF_CLEAR);
166 if (data->replyport_read && data->replyport_write)
169 ** Init the msg ports. They don't need a signal to be allocated
171 NEWLIST(&data->replyport_read->mp_MsgList);
172 data->replyport_read ->mp_Node.ln_Type = NT_MSGPORT;
174 NEWLIST(&data->replyport_write->mp_MsgList);
175 data->replyport_write->mp_Node.ln_Type = NT_MSGPORT;
177 data->softint_read = AllocMem(sizeof(struct Interrupt), MEMF_CLEAR);
178 data->softint_write = AllocMem(sizeof(struct Interrupt), MEMF_CLEAR);
180 if (data->softint_read && data->softint_write)
182 data->softint_read->is_Data = data;
183 data->softint_read->is_Code = serialunit_receive_data;
185 data->softint_write->is_Data = data;
186 data->softint_write->is_Code = serialunit_write_more_data;
188 data->replyport_read->mp_Flags = PA_SOFTINT;
189 data->replyport_read->mp_SoftInt = data->softint_read;
191 data->replyport_write->mp_Flags = PA_SOFTINT;
192 data->replyport_write->mp_SoftInt = data->softint_write;
194 data->unixio_read = OOP_NewObject(NULL, CLID_Hidd_UnixIO, (struct TagItem *)tags);
195 data->unixio_write = OOP_NewObject(NULL, CLID_Hidd_UnixIO, (struct TagItem *)tags);
197 if (NULL != data->unixio_read && NULL != data->unixio_write)
199 ULONG error;
200 D(bug("Creating UnixIO AsyncIO command!\n"));
202 error = Hidd_UnixIO_AsyncIO(data->unixio_read,
203 data->filedescriptor,
204 vHidd_UnixIO_Terminal,
205 data->replyport_read,
206 vHidd_UnixIO_Read | vHidd_UnixIO_Keep,
207 SysBase);
209 error = Hidd_UnixIO_AsyncIO(data->unixio_write,
210 data->filedescriptor,
211 vHidd_UnixIO_Terminal,
212 data->replyport_write,
213 vHidd_UnixIO_Write | vHidd_UnixIO_Keep,
214 SysBase);
215 goto exit;
219 if (NULL != data->unixio_read)
220 OOP_DisposeObject(data->unixio_read);
222 if (NULL != data->unixio_write)
223 OOP_DisposeObject(data->unixio_write);
226 if (data->softint_read)
227 FreeMem(data->softint_read, sizeof(struct Interrupt));
228 if (data->softint_write)
229 FreeMem(data->softint_write, sizeof(struct Interrupt));
232 if (data->replyport_read)
233 FreeMem(data->replyport_read , sizeof(struct MsgPort));
234 if (data->replyport_write)
235 FreeMem(data->replyport_write, sizeof(struct MsgPort));
237 #else
238 goto exit;
239 #endif
241 Hidd_UnixIO_CloseFile(data->unixio, data->filedescriptor, NULL);
244 OOP_DisposeObject(obj);
245 obj = NULL;
246 } /* if (obj) */
248 D(bug("%s - an error occurred!\n",__FUNCTION__));
250 exit:
251 ReturnPtr("SerialUnit::New()", OOP_Object *, obj);
254 /******* SerialUnit::Dispose() ***********************************/
255 OOP_Object *UXSerUnit__Root__Dispose(OOP_Class *cl, OOP_Object *obj, OOP_Msg msg)
257 struct HIDDSerialUnitData * data;
258 EnterFunc(bug("SerialUnit::Dispose()\n"));
260 data = OOP_INST_DATA(cl, obj);
261 D(bug("Freeing filedescriptor (%d)!\n",data->filedescriptor));
263 if (-1 != data->filedescriptor)
265 #if 0
266 tcsetattr(data->filedescriptor, TCSANOW, &data->orig_termios);
267 Hidd_UnixIO_AbortAsyncIO(data->unixio_read,
268 data->filedescriptor,
269 SysBase);
270 #endif
272 Hidd_UnixIO_CloseFile(data->unixio, data->filedescriptor, NULL);
274 #if 0
275 FreeMem(data->replyport_read, sizeof(struct MsgPort));
276 FreeMem(data->replyport_write, sizeof(struct MsgPort));
278 FreeMem(data->softint_read , sizeof(struct Interrupt));
279 FreeMem(data->softint_write, sizeof(struct Interrupt));
281 OOP_DisposeObject(data->unixio_read);
282 OOP_DisposeObject(data->unixio_write);
283 #endif
285 OOP_DoSuperMethod(cl, obj, (OOP_Msg)msg);
286 ReturnPtr("SerialUnit::Dispose()", OOP_Object *, obj);
291 /******* SerialUnit::Init() **********************************/
292 BOOL UXSerUnit__Hidd_SerialUnit__Init(OOP_Class *cl, OOP_Object *o, struct pHidd_SerialUnit_Init *msg)
294 struct HIDDSerialUnitData * data = OOP_INST_DATA(cl, o);
296 EnterFunc(bug("SerialUnit::Init()\n"));
298 data->DataReceivedCallBack = msg->DataReceived;
299 data->DataReceivedUserData = msg->DataReceivedUserData;
300 data->DataWriteCallBack = msg->WriteData;
301 data->DataWriteUserData = msg->WriteDataUserData;
303 ReturnBool("SerialUnit::Init()", TRUE);
306 /******* SerialUnit::Write() **********************************/
307 ULONG UXSerUnit__Hidd_SerialUnit__Write(OOP_Class *cl, OOP_Object *o, struct pHidd_SerialUnit_Write *msg)
309 struct HIDDSerialUnitData * data = OOP_INST_DATA(cl, o);
310 ULONG len = 0;
312 EnterFunc(bug("SerialUnit::Write()\n"));
314 * If the output is currently suspended then I don't do anything...
317 if (TRUE == data->stopped)
318 return 0;
320 D(bug("Writing %d bytes to fd %d (stream: %s)\n",
321 msg->Length,
322 data->filedescriptor,
323 msg->Outbuffer));
325 len = Hidd_UnixIO_WriteFile(data->unixio, data->filedescriptor,
326 msg->Outbuffer,
327 msg->Length, NULL);
330 ReturnInt("SerialUnit::Write()",ULONG, len);
333 /***************************************************************************/
335 static ULONG valid_baudrates[] =
340 110,
341 134,
342 150,
343 200,
344 300,
345 600,
346 1200,
347 1800,
348 2400,
349 4800,
350 9600,
351 19200,
352 38400,
353 57600,
354 115200,
358 /*** unused due to cfsetspeed ***
360 static LONG unix_baudrates[] =
363 B50,
364 B75,
365 B110
366 B134,
367 B150,
368 B200,
369 B300,
370 B600,
371 B1200,
372 B1800,
373 B2400,
374 B4800,
375 B9600,
376 B19200,
377 B38400,
378 B57600,
379 B115200
382 ********************************/
384 /******* SerialUnit::SetBaudrate() **********************************/
385 ULONG UXSerUnit__Hidd_SerialUnit__SetBaudrate(OOP_Class *cl, OOP_Object *o, struct pHidd_SerialUnit_SetBaudrate *msg)
387 struct HIDDSerialUnitData * data = OOP_INST_DATA(cl, o);
388 BOOL valid = FALSE;
390 if (msg->baudrate != data->baudrate)
392 int i = 0;
393 D(bug("Trying to adjust the baudrate to %d\n",msg->baudrate));
394 while (FALSE == valid && ~0 != valid_baudrates[i])
396 if (msg->baudrate == valid_baudrates[i])
398 #if 0
399 struct termios _termios;
400 tcgetattr(data->filedescriptor, &_termios);
401 cfsetspeed(&_termios, msg->baudrate);
403 if (tcsetattr(data->filedescriptor, TCSANOW, &_termios) <0)
405 D(bug("Failed to set to new baudrate %d\n",msg->baudrate));
407 else
409 data->baudrate = msg->baudrate;
410 D(bug("Adjusted to new baudrate %d!\n",msg->baudrate));
411 valid = TRUE;
413 #else
414 valid = TRUE;
415 #endif
417 i++;
418 } /* while */
419 } /* if */
420 return valid;
423 static UBYTE valid_datalengths[] =
432 static UBYTE unix_datalengths[] =
434 CS5,
435 CS6,
436 CS7,
440 /******* SerialUnit::SetParameters() **********************************/
441 ULONG UXSerUnit__Hidd_SerialUnit__SetParameters(OOP_Class *cl, OOP_Object *o, struct pHidd_SerialUnit_SetParameters *msg)
443 struct HIDDSerialUnitData * data = OOP_INST_DATA(cl, o);
444 BOOL valid = TRUE;
445 int i = 0;
446 struct TagItem * tags = msg->tags;
448 while (TAG_END != tags[i].ti_Tag && TRUE == valid)
450 switch (tags[i].ti_Tag)
452 case TAG_DATALENGTH:
453 if ((UBYTE)tags[i].ti_Data != data->datalength)
455 int j = 0;
456 BOOL found = FALSE;
457 while (0 != valid_datalengths[j])
459 if ((UBYTE)tags[i].ti_Data == valid_datalengths[j])
461 found = TRUE;
462 data->datalength = unix_datalengths[j];
463 break;
466 j++;
468 valid = found;
471 break;
473 case TAG_STOP_BITS:
474 if (2 == tags[i].ti_Data) {
475 data->stopbits = 2;
476 } else
477 data->stopbits = 1;
478 break;
480 case TAG_PARITY:
481 if ( /* PARITY_0 == tags[i].ti_Data ||
482 PARITY_1 == tags[i].ti_Data || */
483 PARITY_EVEN == tags[i].ti_Data ||
484 PARITY_ODD == tags[i].ti_Data)
486 data->parity = TRUE;
487 data->paritytype = tags[i].ti_Data;
489 else
490 valid = FALSE;
491 break;
493 case TAG_PARITY_OFF:
494 data->parity = FALSE;
495 break;
497 case TAG_SKIP:
498 case TAG_IGNORE:
499 break;
501 default:
502 valid = FALSE;
504 i++;
507 settermios(data);
509 return valid;
512 /******* SerialUnit::SendBreak() **********************************/
513 BYTE UXSerUnit__Hidd_SerialUnit__SendBreak(OOP_Class *cl, OOP_Object *o, struct pHidd_SerialUnit_SendBreak *msg)
515 #if 0
516 struct HIDDSerialUnitData * data = OOP_INST_DATA(cl, o);
517 if (0 == tcsendbreak(data->filedescriptor, msg->duration))
518 #endif
519 return 0;
521 return SerErr_LineErr;
524 /******* SerialUnit::Start() **********************************/
525 VOID UXSerUnit__Hidd_SerialUnit__Start(OOP_Class *cl, OOP_Object *o, struct pHidd_SerialUnit_Start *msg)
527 struct HIDDSerialUnitData * data = OOP_INST_DATA(cl, o);
530 * Allow or start feeding the UART with data. Get the data
531 * from upper layer.
533 if (TRUE == data->stopped) {
534 if (NULL != data->DataWriteCallBack)
535 data->DataWriteCallBack(data->unitnum, data->DataWriteUserData);
537 * Also mark the stopped flag as FALSE.
539 data->stopped = FALSE;
544 /******* SerialUnit::Stop() **********************************/
545 VOID UXSerUnit__Hidd_SerialUnit__Stop(OOP_Class *cl, OOP_Object *o, struct pHidd_SerialUnit_Stop *msg)
547 struct HIDDSerialUnitData * data = OOP_INST_DATA(cl, o);
550 * The next time the interrupt comes along and asks for
551 * more data we just don't do anything...
553 data->stopped = TRUE;
556 /****** SerialUnit::GetCapabilities ********************************/
557 VOID UXSerUnit__Hidd_SerialUnit__GetCapabilities(OOP_Class * cl, OOP_Object *o, struct TagItem * tags)
559 if (NULL != tags)
561 int i = 0;
562 BOOL end = FALSE;
563 while (FALSE == end)
565 switch (tags[i].ti_Tag)
567 case HIDDA_SerialUnit_BPSRate:
568 tags[i].ti_Data = (STACKIPTR)valid_baudrates;
569 break;
571 case HIDDA_SerialUnit_DataLength:
572 tags[i].ti_Data = (STACKIPTR)valid_datalengths;
573 break;
575 case TAG_DONE:
576 end = TRUE;
577 break;
579 i++;
584 /****** SerialUnit::GetStatus ********************************/
585 UWORD UXSerUnit__Hidd_SerialUnit__GetStatus(OOP_Class *cl, OOP_Object *o, struct pHidd_SerialUnit_GetStatus *msg)
587 // struct HIDDSerialUnitData * data = OOP_INST_DATA(cl, o);
589 return 0;
592 /************* The software interrupt handler that gets data from UART *****/
595 #define READBUFFER_SIZE 513
597 AROS_INTH1(serialunit_receive_data, struct HIDDSerialUnitData *, data)
599 AROS_INTFUNC_INIT
601 ssize_t len;
602 UBYTE buffer[READBUFFER_SIZE];
603 // struct Message * msg;
606 ** Get the unixio message from my port but don't free it
608 // msg = GetMsg(data->replyport_read);
609 // FreeMem(msg, sizeof(struct uioMessage));
612 ** Read the data from the port ...
614 len = Hidd_UnixIO_ReadFile(data->unixio, data->filedescriptor, buffer, READBUFFER_SIZE, NULL);
616 ** ... and deliver them to whoever is interested.
619 if (NULL != data->DataReceivedCallBack)
620 data->DataReceivedCallBack(buffer, len, data->unitnum, data->DataReceivedUserData);
622 return FALSE;
624 AROS_INTFUNC_EXIT
627 AROS_INTH1(serialunit_write_more_data, struct HIDDSerialUnitData *, data)
629 AROS_INTFUNC_INIT
631 // struct Message * msg;
634 ** Get the unixio message from my port but don't free it
636 // msg = GetMsg(data->replyport_write);
637 // FreeMem(msg, sizeof(struct uioMessage));
640 ** Ask for more data be written to the unit
641 ** but only if output is not currently suspended.
643 if (TRUE == data->stopped)
644 return;
645 D(bug("Asking for more data to be written to unit %d\n",data->unitnum));
647 if (NULL != data->DataWriteCallBack)
648 data->DataWriteCallBack(data->unitnum, data->DataWriteUserData);
650 return FALSE;
652 AROS_INTFUNC_EXIT
656 /******* init_serialunitclass ********************************/
658 #undef __IHidd_SerialUnitAB
659 #define __IHidd_SerialUnitAB (LIBBASE->hdg_csd.hiddSerialUnitAB)
661 #undef __IHidd_UnixIO
662 #define __IHidd_UnixIO (LIBBASE->hdg_csd.hiddUnixIOAttrBase)
664 static int UXSerUnit_InitAttrBase(LIBBASETYPEPTR LIBBASE)
666 EnterFunc(bug(" UXSerUnit_InitAttrBase(LIBBASE=%p)\n", LIBBASE));
668 __IHidd_SerialUnitAB = OOP_ObtainAttrBase(IID_Hidd_SerialUnit);
670 __IHidd_UnixIO = OOP_ObtainAttrBase(IID_Hidd_UnixIO);
672 ReturnInt("UXSerUnit_InitAttrBase", ULONG, __IHidd_SerialUnitAB != 0 && __IHidd_UnixIO != 0);
675 ADD2INITLIB(UXSerUnit_InitAttrBase, 0)
678 /**************************************************************/
680 static void settermios(struct HIDDSerialUnitData * data)
682 #if 0
683 struct termios _termios;
684 tcgetattr(data->filedescriptor, &_termios);
686 _termios.c_cflag &= ~CSIZE;
687 _termios.c_cflag |= data->datalength;
690 * Parity
692 if (FALSE == data->parity)
693 _termios.c_cflag &= ~(PARENB|PARODD);
694 else
696 _termios.c_cflag |= PARENB;
697 switch (data->paritytype)
699 case PARITY_EVEN:
700 _termios.c_cflag &= ~PARODD;
701 break;
703 case PARITY_ODD:
704 _termios.c_cflag |= PARODD;
705 break;
710 * Stop Bits
712 _termios.c_cflag &= ~CSTOPB;
713 if (2 == data->stopbits)
714 _termios.c_cflag |= CSTOPB;
716 if (tcsetattr(data->filedescriptor, TCSADRAIN, &_termios) < 0)
718 // D(bug("Failed to set new termios\n"));
720 else
722 // D(bug("Adjusted to new termios!\n"));
724 #endif
725 } /* settermios */
727 /**************************************************************/
730 * Adapt the termios structure to the preferences
732 static void adapt_termios(struct termios * termios,
733 struct Preferences * prefs)
735 #if 0
736 cfmakeraw(termios);
738 * Parity.
740 termios->c_cflag &= ~(PARENB|PARODD);
741 switch ((prefs->SerParShk >> 4) & 0x0f) {
742 case SPARITY_NONE:
743 termios->c_cflag &= ~(PARENB|PARODD);
744 break;
746 case SPARITY_EVEN:
747 termios->c_cflag |= PARENB;
748 break;
750 case SPARITY_ODD:
751 termios->c_cflag |= (PARODD|PARENB);
752 break;
754 case SPARITY_MARK:
755 case SPARITY_SPACE:
756 default:
757 break;
761 * Bit per character
763 termios->c_cflag &= ~CSIZE;
764 switch ((prefs->SerRWBits & 0x0f)) {
765 default: /* 8 bit */
766 case 0:
767 termios->c_cflag |= CS8;
768 break;
770 case 1: /* 7 bit */
771 termios->c_cflag |= CS7;
772 break;
774 case 2: /* 6 bit */
775 termios->c_cflag |= CS6;
776 break;
778 case 3: /* 5 bit */
779 termios->c_cflag |= CS5;
780 break;
784 * 2 stop bits ? default is '1'.
786 if (1 == (prefs->SerStopBuf >> 4))
787 termios->c_cflag |= CSTOPB;
788 else
789 termios->c_cflag &= ~CSTOPB;
792 * Handshake to be used.
794 termios->c_iflag &= ~(IXON|IXOFF);
795 termios->c_cflag &= ~CRTSCTS;
796 switch((prefs->SerParShk & 0x0f)) {
797 case SHSHAKE_XON:
798 termios->c_iflag |= (IXON|IXOFF);
799 break;
801 case SHSHAKE_RTS:
802 termios->c_cflag |= CRTSCTS;
803 break;
805 default:
806 break;
809 cfsetspeed(termios, prefs->BaudRate);
810 #endif
812 } /* adapt_termios */