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>
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
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
[] =
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
;
74 static const struct TagItem tags
[] = {{ TAG_END
, 0}};
76 struct TagItem
*tag
, *tstate
;
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
)))
88 if (IS_HIDDSERIALUNIT_ATTR(tag
->ti_Tag
, idx
))
93 case aoHidd_SerialUnit_Unit
:
94 unitnum
= (ULONG
)tag
->ti_Data
;
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
);
107 struct termios _termios
;
108 const struct TagItem tags
[] = {
109 {aHidd_UnixIO_Opener
, (IPTR
)"serial.hidd"},
110 {aHidd_UnixIO_Architecture
, (IPTR
)AROS_ARCHITECTURE
},
114 data
= OOP_INST_DATA(cl
, obj
);
116 data
->unitnum
= unitnum
;
118 data
->unixio
= OOP_NewObject(NULL
, CLID_Hidd_UnixIO
, (struct TagItem
*)tags
);
120 OOP_DisposeObject(obj
);
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);
137 ** Configure the tty driver
139 tcgetattr(data
->filedescriptor
, &data
->orig_termios
);
140 tcgetattr(data
->filedescriptor
, &_termios
);
141 cfmakeraw(&_termios
);
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
);
158 D(bug("Setting baudrate to %d.\n",data
->baudrate
));
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
)
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
,
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
,
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
));
241 Hidd_UnixIO_CloseFile(data
->unixio
, data
->filedescriptor
, NULL
);
244 OOP_DisposeObject(obj
);
248 D(bug("%s - an error occurred!\n",__FUNCTION__
));
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
)
266 tcsetattr(data
->filedescriptor
, TCSANOW
, &data
->orig_termios
);
267 Hidd_UnixIO_AbortAsyncIO(data
->unixio_read
,
268 data
->filedescriptor
,
272 Hidd_UnixIO_CloseFile(data
->unixio
, data
->filedescriptor
, NULL
);
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
);
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
);
312 EnterFunc(bug("SerialUnit::Write()\n"));
314 * If the output is currently suspended then I don't do anything...
317 if (TRUE
== data
->stopped
)
320 D(bug("Writing %d bytes to fd %d (stream: %s)\n",
322 data
->filedescriptor
,
325 len
= Hidd_UnixIO_WriteFile(data
->unixio
, data
->filedescriptor
,
330 ReturnInt("SerialUnit::Write()",ULONG
, len
);
333 /***************************************************************************/
335 static ULONG valid_baudrates
[] =
358 /*** unused due to cfsetspeed ***
360 static LONG unix_baudrates[] =
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
);
390 if (msg
->baudrate
!= data
->baudrate
)
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
])
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
));
409 data
->baudrate
= msg
->baudrate
;
410 D(bug("Adjusted to new baudrate %d!\n",msg
->baudrate
));
423 static UBYTE valid_datalengths
[] =
432 static UBYTE unix_datalengths
[] =
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
);
446 struct TagItem
* tags
= msg
->tags
;
448 while (TAG_END
!= tags
[i
].ti_Tag
&& TRUE
== valid
)
450 switch (tags
[i
].ti_Tag
)
453 if ((UBYTE
)tags
[i
].ti_Data
!= data
->datalength
)
457 while (0 != valid_datalengths
[j
])
459 if ((UBYTE
)tags
[i
].ti_Data
== valid_datalengths
[j
])
462 data
->datalength
= unix_datalengths
[j
];
474 if (2 == tags
[i
].ti_Data
) {
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
)
487 data
->paritytype
= tags
[i
].ti_Data
;
494 data
->parity
= FALSE
;
512 /******* SerialUnit::SendBreak() **********************************/
513 BYTE
UXSerUnit__Hidd_SerialUnit__SendBreak(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_SerialUnit_SendBreak
*msg
)
516 struct HIDDSerialUnitData
* data
= OOP_INST_DATA(cl
, o
);
517 if (0 == tcsendbreak(data
->filedescriptor
, msg
->duration
))
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
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
)
565 switch (tags
[i
].ti_Tag
)
567 case HIDDA_SerialUnit_BPSRate
:
568 tags
[i
].ti_Data
= (STACKIPTR
)valid_baudrates
;
571 case HIDDA_SerialUnit_DataLength
:
572 tags
[i
].ti_Data
= (STACKIPTR
)valid_datalengths
;
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);
592 /************* The software interrupt handler that gets data from UART *****/
595 #define READBUFFER_SIZE 513
597 AROS_INTH1(serialunit_receive_data
, struct HIDDSerialUnitData
*, data
)
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
);
627 AROS_INTH1(serialunit_write_more_data
, struct HIDDSerialUnitData
*, data
)
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
)
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
);
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
)
683 struct termios _termios
;
684 tcgetattr(data
->filedescriptor
, &_termios
);
686 _termios
.c_cflag
&= ~CSIZE
;
687 _termios
.c_cflag
|= data
->datalength
;
692 if (FALSE
== data
->parity
)
693 _termios
.c_cflag
&= ~(PARENB
|PARODD
);
696 _termios
.c_cflag
|= PARENB
;
697 switch (data
->paritytype
)
700 _termios
.c_cflag
&= ~PARODD
;
704 _termios
.c_cflag
|= PARODD
;
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"));
722 // D(bug("Adjusted to new termios!\n"));
727 /**************************************************************/
730 * Adapt the termios structure to the preferences
732 static void adapt_termios(struct termios
* termios
,
733 struct Preferences
* prefs
)
740 termios
->c_cflag
&= ~(PARENB
|PARODD
);
741 switch ((prefs
->SerParShk
>> 4) & 0x0f) {
743 termios
->c_cflag
&= ~(PARENB
|PARODD
);
747 termios
->c_cflag
|= PARENB
;
751 termios
->c_cflag
|= (PARODD
|PARENB
);
763 termios
->c_cflag
&= ~CSIZE
;
764 switch ((prefs
->SerRWBits
& 0x0f)) {
767 termios
->c_cflag
|= CS8
;
771 termios
->c_cflag
|= CS7
;
775 termios
->c_cflag
|= CS6
;
779 termios
->c_cflag
|= CS5
;
784 * 2 stop bits ? default is '1'.
786 if (1 == (prefs
->SerStopBuf
>> 4))
787 termios
->c_cflag
|= CSTOPB
;
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)) {
798 termios
->c_iflag
|= (IXON
|IXOFF
);
802 termios
->c_cflag
|= CRTSCTS
;
809 cfsetspeed(termios
, prefs
->BaudRate
);
812 } /* adapt_termios */