2 Copyright © 1995-2001, The AROS Development Team. All rights reserved.
5 Desc: Serial Unit hidd class implementation.
10 /* the rest are Amiga includes */
11 #include <proto/exec.h>
12 #include <proto/utility.h>
13 #include <proto/oop.h>
14 #include <proto/alib.h>
15 #include <exec/libraries.h>
16 #include <exec/ports.h>
17 #include <exec/memory.h>
18 #include <exec/interrupts.h>
19 #include <exec/lists.h>
21 #include <utility/tagitem.h>
22 #include <hidd/serial.h>
23 #include <hidd/unixio.h>
26 #include <devices/serial.h>
28 #include "serial_intern.h"
29 #include <asm/registers.h>
35 #include <aros/debug.h>
37 static void serialunit_receive_data(APTR iD
, UWORD data
, struct ExecBase
*);
38 static ULONG
serialunit_write_more_data(APTR iD
, APTR iC
, struct ExecBase
*);
40 UWORD
get_ustcnt(struct HIDDSerialUnitData
* data
);
41 BOOL
set_baudrate(struct HIDDSerialUnitData
* data
, ULONG speed
);
44 * Min. and max. supported speed by the UART
47 #define MAXSPEED 230400
51 static inline void serial_out_w(struct HIDDSerialUnitData
* data
,
55 D(bug("poke.w 0x%x,0x%x\n",data
->baseaddr
+offset
,value
));
56 WREG_W((data
->baseaddr
+offset
)) = value
;
59 static inline UWORD
serial_in_w(struct HIDDSerialUnitData
* data
,
62 UWORD value
= RREG_W((data
->baseaddr
+offset
));
63 D(bug("peek.w 0x%x = 0x%x\n",data
->baseaddr
+offset
,value
));
68 static inline void serial_out_b(struct HIDDSerialUnitData
* data
,
72 D(bug("poke.b 0x%x,0x%x\n",data
->baseaddr
+offset
,value
));
73 WREG_B((data
->baseaddr
+offset
)) = value
;
77 static inline UBYTE
serial_in_b(struct HIDDSerialUnitData
* data
,
80 UBYTE value
= RREG_B(data
->baseaddr
+offset
);
81 D(bug("peek.b 0x%x = 0x%x\n",data
->baseaddr
+offset
,value
));
85 #define SysBase (CSD(cl->UserData)->sysbase)
87 /*************************** Classes *****************************/
89 /* IO bases for every COM port */
90 ULONG bases
[] = {USTCNT1
, USTCNT2
};
93 /******* SerialUnit::New() ***********************************/
94 static OOP_Object
*serialunit_new(OOP_Class
*cl
, OOP_Object
*obj
, struct pRoot_New
*msg
)
96 struct HIDDSerialUnitData
* data
;
97 struct TagItem
*tag
, *tstate
;
100 EnterFunc(bug("SerialUnit::New()\n"));
102 tstate
= msg
->attrList
;
103 while ((tag
= NextTagItem((struct TagItem
**)&tstate
))) {
106 #define csd CSD(cl->UserData)
107 if (IS_HIDDSERIALUNIT_ATTR(tag
->ti_Tag
, idx
)) {
111 case aoHidd_SerialUnit_Unit
:
112 unitnum
= (ULONG
)tag
->ti_Data
;
117 } /* while (tags to process) */
119 obj
= (OOP_Object
*)OOP_DoSuperMethod(cl
, obj
, (OOP_Msg
)msg
);
123 data
= OOP_INST_DATA(cl
, obj
);
125 data
->baseaddr
= bases
[unitnum
];
127 data
->datalength
= 8;
128 data
->parity
= FALSE
;
129 data
->baudrate
= SER_DEFAULT_BAUDRATE
;
130 data
->unitnum
= unitnum
;
132 CSD(cl
->UserData
)->units
[data
->unitnum
] = data
;
134 //D(bug("Unit %d at 0x0%x\n", data->unitnum, data->baseaddr));
136 /* Init UART - See 14-10 of dragonball documentation */
137 serial_out_w(data
, O_USTCNT
, UEN_F
| RXEN_F
| TXEN_F
| RXRE_F
);
138 dummy
= RREG_W(URX1
);
139 //D(bug("Setting baudrate now!"));
140 /* Now set the baudrate */
141 set_baudrate(data
, data
->baudrate
);
143 /* Set the interrupts and the levels according to the baudrate */
144 serial_out_w(data
, O_USTCNT
, (get_ustcnt(data
) | UEN_F
| RXEN_F
| TXEN_F
| RXRE_F
));
148 ReturnPtr("SerialUnit::New()", OOP_Object
*, obj
);
151 /******* SerialUnit::Dispose() ***********************************/
152 static OOP_Object
*serialunit_dispose(OOP_Class
*cl
, OOP_Object
*obj
, OOP_Msg msg
)
154 struct HIDDSerialUnitData
* data
;
155 EnterFunc(bug("SerialUnit::Dispose()\n"));
157 data
= OOP_INST_DATA(cl
, obj
);
159 CSD(cl
->UserData
)->units
[data
->unitnum
] = NULL
;
161 /* stop all interrupts, disabling the UART (might save power) */
162 serial_out_w(data
, O_USTCNT
, 0);
164 OOP_DoSuperMethod(cl
, obj
, (OOP_Msg
)msg
);
165 ReturnPtr("SerialUnit::Dispose()", OOP_Object
*, obj
);
170 /******* SerialUnit::Init() **********************************/
171 BOOL
serialunit_init(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_SerialUnit_Init
*msg
)
173 struct HIDDSerialUnitData
* data
= OOP_INST_DATA(cl
, o
);
175 EnterFunc(bug("SerialUnit::Init()\n"));
176 data
->DataReceivedCallBack
= msg
->DataReceived
;
177 data
->DataReceivedUserData
= msg
->DataReceivedUserData
;
178 data
->DataWriteCallBack
= msg
->WriteData
;
179 data
->DataWriteUserData
= msg
->WriteDataUserData
;
181 ReturnBool("SerialUnit::Init()", TRUE
);
184 /******* SerialUnit::Write() **********************************/
185 ULONG
serialunit_write(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_SerialUnit_Write
*msg
)
187 struct HIDDSerialUnitData
* data
= OOP_INST_DATA(cl
, o
);
188 ULONG len
= msg
->Length
;
192 EnterFunc(bug("SerialUnit::Write()\n"));
195 * If the output is currently stopped just don't do anything here.
197 if (TRUE
== data
->stopped
)
200 utx
= serial_in_w(data
, O_UTX
);
203 * I may only write something here if nothing is in the fifo right
204 * now because otherwise this might be handled through an interrupt.
206 if (utx
& FIFO_EMPTY_F
) {
207 /* write data into FIFO */
209 //D(bug("%c",msg->Outbuffer[count]));
210 serial_out_w(data
, O_UTX
, msg
->Outbuffer
[count
++]);
212 utx
= serial_in_w(data
, O_UTX
);
213 } while (len
> 0 && (utx
& TX_AVAIL_F
));
216 ReturnInt("SerialUnit::Write()",ULONG
, count
);
219 /***************************************************************************/
221 static ULONG valid_baudrates
[] =
223 MINSPEED
| LIMIT_LOWER_BOUND
,
224 MAXSPEED
| LIMIT_UPPER_BOUND
,
229 /******* SerialUnit::SetBaudrate() **********************************/
230 BOOL
serialunit_setbaudrate(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_SerialUnit_SetBaudrate
*msg
)
232 struct HIDDSerialUnitData
* data
= OOP_INST_DATA(cl
, o
);
235 if (msg
->baudrate
!= data
->baudrate
) {
236 valid
= set_baudrate(data
, msg
->baudrate
);
241 static UBYTE valid_datalengths
[] =
248 /******* SerialUnit::SetParameters() **********************************/
249 BOOL
serialunit_setparameters(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_SerialUnit_SetParameters
*msg
)
251 struct HIDDSerialUnitData
* data
= OOP_INST_DATA(cl
, o
);
254 struct TagItem
* tags
= msg
->tags
;
256 while (TAG_END
!= tags
[i
].ti_Tag
&& TRUE
== valid
) {
257 switch (tags
[i
].ti_Tag
) {
259 if (tags
[i
].ti_Data
>= 7 && tags
[i
].ti_Data
<= 8)
260 data
->datalength
= tags
[i
].ti_Data
;
266 if (1 == tags
[i
].ti_Data
||
267 2 == tags
[i
].ti_Data
)
268 data
->stopbits
= tags
[i
].ti_Data
;
274 if (PARITY_EVEN
== tags
[i
].ti_Data
||
275 PARITY_ODD
== tags
[i
].ti_Data
) {
277 data
->paritytype
= tags
[i
].ti_Data
;
284 data
->parity
= FALSE
;
301 serial_out_w(data
, O_USTCNT
, get_ustcnt(data
));
306 /******* SerialUnit::SendBreak() **********************************/
307 BYTE
serialunit_sendbreak(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_SerialUnit_SendBreak
*msg
)
309 struct HIDDSerialUnitData
* data
= OOP_INST_DATA(cl
, o
);
311 UWORD code
= serial_in_w(data
, O_UTX
);
312 serial_out_w(data
, O_UTX
, code
| SEND_BREAK_F
);
314 return SerErr_LineErr
;
317 /******* SerialUnit::Start() **********************************/
318 VOID
serialunit_start(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_SerialUnit_Start
*msg
)
320 struct HIDDSerialUnitData
* data
= OOP_INST_DATA(cl
, o
);
323 * Allow or start feeding the UART with data. Get the data
326 if (TRUE
== data
->stopped
) {
327 if (NULL
!= data
->DataWriteCallBack
)
328 data
->DataWriteCallBack(data
->unitnum
, data
->DataWriteUserData
);
330 * Also mark the stopped flag as FALSE.
332 data
->stopped
= FALSE
;
336 /******* SerialUnit::Stop() **********************************/
337 VOID
serialunit_stop(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_SerialUnit_Stop
*msg
)
339 struct HIDDSerialUnitData
* data
= OOP_INST_DATA(cl
, o
);
342 * The next time the interrupt comes along and asks for
343 * more data we just don't do anything...
345 data
->stopped
= TRUE
;
348 /****** SerialUnit::GetCapabilities ********************************/
349 VOID
serialunit_getcapabilities(OOP_Class
* cl
, OOP_Object
*o
, struct TagItem
* tags
)
354 while (FALSE
== end
) {
355 switch (tags
[i
].ti_Tag
) {
356 case HIDDA_SerialUnit_BPSRate
:
357 tags
[i
].ti_Data
= (STACKIPTR
)valid_baudrates
;
360 case HIDDA_SerialUnit_DataLength
:
361 tags
[i
].ti_Data
= (STACKIPTR
)valid_datalengths
;
373 /****** SerialUnit::GetStatus ********************************/
374 UWORD
serialunit_getstatus(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_SerialUnit_GetStatus
*msg
)
376 struct HIDDSerialUnitData
* data
= OOP_INST_DATA(cl
, o
);
388 /************* The function that gets data from UART *****/
395 #define READBUFFER_SIZE 65
397 static void serialunit_receive_data(APTR iD
, UWORD urx
, struct ExecBase
* SysBase
)
399 struct HIDDSerialUnitData
* data
= iD
;
401 UBYTE buffer
[READBUFFER_SIZE
];
404 ** Read the data from the port ...
405 ** !!! The xcopilot implementation seem rather stupid. I can only get one
406 ** byte per interrupt. I hope the real thing is a bit better... !!!
408 while (len
< sizeof(buffer
)) {
409 buffer
[len
++] = (UBYTE
)urx
;
410 //D(bug("Got byte form serial port: %d (%c)\n",(UBYTE)urx,(UBYTE)urx));
413 * Check for the next incoming byte - whether there is one.
414 * I have to do it this way, because xcopilot returns no
415 * DATA_READY flag once the register is read with 16 bit access.
417 urx
= serial_in_w(data
, O_URX
);
418 if (0 == (DATA_READY_F
& urx
)) {
424 ** ... and deliver them to whoever is interested.
427 if (NULL
!= data
->DataReceivedCallBack
)
428 data
->DataReceivedCallBack(buffer
, len
, data
->unitnum
, data
->DataReceivedUserData
);
431 static ULONG
serialunit_write_more_data(APTR iD
, APTR iC
, struct ExecBase
* SysBase
)
433 struct HIDDSerialUnitData
* data
= iD
;
436 * If the output is currently stopped just don't do
439 if (TRUE
== data
->stopped
)
443 ** Ask for more data be written to the unit
445 // D(bug("Asking for more data to be written to unit %d\n",data->unitnum));
447 if (NULL
!= data
->DataWriteCallBack
)
448 data
->DataWriteCallBack(data
->unitnum
, data
->DataWriteUserData
);
453 /******* init_serialunitclass ********************************/
455 #define SysBase (csd->sysbase)
456 #define OOPBase (csd->oopbase)
457 #define UtilityBase (csd->utilitybase)
460 #define NUM_ROOT_METHODS 2
461 #define NUM_SERIALUNIT_METHODS moHidd_SerialUnit_NumMethods
463 OOP_Class
*init_serialunitclass (struct class_static_data
*csd
)
465 OOP_Class
*cl
= NULL
;
467 struct OOP_MethodDescr serialunithiddroot_descr
[NUM_ROOT_METHODS
+ 1] =
469 {(IPTR (*)())serialunit_new
, moRoot_New
},
470 {(IPTR (*)())serialunit_dispose
, moRoot_Dispose
},
472 {(IPTR (*)())serialunit_set, moRoot_Set},
473 {(IPTR (*)())serialunit_get, moRoot_Get},
478 struct OOP_MethodDescr serialunithidd_descr
[NUM_SERIALUNIT_METHODS
+ 1] =
480 {(IPTR (*)())serialunit_init
, moHidd_SerialUnit_Init
},
481 {(IPTR (*)())serialunit_write
, moHidd_SerialUnit_Write
},
482 {(IPTR (*)())serialunit_setbaudrate
, moHidd_SerialUnit_SetBaudrate
},
483 {(IPTR (*)())serialunit_setparameters
, moHidd_SerialUnit_SetParameters
},
484 {(IPTR (*)())serialunit_sendbreak
, moHidd_SerialUnit_SendBreak
},
485 {(IPTR (*)())serialunit_start
, moHidd_SerialUnit_Start
},
486 {(IPTR (*)())serialunit_stop
, moHidd_SerialUnit_Stop
},
487 {(IPTR (*)())serialunit_getcapabilities
,moHidd_SerialUnit_GetCapabilities
},
488 {(IPTR (*)())serialunit_getstatus
,moHidd_SerialUnit_GetStatus
},
492 struct OOP_InterfaceDescr ifdescr
[] =
494 {serialunithiddroot_descr
, IID_Root
, NUM_ROOT_METHODS
},
495 {serialunithidd_descr
, IID_Hidd_SerialUnit
, NUM_SERIALUNIT_METHODS
},
499 OOP_AttrBase MetaAttrBase
= OOP_GetAttrBase(IID_Meta
);
501 struct TagItem tags
[] =
503 { aMeta_SuperID
, (IPTR
)CLID_Root
},
504 { aMeta_InterfaceDescr
, (IPTR
)ifdescr
},
505 { aMeta_ID
, (IPTR
)CLID_Hidd_SerialUnit
},
506 { aMeta_InstSize
, (IPTR
)sizeof (struct HIDDSerialUnitData
) },
511 EnterFunc(bug(" init_serialunitclass(csd=%p)\n", csd
));
513 cl
= OOP_NewObject(NULL
, CLID_HiddMeta
, tags
);
514 D(bug("Class=%p\n", cl
));
516 __IHidd_SerialUnitAB
= OOP_ObtainAttrBase(IID_Hidd_SerialUnit
);
517 if (NULL
!= __IHidd_SerialUnitAB
) {
518 D(bug("SerialUnit Class ok\n"));
519 cl
->UserData
= (APTR
)csd
;
523 free_serialunitclass(csd
);
528 ReturnPtr("init_serialunitclass", OOP_Class
*, cl
);
532 void free_serialunitclass(struct class_static_data
*csd
)
534 EnterFunc(bug("free_serialhiddclass(csd=%p)\n", csd
));
537 OOP_RemoveClass(csd
->serialhiddclass
);
539 if(csd
->serialhiddclass
) OOP_DisposeObject((OOP_Object
*) csd
->serialhiddclass
);
540 csd
->serialhiddclass
= NULL
;
543 ReturnVoid("free_serialhiddclass");
547 UWORD
get_ustcnt(struct HIDDSerialUnitData
* data
)
550 switch (data
->datalength
) {
551 case 8: ustcnt
|= EITHER8OR7_F
;
555 switch (data
->stopbits
) {
556 case 1: /* 1 stopbit */
560 case 2: /* 2 stopbits */
568 if (TRUE
== data
->parity
) {
569 ustcnt
|= PARITY_EN_F
;
571 switch (data
->paritytype
) {
578 if (data
->baudrate
< 1200) {
579 ustcnt
|= /*RXFE_F|RXHE_F|*/ RXRE_F
| /* TXEE_F|*/ TXHE_F
;
580 } else if (data
->baudrate
< 9600) {
581 ustcnt
|= /* RXHE_F|*/ RXRE_F
| /* TXEE_F|*/ TXHE_F
;
583 ustcnt
|= RXRE_F
|TXHE_F
;
589 struct baud_rate_settings
597 * For a default 33.16Mhz system clock
599 static const struct baud_rate_settings brs
[] =
616 BOOL
set_baudrate(struct HIDDSerialUnitData
* data
, ULONG speed
)
618 /* set the speed on the UART now */
619 #warning Which bits to set in ubaud???
624 if (speed
< MINSPEED
|| speed
> MAXSPEED
)
627 while (~0 != brs
[i
].baudrate
) {
628 if (speed
== brs
[i
].baudrate
) {
629 ubaud
|= (((UWORD
)brs
[i
].divider
) << 8) | brs
[i
].prescaler
;
636 if (FALSE
== found
) {
642 ULONG _prescaler
= 0;
644 * Try to calculate the parameters for this odd baudrate.
645 * Don't know whether this is correct...
647 while (divider
> 0) {
648 prescaler
= (2073600/(1<<divider
))/speed
;
650 * Calculate backwards and see how good this
651 * result is (due to integer rounding of the
652 * previous divisions).
657 if (prescaler
< 65) {
658 val
= prescaler
*(1<<divider
);
662 _prescaler
= prescaler
;
669 ubaud
|= (((UWORD
)_divider
) << 8) | (65-_prescaler
);
672 serial_out_w(data
, O_UBAUD
, ubaud
);
676 /* Serial interrupts */
679 #define SysBase (hw->sysBase)
680 #define csd ((struct class_static_data *)(irq->h_Data))
683 static void common_serial_int_handler(HIDDT_IRQ_Handler
* irq
,
684 HIDDT_IRQ_HwInfo
* hw
,
688 if (csd
->units
[unitnum
]) {
689 code
= serial_in_w(csd
->units
[unitnum
], O_URX
);
692 //D(bug("---------- IN COMMON SERIAL HANDLER!\n"));
693 //D(bug("URX: code=0x%x\n",code));
694 if (code
& (FIFO_EMPTY_F
|FIFO_HALF_F
|DATA_READY_F
)) {
695 D(bug("In %s 1\n",__FUNCTION__
));
696 if (csd
->units
[unitnum
]) {
697 serialunit_receive_data(csd
->units
[unitnum
],
704 if (csd
->units
[unitnum
])
705 code
= serial_in_w(csd
->units
[unitnum
], O_UTX
);
707 //D(bug("UTX: code=0x%x\n",code));
708 if (code
& (FIFO_EMPTY_F
|FIFO_HALF_F
|TX_AVAIL_F
)) {
709 D(bug("In %s 2\n",__FUNCTION__
));
710 if (csd
->units
[unitnum
]) {
711 if (0 == serialunit_write_more_data(csd
->units
[unitnum
],
720 void serial_int_uart1(HIDDT_IRQ_Handler
*irq
, HIDDT_IRQ_HwInfo
*hw
)
722 common_serial_int_handler(irq
, hw
, 0);
725 void serial_int_uart2(HIDDT_IRQ_Handler
*irq
, HIDDT_IRQ_HwInfo
*hw
)
727 common_serial_int_handler(irq
, hw
, 1);