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
;
73 static const struct TagItem tags
[] = {{ TAG_END
, 0}};
74 struct TagItem
*tag
, *tstate
;
77 EnterFunc(bug("SerialUnit::New()\n"));
78 D(bug("SerialUnit created on %s at %s.\n",__DATE__
,__TIME__
));
80 tstate
= msg
->attrList
;
81 while ((tag
= NextTagItem((struct TagItem
**)&tstate
)))
86 if (IS_HIDDSERIALUNIT_ATTR(tag
->ti_Tag
, idx
))
91 case aoHidd_SerialUnit_Unit
:
92 unitnum
= (ULONG
)tag
->ti_Data
;
97 } /* while (tags to process) */
99 D(bug("!!!!Request for unit number %d\n",unitnum
));
101 obj
= (OOP_Object
*)OOP_DoSuperMethod(cl
, obj
, (OOP_Msg
)msg
);
105 struct termios _termios
;
107 data
= OOP_INST_DATA(cl
, obj
);
109 data
->unitnum
= unitnum
;
111 D(bug("Opening %s.\n",unitname
[data
->unitnum
]));
113 data
->filedescriptor
= unix_open_nonblock(unitname
[data
->unitnum
]);
115 D(bug("Opened %s on handle %d\n",unitname
[data
->unitnum
], data
->filedescriptor
));
117 if (-1 != data
->filedescriptor
)
119 struct IntuitionBase
* IntuitionBase
= (struct IntuitionBase
*)OpenLibrary("intuition.library",0);
122 ** Configure the tty driver
124 tcgetattr(data
->filedescriptor
, &data
->orig_termios
);
125 tcgetattr(data
->filedescriptor
, &_termios
);
126 cfmakeraw(&_termios
);
129 * Get the preferences information from intuition library.
130 * If intuition could not be opened (?) then I will just
131 * use the default termios.
133 if (NULL
!= IntuitionBase
) {
134 struct Preferences prefs
;
135 GetPrefs(&prefs
,sizeof(prefs
));
136 data
->baudrate
= prefs
.BaudRate
;
137 adapt_termios(&_termios
, &prefs
);
138 CloseLibrary((struct Library
*)IntuitionBase
);
142 D(bug("Setting baudrate to %d.\n",data
->baudrate
));
144 if (tcsetattr(data
->filedescriptor
, TCSANOW
, &_termios
) >=0)
146 data
->replyport_read
= AllocMem(sizeof(struct MsgPort
), MEMF_PUBLIC
|MEMF_CLEAR
);
147 data
->replyport_write
= AllocMem(sizeof(struct MsgPort
), MEMF_PUBLIC
|MEMF_CLEAR
);
149 if (data
->replyport_read
&& data
->replyport_write
)
152 ** Init the msg ports. They don't need a signal to be allocated
154 NEWLIST(&data
->replyport_read
->mp_MsgList
);
155 data
->replyport_read
->mp_Node
.ln_Type
= NT_MSGPORT
;
157 NEWLIST(&data
->replyport_write
->mp_MsgList
);
158 data
->replyport_write
->mp_Node
.ln_Type
= NT_MSGPORT
;
160 data
->softint_read
= AllocMem(sizeof(struct Interrupt
), MEMF_CLEAR
);
161 data
->softint_write
= AllocMem(sizeof(struct Interrupt
), MEMF_CLEAR
);
163 if (data
->softint_read
&& data
->softint_write
)
165 data
->softint_read
->is_Data
= data
;
166 data
->softint_read
->is_Code
= serialunit_receive_data
;
168 data
->softint_write
->is_Data
= data
;
169 data
->softint_write
->is_Code
= serialunit_write_more_data
;
171 data
->replyport_read
->mp_Flags
= PA_SOFTINT
;
172 data
->replyport_read
->mp_SoftInt
= data
->softint_read
;
174 data
->replyport_write
->mp_Flags
= PA_SOFTINT
;
175 data
->replyport_write
->mp_SoftInt
= data
->softint_write
;
177 data
->unixio_read
= OOP_NewObject(NULL
, CLID_Hidd_UnixIO
, (struct TagItem
*)tags
);
178 data
->unixio_write
= OOP_NewObject(NULL
, CLID_Hidd_UnixIO
, (struct TagItem
*)tags
);
180 if (NULL
!= data
->unixio_read
&& NULL
!= data
->unixio_write
)
183 D(bug("Creating UnixIO AsyncIO command!\n"));
185 error
= Hidd_UnixIO_AsyncIO(data
->unixio_read
,
186 data
->filedescriptor
,
187 vHidd_UnixIO_Terminal
,
188 data
->replyport_read
,
189 vHidd_UnixIO_Read
| vHidd_UnixIO_Keep
,
192 error
= Hidd_UnixIO_AsyncIO(data
->unixio_write
,
193 data
->filedescriptor
,
194 vHidd_UnixIO_Terminal
,
195 data
->replyport_write
,
196 vHidd_UnixIO_Write
| vHidd_UnixIO_Keep
,
202 if (NULL
!= data
->unixio_read
)
203 OOP_DisposeObject(data
->unixio_read
);
205 if (NULL
!= data
->unixio_write
)
206 OOP_DisposeObject(data
->unixio_write
);
209 if (data
->softint_read
)
210 FreeMem(data
->softint_read
, sizeof(struct Interrupt
));
211 if (data
->softint_write
)
212 FreeMem(data
->softint_write
, sizeof(struct Interrupt
));
215 if (data
->replyport_read
)
216 FreeMem(data
->replyport_read
, sizeof(struct MsgPort
));
217 if (data
->replyport_write
)
218 FreeMem(data
->replyport_write
, sizeof(struct MsgPort
));
222 close(data
->filedescriptor
);
225 OOP_DisposeObject(obj
);
229 D(bug("%s - an error occurred!\n",__FUNCTION__
));
232 ReturnPtr("SerialUnit::New()", OOP_Object
*, obj
);
235 /******* SerialUnit::Dispose() ***********************************/
236 OOP_Object
*UXSerUnit__Root__Dispose(OOP_Class
*cl
, OOP_Object
*obj
, OOP_Msg msg
)
238 struct HIDDSerialUnitData
* data
;
239 EnterFunc(bug("SerialUnit::Dispose()\n"));
241 data
= OOP_INST_DATA(cl
, obj
);
242 D(bug("Freeing filedescriptor (%d)!\n",data
->filedescriptor
));
244 if (-1 != data
->filedescriptor
)
246 tcsetattr(data
->filedescriptor
, TCSANOW
, &data
->orig_termios
);
247 Hidd_UnixIO_AbortAsyncIO(data
->unixio_read
,
248 data
->filedescriptor
,
251 close(data
->filedescriptor
);
253 FreeMem(data
->replyport_read
, sizeof(struct MsgPort
));
254 FreeMem(data
->replyport_write
, sizeof(struct MsgPort
));
256 FreeMem(data
->softint_read
, sizeof(struct Interrupt
));
257 FreeMem(data
->softint_write
, sizeof(struct Interrupt
));
259 OOP_DisposeObject(data
->unixio_read
);
260 OOP_DisposeObject(data
->unixio_write
);
262 OOP_DoSuperMethod(cl
, obj
, (OOP_Msg
)msg
);
263 ReturnPtr("SerialUnit::Dispose()", OOP_Object
*, obj
);
268 /******* SerialUnit::Init() **********************************/
269 BOOL
UXSerUnit__Hidd_SerialUnit__Init(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_SerialUnit_Init
*msg
)
271 struct HIDDSerialUnitData
* data
= OOP_INST_DATA(cl
, o
);
273 EnterFunc(bug("SerialUnit::Init()\n"));
275 data
->DataReceivedCallBack
= msg
->DataReceived
;
276 data
->DataReceivedUserData
= msg
->DataReceivedUserData
;
277 data
->DataWriteCallBack
= msg
->WriteData
;
278 data
->DataWriteUserData
= msg
->WriteDataUserData
;
280 ReturnBool("SerialUnit::Init()", TRUE
);
283 /******* SerialUnit::Write() **********************************/
284 ULONG
UXSerUnit__Hidd_SerialUnit__Write(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_SerialUnit_Write
*msg
)
286 struct HIDDSerialUnitData
* data
= OOP_INST_DATA(cl
, o
);
289 EnterFunc(bug("SerialUnit::Write()\n"));
291 * If the output is currently suspended then I don't do anything...
294 if (TRUE
== data
->stopped
)
297 D(bug("Writing %d bytes to fd %d (stream: %s)\n",
299 data
->filedescriptor
,
302 len
= write(data
->filedescriptor
,
307 ReturnInt("SerialUnit::Write()",ULONG
, len
);
310 /***************************************************************************/
312 static ULONG valid_baudrates
[] =
335 /*** unused due to cfsetspeed ***
337 static LONG unix_baudrates[] =
359 ********************************/
361 /******* SerialUnit::SetBaudrate() **********************************/
362 ULONG
UXSerUnit__Hidd_SerialUnit__SetBaudrate(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_SerialUnit_SetBaudrate
*msg
)
364 struct HIDDSerialUnitData
* data
= OOP_INST_DATA(cl
, o
);
367 if (msg
->baudrate
!= data
->baudrate
)
370 D(bug("Trying to adjust the baudrate to %d\n",msg
->baudrate
));
371 while (FALSE
== valid
&& ~0 != valid_baudrates
[i
])
373 if (msg
->baudrate
== valid_baudrates
[i
])
375 struct termios _termios
;
376 tcgetattr(data
->filedescriptor
, &_termios
);
377 cfsetspeed(&_termios
, msg
->baudrate
);
379 if (tcsetattr(data
->filedescriptor
, TCSANOW
, &_termios
) <0)
381 D(bug("Failed to set to new baudrate %d\n",msg
->baudrate
));
385 data
->baudrate
= msg
->baudrate
;
386 D(bug("Adjusted to new baudrate %d!\n",msg
->baudrate
));
396 static UBYTE valid_datalengths
[] =
405 static UBYTE unix_datalengths
[] =
413 /******* SerialUnit::SetParameters() **********************************/
414 ULONG
UXSerUnit__Hidd_SerialUnit__SetParameters(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_SerialUnit_SetParameters
*msg
)
416 struct HIDDSerialUnitData
* data
= OOP_INST_DATA(cl
, o
);
419 struct TagItem
* tags
= msg
->tags
;
421 while (TAG_END
!= tags
[i
].ti_Tag
&& TRUE
== valid
)
423 switch (tags
[i
].ti_Tag
)
426 if ((UBYTE
)tags
[i
].ti_Data
!= data
->datalength
)
430 while (0 != valid_datalengths
[j
])
432 if ((UBYTE
)tags
[i
].ti_Data
== valid_datalengths
[j
])
435 data
->datalength
= unix_datalengths
[j
];
447 if (2 == tags
[i
].ti_Data
) {
454 if ( /* PARITY_0 == tags[i].ti_Data ||
455 PARITY_1 == tags[i].ti_Data || */
456 PARITY_EVEN
== tags
[i
].ti_Data
||
457 PARITY_ODD
== tags
[i
].ti_Data
)
460 data
->paritytype
= tags
[i
].ti_Data
;
467 data
->parity
= FALSE
;
485 /******* SerialUnit::SendBreak() **********************************/
486 BYTE
UXSerUnit__Hidd_SerialUnit__SendBreak(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_SerialUnit_SendBreak
*msg
)
488 struct HIDDSerialUnitData
* data
= OOP_INST_DATA(cl
, o
);
490 if (0 == tcsendbreak(data
->filedescriptor
, msg
->duration
))
493 return SerErr_LineErr
;
496 /******* SerialUnit::Start() **********************************/
497 VOID
UXSerUnit__Hidd_SerialUnit__Start(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_SerialUnit_Start
*msg
)
499 struct HIDDSerialUnitData
* data
= OOP_INST_DATA(cl
, o
);
502 * Allow or start feeding the UART with data. Get the data
505 if (TRUE
== data
->stopped
) {
506 if (NULL
!= data
->DataWriteCallBack
)
507 data
->DataWriteCallBack(data
->unitnum
, data
->DataWriteUserData
);
509 * Also mark the stopped flag as FALSE.
511 data
->stopped
= FALSE
;
516 /******* SerialUnit::Stop() **********************************/
517 VOID
UXSerUnit__Hidd_SerialUnit__Stop(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_SerialUnit_Stop
*msg
)
519 struct HIDDSerialUnitData
* data
= OOP_INST_DATA(cl
, o
);
522 * The next time the interrupt comes along and asks for
523 * more data we just don't do anything...
525 data
->stopped
= TRUE
;
528 /****** SerialUnit::GetCapabilities ********************************/
529 VOID
UXSerUnit__Hidd_SerialUnit__GetCapabilities(OOP_Class
* cl
, OOP_Object
*o
, struct TagItem
* tags
)
537 switch (tags
[i
].ti_Tag
)
539 case HIDDA_SerialUnit_BPSRate
:
540 tags
[i
].ti_Data
= (STACKIPTR
)valid_baudrates
;
543 case HIDDA_SerialUnit_DataLength
:
544 tags
[i
].ti_Data
= (STACKIPTR
)valid_datalengths
;
556 /****** SerialUnit::GetStatus ********************************/
557 UWORD
UXSerUnit__Hidd_SerialUnit__GetStatus(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_SerialUnit_GetStatus
*msg
)
559 // struct HIDDSerialUnitData * data = OOP_INST_DATA(cl, o);
564 /************* The software interrupt handler that gets data from UART *****/
567 #define READBUFFER_SIZE 513
569 AROS_UFH3(void, serialunit_receive_data
,
570 AROS_UFHA(APTR
, iD
, A1
),
571 AROS_UFHA(APTR
, iC
, A5
),
572 AROS_UFHA(struct ExecBase
*, SysBase
, A6
))
576 struct HIDDSerialUnitData
* data
= iD
;
578 UBYTE buffer
[READBUFFER_SIZE
];
579 // struct Message * msg;
582 ** Get the unixio message from my port but don't free it
584 // msg = GetMsg(data->replyport_read);
585 // FreeMem(msg, sizeof(struct uioMessage));
588 ** Read the data from the port ...
590 len
= read(data
->filedescriptor
, buffer
, READBUFFER_SIZE
);
592 ** ... and deliver them to whoever is interested.
595 if (NULL
!= data
->DataReceivedCallBack
)
596 data
->DataReceivedCallBack(buffer
, len
, data
->unitnum
, data
->DataReceivedUserData
);
601 AROS_UFH3(void, serialunit_write_more_data
,
602 AROS_UFHA(APTR
, iD
, A1
),
603 AROS_UFHA(APTR
, iC
, A5
),
604 AROS_UFHA(struct ExecBase
*, SysBase
, A6
))
608 struct HIDDSerialUnitData
* data
= iD
;
609 // struct Message * msg;
612 ** Get the unixio message from my port but don't free it
614 // msg = GetMsg(data->replyport_write);
615 // FreeMem(msg, sizeof(struct uioMessage));
618 ** Ask for more data be written to the unit
619 ** but only if output is not currently suspended.
621 if (TRUE
== data
->stopped
)
623 D(bug("Asking for more data to be written to unit %d\n",data
->unitnum
));
625 if (NULL
!= data
->DataWriteCallBack
)
626 data
->DataWriteCallBack(data
->unitnum
, data
->DataWriteUserData
);
632 /******* init_serialunitclass ********************************/
634 #undef __IHidd_SerialUnitAB
635 #define __IHidd_SerialUnitAB (LIBBASE->hdg_csd.hiddSerialUnitAB)
637 static int UXSerUnit_InitAttrBase(LIBBASETYPEPTR LIBBASE
)
639 EnterFunc(bug(" UXSerUnit_InitAttrBase(LIBBASE=%p)\n", LIBBASE
));
641 __IHidd_SerialUnitAB
= OOP_ObtainAttrBase(IID_Hidd_SerialUnit
);
643 ReturnInt("UXSerUnit_InitAttrBase", ULONG
, __IHidd_SerialUnitAB
!= 0);
646 ADD2INITLIB(UXSerUnit_InitAttrBase
, 0)
649 /**************************************************************/
651 static void settermios(struct HIDDSerialUnitData
* data
)
654 struct termios _termios
;
655 tcgetattr(data
->filedescriptor
, &_termios
);
657 _termios
.c_cflag
&= ~CSIZE
;
658 _termios
.c_cflag
|= data
->datalength
;
663 if (FALSE
== data
->parity
)
664 _termios
.c_cflag
&= ~(PARENB
|PARODD
);
667 _termios
.c_cflag
|= PARENB
;
668 switch (data
->paritytype
)
671 _termios
.c_cflag
&= ~PARODD
;
675 _termios
.c_cflag
|= PARODD
;
683 _termios
.c_cflag
&= ~CSTOPB
;
684 if (2 == data
->stopbits
)
685 _termios
.c_cflag
|= CSTOPB
;
687 if (tcsetattr(data
->filedescriptor
, TCSADRAIN
, &_termios
) < 0)
689 // D(bug("Failed to set new termios\n"));
693 // D(bug("Adjusted to new termios!\n"));
698 /**************************************************************/
701 * Adapt the termios structure to the preferences
703 static void adapt_termios(struct termios
* termios
,
704 struct Preferences
* prefs
)
710 termios
->c_cflag
&= ~(PARENB
|PARODD
);
711 switch ((prefs
->SerParShk
>> 4) & 0x0f) {
713 termios
->c_cflag
&= ~(PARENB
|PARODD
);
717 termios
->c_cflag
|= PARENB
;
721 termios
->c_cflag
|= (PARODD
|PARENB
);
733 termios
->c_cflag
&= ~CSIZE
;
734 switch ((prefs
->SerRWBits
& 0x0f)) {
737 termios
->c_cflag
|= CS8
;
741 termios
->c_cflag
|= CS7
;
745 termios
->c_cflag
|= CS6
;
749 termios
->c_cflag
|= CS5
;
754 * 2 stop bits ? default is '1'.
756 if (1 == (prefs
->SerStopBuf
>> 4))
757 termios
->c_cflag
|= CSTOPB
;
759 termios
->c_cflag
&= ~CSTOPB
;
762 * Handshake to be used.
764 termios
->c_iflag
&= ~(IXON
|IXOFF
);
765 termios
->c_cflag
&= ~CRTSCTS
;
766 switch((prefs
->SerParShk
& 0x0f)) {
768 termios
->c_iflag
|= (IXON
|IXOFF
);
772 termios
->c_cflag
|= CRTSCTS
;
779 cfsetspeed(termios
, prefs
->BaudRate
);
781 } /* adapt_termios */