2 Copyright © 1995-2006, The AROS Development Team. All rights reserved.
5 Desc: Serial Unit hidd class implementation.
9 /* Some POSIX includes */
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
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
[] =
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
;
75 static const struct TagItem tags
[] = {{ TAG_END
, 0}};
77 struct TagItem
*tag
, *tstate
;
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
)))
89 if (IS_HIDDSERIALUNIT_ATTR(tag
->ti_Tag
, idx
))
94 case aoHidd_SerialUnit_Unit
:
95 unitnum
= (ULONG
)tag
->ti_Data
;
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
);
108 struct termios _termios
;
109 const struct TagItem tags
[] = {
110 {aHidd_UnixIO_Opener
, (IPTR
)"serial.hidd"},
111 {aHidd_UnixIO_Architecture
, (IPTR
)AROS_ARCHITECTURE
},
115 data
= OOP_INST_DATA(cl
, obj
);
117 data
->unitnum
= unitnum
;
119 data
->unixio
= OOP_NewObject(NULL
, CLID_Hidd_UnixIO
, (struct TagItem
*)tags
);
121 OOP_DisposeObject(obj
);
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);
138 ** Configure the tty driver
140 tcgetattr(data
->filedescriptor
, &data
->orig_termios
);
141 tcgetattr(data
->filedescriptor
, &_termios
);
142 cfmakeraw(&_termios
);
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
);
159 D(bug("Setting baudrate to %d.\n",data
->baudrate
));
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
)
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
,
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
,
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
));
242 Hidd_UnixIO_CloseFile(data
->unixio
, data
->filedescriptor
, NULL
);
245 OOP_DisposeObject(obj
);
249 D(bug("%s - an error occurred!\n",__FUNCTION__
));
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
)
267 tcsetattr(data
->filedescriptor
, TCSANOW
, &data
->orig_termios
);
268 Hidd_UnixIO_AbortAsyncIO(data
->unixio_read
,
269 data
->filedescriptor
,
273 Hidd_UnixIO_CloseFile(data
->unixio
, data
->filedescriptor
, NULL
);
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
);
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
);
313 EnterFunc(bug("SerialUnit::Write()\n"));
315 * If the output is currently suspended then I don't do anything...
318 if (TRUE
== data
->stopped
)
321 D(bug("Writing %d bytes to fd %d (stream: %s)\n",
323 data
->filedescriptor
,
326 len
= Hidd_UnixIO_WriteFile(data
->unixio
, data
->filedescriptor
,
331 ReturnInt("SerialUnit::Write()",ULONG
, len
);
334 /***************************************************************************/
336 static ULONG valid_baudrates
[] =
359 /*** unused due to cfsetspeed ***
361 static LONG unix_baudrates[] =
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
);
391 if (msg
->baudrate
!= data
->baudrate
)
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
])
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
));
410 data
->baudrate
= msg
->baudrate
;
411 D(bug("Adjusted to new baudrate %d!\n",msg
->baudrate
));
424 static UBYTE valid_datalengths
[] =
433 static UBYTE unix_datalengths
[] =
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
);
447 struct TagItem
* tags
= msg
->tags
;
449 while (TAG_END
!= tags
[i
].ti_Tag
&& TRUE
== valid
)
451 switch (tags
[i
].ti_Tag
)
454 if ((UBYTE
)tags
[i
].ti_Data
!= data
->datalength
)
458 while (0 != valid_datalengths
[j
])
460 if ((UBYTE
)tags
[i
].ti_Data
== valid_datalengths
[j
])
463 data
->datalength
= unix_datalengths
[j
];
475 if (2 == tags
[i
].ti_Data
) {
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
)
488 data
->paritytype
= tags
[i
].ti_Data
;
495 data
->parity
= FALSE
;
513 /******* SerialUnit::SendBreak() **********************************/
514 BYTE
UXSerUnit__Hidd_SerialUnit__SendBreak(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_SerialUnit_SendBreak
*msg
)
517 struct HIDDSerialUnitData
* data
= OOP_INST_DATA(cl
, o
);
518 if (0 == tcsendbreak(data
->filedescriptor
, msg
->duration
))
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
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
)
566 switch (tags
[i
].ti_Tag
)
568 case HIDDA_SerialUnit_BPSRate
:
569 tags
[i
].ti_Data
= (STACKIPTR
)valid_baudrates
;
572 case HIDDA_SerialUnit_DataLength
:
573 tags
[i
].ti_Data
= (STACKIPTR
)valid_datalengths
;
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);
593 /************* The software interrupt handler that gets data from UART *****/
596 #define READBUFFER_SIZE 513
598 AROS_INTH1(serialunit_receive_data
, struct HIDDSerialUnitData
*, data
)
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
);
628 AROS_INTH1(serialunit_write_more_data
, struct HIDDSerialUnitData
*, data
)
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
)
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
);
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
)
684 struct termios _termios
;
685 tcgetattr(data
->filedescriptor
, &_termios
);
687 _termios
.c_cflag
&= ~CSIZE
;
688 _termios
.c_cflag
|= data
->datalength
;
693 if (FALSE
== data
->parity
)
694 _termios
.c_cflag
&= ~(PARENB
|PARODD
);
697 _termios
.c_cflag
|= PARENB
;
698 switch (data
->paritytype
)
701 _termios
.c_cflag
&= ~PARODD
;
705 _termios
.c_cflag
|= PARODD
;
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"));
723 // D(bug("Adjusted to new termios!\n"));
728 /**************************************************************/
731 * Adapt the termios structure to the preferences
733 static void adapt_termios(struct termios
* termios
,
734 struct Preferences
* prefs
)
741 termios
->c_cflag
&= ~(PARENB
|PARODD
);
742 switch ((prefs
->SerParShk
>> 4) & 0x0f) {
744 termios
->c_cflag
&= ~(PARENB
|PARODD
);
748 termios
->c_cflag
|= PARENB
;
752 termios
->c_cflag
|= (PARODD
|PARENB
);
764 termios
->c_cflag
&= ~CSIZE
;
765 switch ((prefs
->SerRWBits
& 0x0f)) {
768 termios
->c_cflag
|= CS8
;
772 termios
->c_cflag
|= CS7
;
776 termios
->c_cflag
|= CS6
;
780 termios
->c_cflag
|= CS5
;
785 * 2 stop bits ? default is '1'.
787 if (1 == (prefs
->SerStopBuf
>> 4))
788 termios
->c_cflag
|= CSTOPB
;
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)) {
799 termios
->c_iflag
|= (IXON
|IXOFF
);
803 termios
->c_cflag
|= CRTSCTS
;
810 cfsetspeed(termios
, prefs
->BaudRate
);
813 } /* adapt_termios */