2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
5 Desc: Serial Unit hidd class implementation.
10 Right now I am assuming that there is a 1.8432 MHZ crystal connected to
16 #include <asm/amcc440.h>
18 /* the rest are Amiga includes */
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 <intuition/preferences.h>
36 #include <devices/serial.h>
38 #include "serial_intern.h"
44 #include <aros/debug.h>
46 /* The speed of the crystal */
47 #define CRYSTAL_SPEED 1843200
50 static void serialunit_receive_data();
51 ULONG
serialunit_write_more_data();
53 unsigned char get_lcr(struct HIDDSerialUnitData
* data
);
54 unsigned char get_fcr(ULONG baudrate
);
55 BOOL
set_baudrate(struct HIDDSerialUnitData
* data
, ULONG speed
);
56 static void adapt_data(struct HIDDSerialUnitData
* data
,
57 struct Preferences
* prefs
);
59 static inline void serial_out(struct HIDDSerialUnitData
* data
,
63 outb(value
, data
->baseaddr
+offset
);
66 static inline void serial_outp(struct HIDDSerialUnitData
* data
,
70 outb_p(value
, data
->baseaddr
+offset
);
73 static inline unsigned int serial_in(struct HIDDSerialUnitData
* data
,
76 return inb(data
->baseaddr
+offset
);
79 static inline unsigned int serial_inp(struct HIDDSerialUnitData
* data
,
82 return inb_p(data
->baseaddr
+offset
);
87 /*************************** Classes *****************************/
89 /* IO bases for every COM port */
90 static ULONG bases
[] = { UART0_RBR
, UART1_RBR
, UART2_RBR
, UART3_RBR
};
92 /******* SerialUnit::New() ***********************************/
93 OOP_Object
*PPC4xxSerUnit__Root__New(OOP_Class
*cl
, OOP_Object
*obj
, struct pRoot_New
*msg
)
95 struct HIDDSerialUnitData
* data
;
96 struct TagItem
*tag
, *tstate
;
99 EnterFunc(bug("SerialUnit::New()\n"));
101 tstate
= msg
->attrList
;
102 while ((tag
= NextTagItem(&tstate
)))
106 #define csd CSD(cl->UserData)
107 if (IS_HIDDSERIALUNIT_ATTR(tag
->ti_Tag
, idx
))
112 case aoHidd_SerialUnit_Unit
:
113 unitnum
= (ULONG
)tag
->ti_Data
;
118 } /* while (tags to process) */
120 obj
= (OOP_Object
*)OOP_DoSuperMethod(cl
, obj
, (OOP_Msg
)msg
);
124 struct IntuitionBase
* IntuitionBase
= (struct IntuitionBase
*)OpenLibrary("intuition.library",0);
125 data
= OOP_INST_DATA(cl
, obj
);
127 data
->baseaddr
= bases
[unitnum
];
129 if (NULL
!= IntuitionBase
) {
130 struct Preferences prefs
;
131 GetPrefs(&prefs
,sizeof(prefs
));
132 data
->baudrate
= prefs
.BaudRate
;
133 adapt_data(data
, &prefs
);
134 CloseLibrary((struct Library
*)IntuitionBase
);
136 data
->datalength
= 8;
137 data
->parity
= FALSE
;
138 data
->baudrate
= 9600; /* will be initialize in set_baudrate() */
140 data
->unitnum
= unitnum
;
143 CSD(cl
->UserData
)->sd_Unit
[data
->unitnum
] = data
;
146 D(bug("Unit %d at 0x0%x\n", data
->unitnum
, data
->baseaddr
));
149 serial_outp(data
, UART_LCR
, 0xBF);
150 serial_outp(data
, UART_EFR
, UART_EFR_ECB
);
151 serial_outp(data
, UART_IER
, 0);
152 serial_outp(data
, UART_EFR
, 0);
153 serial_outp(data
, UART_LCR
, 0);
155 /* clear the FIFOs */
156 serial_outp(data
, UART_FCR
, (UART_FCR_CLEAR_RCVR
| UART_FCR_CLEAR_XMIT
));
158 /* clear the interrupt registers */
159 (void)serial_inp(data
, UART_RX
);
160 (void)serial_inp(data
, UART_IIR
);
161 (void)serial_inp(data
, UART_MSR
);
163 /* initilize the UART */
164 serial_outp(data
, UART_LCR
, get_lcr(data
));
166 serial_outp(data
, UART_MCR
, UART_MCR_OUT2
| UART_MCR_DTR
| UART_MCR_RTS
);
167 serial_outp(data
, UART_IER
, UART_IER_RDI
| UART_IER_THRI
| UART_IER_RLSI
| UART_IER_MSI
);
169 /* clear the interrupt registers again ... */
170 (void)serial_inp(data
, UART_LSR
);
171 (void)serial_inp(data
, UART_RX
);
172 (void)serial_inp(data
, UART_IIR
);
173 (void)serial_inp(data
, UART_MSR
);
175 set_baudrate(data
, data
->baudrate
);
178 ReturnPtr("SerialUnit::New()", OOP_Object
*, obj
);
181 /******* SerialUnit::Dispose() ***********************************/
182 OOP_Object
*PPC4xxSerUnit__Root__Dispose(OOP_Class
*cl
, OOP_Object
*obj
, OOP_Msg msg
)
184 struct HIDDSerialUnitData
* data
;
185 EnterFunc(bug("SerialUnit::Dispose()\n"));
187 data
= OOP_INST_DATA(cl
, obj
);
190 CSD(cl
->UserData
)->units
[data
->unitnum
] = NULL
;
193 /* stop all interrupts */
194 serial_outp(data
, UART_IER
, 0);
196 OOP_DoSuperMethod(cl
, obj
, (OOP_Msg
)msg
);
197 ReturnPtr("SerialUnit::Dispose()", OOP_Object
*, obj
);
202 /******* SerialUnit::Init() **********************************/
203 BOOL
PPC4xxSerUnit__Hidd_SerialUnit__Init(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_SerialUnit_Init
*msg
)
205 struct HIDDSerialUnitData
* data
= OOP_INST_DATA(cl
, o
);
207 EnterFunc(bug("SerialUnit::Init()\n"));
209 data
->DataReceivedCallBack
= msg
->DataReceived
;
210 data
->DataReceivedUserData
= msg
->DataReceivedUserData
;
211 data
->DataWriteCallBack
= msg
->WriteData
;
212 data
->DataWriteUserData
= msg
->WriteDataUserData
;
215 ReturnBool("SerialUnit::Init()", TRUE
);
218 /******* SerialUnit::Write() **********************************/
219 ULONG
PPC4xxSerUnit__Hidd_SerialUnit__Write(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_SerialUnit_Write
*msg
)
221 struct HIDDSerialUnitData
* data
= OOP_INST_DATA(cl
, o
);
222 unsigned char status
;
223 ULONG len
= msg
->Length
;
226 EnterFunc(bug("SerialUnit::Write()\n"));
229 * If the output is currently stopped just don't do anything here.
231 if (TRUE
== data
->stopped
)
234 status
= serial_inp(data
, UART_LSR
);
236 if (status
& UART_LSR_THRE
)
238 /* write data into FIFO */
241 serial_outp(data
, UART_TX
, msg
->Outbuffer
[count
++]);
243 } while (len
> 0 && serial_inp(data
, UART_LSR
& UART_LSR_TEMT
));
246 ReturnInt("SerialUnit::Write()",ULONG
, count
);
249 /***************************************************************************/
251 static ULONG valid_baudrates
[] =
253 2 | LIMIT_LOWER_BOUND
,
254 115200 | LIMIT_UPPER_BOUND
,
259 /******* SerialUnit::SetBaudrate() **********************************/
260 BOOL
PPC4xxSerUnit__Hidd_SerialUnit__SetBaudrate(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_SerialUnit_SetBaudrate
*msg
)
262 struct HIDDSerialUnitData
* data
= OOP_INST_DATA(cl
, o
);
265 if (msg
->baudrate
!= data
->baudrate
)
267 valid
= set_baudrate(data
, msg
->baudrate
);
272 static UBYTE valid_datalengths
[] =
281 /******* SerialUnit::SetParameters() **********************************/
282 BOOL
PPC4xxSerUnit__Hidd_SerialUnit__SetParameters(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_SerialUnit_SetParameters
*msg
)
284 struct HIDDSerialUnitData
* data
= OOP_INST_DATA(cl
, o
);
287 struct TagItem
* tags
= msg
->tags
;
289 while (TAG_END
!= tags
[i
].ti_Tag
&& TRUE
== valid
)
291 switch (tags
[i
].ti_Tag
)
294 if ((BYTE
)tags
[i
].ti_Data
>= 5 && (BYTE
)tags
[i
].ti_Data
<= 8)
295 data
->datalength
= tags
[i
].ti_Data
;
300 case TAG_STOP_BITS
: /* 3 means 1.5 stopbits (if supported) */
301 if (1 == tags
[i
].ti_Data
||
302 2 == tags
[i
].ti_Data
||
303 3 == tags
[i
].ti_Data
)
304 data
->stopbits
= tags
[i
].ti_Data
;
310 if (PARITY_0
== tags
[i
].ti_Data
||
311 PARITY_1
== tags
[i
].ti_Data
||
312 PARITY_EVEN
== tags
[i
].ti_Data
||
313 PARITY_ODD
== tags
[i
].ti_Data
)
316 data
->paritytype
= tags
[i
].ti_Data
;
323 data
->parity
= FALSE
;
327 serial_outp(data
, UART_MCR
, (tags
[i
].ti_Data
& 0x0f) | 0x08);
341 serial_outp(data
, UART_LCR
, get_lcr(data
));
346 /******* SerialUnit::SendBreak() **********************************/
347 BYTE
PPC4xxSerUnit__Hidd_SerialUnit__SendBreak(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_SerialUnit_SendBreak
*msg
)
349 return SerErr_LineErr
;
352 /******* SerialUnit::Start() **********************************/
353 VOID
PPC4xxSerUnit__Hidd_SerialUnit__Start(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_SerialUnit_Start
*msg
)
355 struct HIDDSerialUnitData
* data
= OOP_INST_DATA(cl
, o
);
358 * Allow or start feeding the UART with data. Get the data
361 if (TRUE
== data
->stopped
) {
362 if (NULL
!= data
->DataWriteCallBack
)
363 data
->DataWriteCallBack(data
->unitnum
, data
->DataWriteUserData
);
365 * Also mark the stopped flag as FALSE.
367 data
->stopped
= FALSE
;
371 /******* SerialUnit::Stop() **********************************/
372 VOID
PPC4xxSerUnit__Hidd_SerialUnit__Stop(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_SerialUnit_Stop
*msg
)
374 struct HIDDSerialUnitData
* data
= OOP_INST_DATA(cl
, o
);
377 * The next time the interrupt comes along and asks for
378 * more data we just don't do anything...
380 data
->stopped
= TRUE
;
383 /****** SerialUnit::GetCapabilities ********************************/
384 VOID
PPC4xxSerUnit__Hidd_SerialUnit__GetCapabilities(OOP_Class
* cl
, OOP_Object
*o
, struct TagItem
* tags
)
392 switch (tags
[i
].ti_Tag
)
394 case HIDDA_SerialUnit_BPSRate
:
395 tags
[i
].ti_Data
= (STACKIPTR
)valid_baudrates
;
398 case HIDDA_SerialUnit_DataLength
:
399 tags
[i
].ti_Data
= (STACKIPTR
)valid_datalengths
;
411 /****** SerialUnit::GetStatus ********************************/
412 UWORD
PPC4xxSerUnit__Hidd_SerialUnit__GetStatus(OOP_Class
* cl
, OOP_Object
*o
, struct pHidd_SerialUnit_GetStatus
*msg
)
414 struct HIDDSerialUnitData
* data
= OOP_INST_DATA(cl
, o
);
416 UBYTE msr
= serial_inp(data
, UART_MSR
);
417 UBYTE mcr
= serial_inp(data
, UART_MCR
);
419 if (msr
& UART_MSR_DCD
)
421 if (msr
& UART_MSR_DSR
)
423 if (msr
& UART_MSR_CTS
)
426 if (mcr
& UART_MCR_DTR
)
428 if (mcr
& UART_MCR_RTS
)
429 status
|= (1<<6); /* old RKMs say 'ready to send' */
433 /************* The software interrupt handler that gets data from UART *****/
436 #define READBUFFER_SIZE 513
438 static AROS_UFH3(void, serialunit_receive_data
,
439 AROS_UFHA(APTR
, iD
, A1
),
440 AROS_UFHA(APTR
, iC
, A5
),
441 AROS_UFHA(struct ExecBase
*, SysBase
, A6
))
445 struct HIDDSerialUnitData
* data
= iD
;
447 UBYTE buffer
[READBUFFER_SIZE
];
450 ** Read the data from the port ...
454 buffer
[len
++] = serial_inp(data
, UART_RX
);
456 while (serial_inp(data
, UART_LSR
) & UART_LSR_DR
);
459 ** ... and deliver them to whoever is interested.
462 if (NULL
!= data
->DataReceivedCallBack
)
463 data
->DataReceivedCallBack(buffer
, len
, data
->unitnum
, data
->DataReceivedUserData
);
470 AROS_UFH3(ULONG
, serialunit_write_more_data
,
471 AROS_UFHA(APTR
, iD
, A1
),
472 AROS_UFHA(APTR
, iC
, A5
),
473 AROS_UFHA(struct ExecBase
*, SysBase
, A6
))
478 struct HIDDSerialUnitData
* data
= iD
;
481 * If the output is currently stopped just don't do
484 if (TRUE
== data
->stopped
)
488 ** Ask for more data be written to the unit
490 D(bug("Asking for more data to be written to unit %d\n",data
->unitnum
));
492 if (NULL
!= data
->DataWriteCallBack
)
493 bytes
= data
->DataWriteCallBack(data
->unitnum
, data
->DataWriteUserData
);
500 /* some help routines */
502 unsigned char get_lcr(struct HIDDSerialUnitData
* data
)
505 switch (data
->datalength
)
522 switch (data
->stopbits
)
524 case 1: /* 1 stopbit */
528 case 3: /* 1.5 stopbits (is this supported ?!!!) */
529 if (data
->datalength
== 5)
533 case 2: /* 2 stopbits */
534 if (data
->datalength
>= 6 && data
->datalength
<= 8)
542 if (TRUE
== data
->parity
)
546 switch (data
->paritytype
)
557 lcr
|= (1 << 4) | (1 << 5);
563 if (TRUE
== data
->breakcontrol
)
568 unsigned char get_fcr(ULONG baudrate
)
574 Depending on the baudrate set the fifo interrupt threshold to a
584 if (baudrate
< 38400)
590 BOOL
set_baudrate(struct HIDDSerialUnitData
* data
, ULONG speed
)
594 if (!(speed
>= 50 && speed
<= 115200))
597 quot
= CRYSTAL_SPEED
/ (speed
<< 4);
599 /* set the speed on the UART now */
600 serial_outp(data
, UART_LCR
, get_lcr(data
) | UART_LCR_DLAB
);
601 serial_outp(data
, UART_DLL
, quot
& 0xff);
602 serial_outp(data
, UART_DLM
, quot
>> 8);
603 serial_outp(data
, UART_LCR
, get_lcr(data
));
604 serial_outp(data
, UART_FCR
, get_fcr(speed
) | UART_FCR_ENABLE_FIFO
);
609 /* Serial interrupts */
611 void serial_int(void *data
, void *data2
);
613 struct HIDDSerialUnitData
*unit
= data
;
616 code
= serial_inp(unit
, UART_IIR
) & 0x07;
621 (void)serial_inp(unit
, UART_LSR
);
626 AROS_UFC3(void, serialunit_receive_data
,
627 AROS_UFCA(APTR
, unit
, A1
),
628 AROS_UFCA(APTR
, NULL
, A5
),
629 AROS_UFCA(struct ExecBase
* , SysBase
, A6
));
634 (void)serial_inp(unit
, UART_MSR
);
639 if (0 == serialunit_write_more_data(unit
, NULL
, SysBase
))
640 (void)serial_inp(unit
, UART_IIR
);
645 static void adapt_data(struct HIDDSerialUnitData
* data
,
646 struct Preferences
* prefs
)
653 switch ((prefs
->SerParShk
>> 4) & 0x0f) {
656 default: /* DEFAULT !! */
657 data
->parity
= FALSE
;
661 data
->paritytype
= PARITY_EVEN
;
665 data
->paritytype
= PARITY_ODD
;
669 data
->paritytype
= PARITY_1
;
672 data
->paritytype
= PARITY_0
;
680 switch ((prefs
->SerRWBits
& 0x0f)) {
683 data
->datalength
= 8;
687 data
->datalength
= 7;
691 data
->datalength
= 6;
695 data
->datalength
= 5;
700 * 2 stop bits ? default is '1'.
702 if (1 == (prefs
->SerStopBuf
>> 4))
708 * Handshake to be used.