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 void serialunit_receive_data();
38 void serialunit_write_more_data();
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
49 static inline void serial_out_w(struct HIDDSerialUnitData
* data
,
53 WREG_W((data
->baseaddr
+offset
)) = value
;
56 static inline unsigned int serial_in_w(struct HIDDSerialUnitData
* data
,
59 return RREG_W(data
->baseaddr
+offset
);
62 /*************************** Classes *****************************/
64 /* IO bases for every COM port */
65 ULONG bases
[] = {USTCNT1
, USTCNT2
};
68 /******* SerialUnit::New() ***********************************/
69 static OOP_Object
*serialunit_new(OOP_Class
*cl
, OOP_Object
*obj
, struct pRoot_New
*msg
)
71 struct HIDDSerialUnitData
* data
;
72 struct TagItem
*tag
, *tstate
;
75 EnterFunc(bug("SerialUnit::New()\n"));
77 tstate
= msg
->attrList
;
78 while ((tag
= NextTagItem((const struct TagItem
**)&tstate
))) {
81 #define csd CSD(cl->UserData)
82 if (IS_HIDDSERIALUNIT_ATTR(tag
->ti_Tag
, idx
)) {
86 case aoHidd_SerialUnit_Unit
:
87 unitnum
= (ULONG
)tag
->ti_Data
;
92 } /* while (tags to process) */
94 obj
= (OOP_Object
*)OOP_DoSuperMethod(cl
, obj
, (OOP_Msg
)msg
);
98 data
= OOP_INST_DATA(cl
, obj
);
100 data
->baseaddr
= bases
[unitnum
];
102 data
->datalength
= 8;
103 data
->parity
= FALSE
;
104 data
->baudrate
= 0; /* will be initialize in set_baudrate() */
105 data
->unitnum
= unitnum
;
107 CSD(cl
->UserData
)->units
[data
->unitnum
] = data
;
109 D(bug("Unit %d at 0x0%x\n", data
->unitnum
, data
->baseaddr
));
111 /* Init UART - See 14-10 of dragonball documentation */
112 serial_out_w(data
,USTCNT
, UEN
| RXEN
);
113 dummy
= RREG_W(URX1
);
114 serial_out_w(data
, USTCNT
, (get_ustcnt(data
) | UEN
| RXEN
| TXEN
));
116 set_baudrate(data
, SER_DEFAULT_BAUDRATE
);
119 ReturnPtr("SerialUnit::New()", OOP_Object
*, obj
);
122 /******* SerialUnit::Dispose() ***********************************/
123 static OOP_Object
*serialunit_dispose(OOP_Class
*cl
, OOP_Object
*obj
, OOP_Msg msg
)
125 struct HIDDSerialUnitData
* data
;
126 EnterFunc(bug("SerialUnit::Dispose()\n"));
128 data
= OOP_INST_DATA(cl
, obj
);
130 CSD(cl
->UserData
)->units
[data
->unitnum
] = NULL
;
132 /* stop all interrupts, disabling the UART (might save power) */
133 serial_out_w(data
, USTCNT
, 0);
135 OOP_DoSuperMethod(cl
, obj
, (OOP_Msg
)msg
);
136 ReturnPtr("SerialUnit::Dispose()", OOP_Object
*, obj
);
141 /******* SerialUnit::Init() **********************************/
142 BOOL
serialunit_init(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_SerialUnit_Init
*msg
)
144 struct HIDDSerialUnitData
* data
= OOP_INST_DATA(cl
, o
);
146 EnterFunc(bug("SerialUnit::Init()\n"));
147 data
->DataReceivedCallBack
= msg
->DataReceived
;
148 data
->DataReceivedUserData
= msg
->DataReceivedUserData
;
149 data
->DataWriteCallBack
= msg
->WriteData
;
150 data
->DataWriteUserData
= msg
->WriteDataUserData
;
152 ReturnBool("SerialUnit::Init()", TRUE
);
155 /******* SerialUnit::Write() **********************************/
156 ULONG
serialunit_write(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_SerialUnit_Write
*msg
)
158 struct HIDDSerialUnitData
* data
= OOP_INST_DATA(cl
, o
);
159 ULONG len
= msg
->Length
;
163 EnterFunc(bug("SerialUnit::Write()\n"));
166 * If the output is currently stopped just don't do anything here.
168 if (TRUE
== data
->stopped
)
171 utx
= serial_in_w(data
, UTX
);
174 * I may only write something here if nothing is in the fifo right
175 * now because otherwise this might be handled through an interrupt.
177 if (utx
& FIFO_EMPTY
) {
178 /* write data into FIFO */
180 serial_out_w(data
, UTX
, msg
->Outbuffer
[count
++]);
182 utx
= serial_in_w(data
, UTX
);
183 } while (len
> 0 && (utx
& TX_AVAIL
));
186 ReturnInt("SerialUnit::Write()",ULONG
, count
);
189 /***************************************************************************/
191 static ULONG valid_baudrates
[] =
193 MINSPEED
| LIMIT_LOWER_BOUND
,
194 MAXSPEED
| LIMIT_UPPER_BOUND
,
199 /******* SerialUnit::SetBaudrate() **********************************/
200 BOOL
serialunit_setbaudrate(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_SerialUnit_SetBaudrate
*msg
)
202 struct HIDDSerialUnitData
* data
= OOP_INST_DATA(cl
, o
);
205 if (msg
->baudrate
!= data
->baudrate
) {
206 valid
= set_baudrate(data
, msg
->baudrate
);
211 static UBYTE valid_datalengths
[] =
218 /******* SerialUnit::SetParameters() **********************************/
219 BOOL
serialunit_setparameters(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_SerialUnit_SetParameters
*msg
)
221 struct HIDDSerialUnitData
* data
= OOP_INST_DATA(cl
, o
);
224 struct TagItem
* tags
= msg
->tags
;
226 while (TAG_END
!= tags
[i
].ti_Tag
&& TRUE
== valid
) {
227 switch (tags
[i
].ti_Tag
) {
229 if (tags
[i
].ti_Data
>= 7 && tags
[i
].ti_Data
<= 8)
230 data
->datalength
= tags
[i
].ti_Data
;
236 if (1 == tags
[i
].ti_Data
||
237 2 == tags
[i
].ti_Data
)
238 data
->stopbits
= tags
[i
].ti_Data
;
244 if (PARITY_EVEN
== tags
[i
].ti_Data
||
245 PARITY_ODD
== tags
[i
].ti_Data
) {
247 data
->paritytype
= tags
[i
].ti_Data
;
254 data
->parity
= FALSE
;
259 // serial_out_w(data, UART_MCR, (tags[i].ti_Data & 0x0f) | 0x08);
272 serial_out_w(data
, USTCNT
, get_ustcnt(data
));
277 /******* SerialUnit::SendBreak() **********************************/
278 BYTE
serialunit_sendbreak(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_SerialUnit_SendBreak
*msg
)
280 struct HIDDSerialUnitData
* data
= OOP_INST_DATA(cl
, o
);
282 return SerErr_LineErr
;
285 /******* SerialUnit::Start() **********************************/
286 VOID
serialunit_start(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_SerialUnit_Start
*msg
)
288 struct HIDDSerialUnitData
* data
= OOP_INST_DATA(cl
, o
);
291 * Allow or start feeding the UART with data. Get the data
294 if (TRUE
== data
->stopped
) {
295 if (NULL
!= data
->DataWriteCallBack
)
296 data
->DataWriteCallBack(data
->unitnum
, data
->DataWriteUserData
);
298 * Also mark the stopped flag as FALSE.
300 data
->stopped
= FALSE
;
304 /******* SerialUnit::Stop() **********************************/
305 VOID
serialunit_stop(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_SerialUnit_Stop
*msg
)
307 struct HIDDSerialUnitData
* data
= OOP_INST_DATA(cl
, o
);
310 * The next time the interrupt comes along and asks for
311 * more data we just don't do anything...
313 data
->stopped
= TRUE
;
316 /****** SerialUnit::GetCapabilities ********************************/
317 VOID
serialunit_getcapabilities(OOP_Class
* cl
, OOP_Object
*o
, struct TagItem
* tags
)
322 while (FALSE
== end
) {
323 switch (tags
[i
].ti_Tag
) {
324 case HIDDA_SerialUnit_BPSRate
:
325 tags
[i
].ti_Data
= (STACKIPTR
)valid_baudrates
;
328 case HIDDA_SerialUnit_DataLength
:
329 tags
[i
].ti_Data
= (STACKIPTR
)valid_datalengths
;
341 /****** SerialUnit::GetStatus ********************************/
342 UWORD
serialunit_getstatus(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_SerialUnit_GetStatus
*msg
)
344 struct HIDDSerialUnitData
* data
= OOP_INST_DATA(cl
, o
);
355 /************* The software interrupt handler that gets data from UART *****/
362 #define READBUFFER_SIZE 65
364 AROS_UFH3(void, serialunit_receive_data
,
365 AROS_UFHA(APTR
, iD
, A1
),
366 AROS_UFHA(APTR
, iC
, A5
),
367 AROS_UFHA(struct ExecBase
*, SysBase
, A6
))
369 struct HIDDSerialUnitData
* data
= iD
;
372 UBYTE buffer
[READBUFFER_SIZE
];
375 ** Read the data from the port ...
378 urx
= serial_in_w(data
, URX
);
379 if (urx
& DATA_READY
)
380 buffer
[len
++] = (UBYTE
)urx
;
386 ** ... and deliver them to whoever is interested.
389 if (NULL
!= data
->DataReceivedCallBack
)
390 data
->DataReceivedCallBack(buffer
, len
, data
->unitnum
, data
->DataReceivedUserData
);
393 AROS_UFH3(void, serialunit_write_more_data
,
394 AROS_UFHA(APTR
, iD
, A1
),
395 AROS_UFHA(APTR
, iC
, A5
),
396 AROS_UFHA(struct ExecBase
*, SysBase
, A6
))
398 struct HIDDSerialUnitData
* data
= iD
;
401 * If the output is currently stopped just don't do
404 if (TRUE
== data
->stopped
)
408 ** Ask for more data be written to the unit
410 D(bug("Asking for more data to be written to unit %d\n",data
->unitnum
));
412 if (NULL
!= data
->DataWriteCallBack
)
413 data
->DataWriteCallBack(data
->unitnum
, data
->DataWriteUserData
);
417 /******* init_serialunitclass ********************************/
419 #define SysBase (csd->sysbase)
420 #define OOPBase (csd->oopbase)
421 #define UtilityBase (csd->utilitybase)
424 #define NUM_ROOT_METHODS 2
425 #define NUM_SERIALUNIT_METHODS moHidd_SerialUnit_NumMethods
427 OOP_Class
*init_serialunitclass (struct class_static_data
*csd
)
429 OOP_Class
*cl
= NULL
;
431 struct OOP_MethodDescr serialunithiddroot_descr
[NUM_ROOT_METHODS
+ 1] =
433 {(IPTR (*)())serialunit_new
, moRoot_New
},
434 {(IPTR (*)())serialunit_dispose
, moRoot_Dispose
},
436 {(IPTR (*)())serialunit_set, moRoot_Set},
437 {(IPTR (*)())serialunit_get, moRoot_Get},
442 struct OOP_MethodDescr serialunithidd_descr
[NUM_SERIALUNIT_METHODS
+ 1] =
444 {(IPTR (*)())serialunit_init
, moHidd_SerialUnit_Init
},
445 {(IPTR (*)())serialunit_write
, moHidd_SerialUnit_Write
},
446 {(IPTR (*)())serialunit_setbaudrate
, moHidd_SerialUnit_SetBaudrate
},
447 {(IPTR (*)())serialunit_setparameters
, moHidd_SerialUnit_SetParameters
},
448 {(IPTR (*)())serialunit_sendbreak
, moHidd_SerialUnit_SendBreak
},
449 {(IPTR (*)())serialunit_start
, moHidd_SerialUnit_Start
},
450 {(IPTR (*)())serialunit_stop
, moHidd_SerialUnit_Stop
},
451 {(IPTR (*)())serialunit_getcapabilities
,moHidd_SerialUnit_GetCapabilities
},
452 {(IPTR (*)())serialunit_getstatus
,moHidd_SerialUnit_GetStatus
},
456 struct OOP_InterfaceDescr ifdescr
[] =
458 {serialunithiddroot_descr
, IID_Root
, NUM_ROOT_METHODS
},
459 {serialunithidd_descr
, IID_Hidd_SerialUnit
, NUM_SERIALUNIT_METHODS
},
463 OOP_AttrBase MetaAttrBase
= OOP_GetAttrBase(IID_Meta
);
465 struct TagItem tags
[] =
467 { aMeta_SuperID
, (IPTR
)CLID_Root
},
468 { aMeta_InterfaceDescr
, (IPTR
)ifdescr
},
469 { aMeta_ID
, (IPTR
)CLID_Hidd_SerialUnit
},
470 { aMeta_InstSize
, (IPTR
)sizeof (struct HIDDSerialUnitData
) },
475 EnterFunc(bug(" init_serialunitclass(csd=%p)\n", csd
));
477 cl
= OOP_NewObject(NULL
, CLID_HiddMeta
, tags
);
478 D(bug("Class=%p\n", cl
));
480 __IHidd_SerialUnitAB
= OOP_ObtainAttrBase(IID_Hidd_SerialUnit
);
481 if (NULL
!= __IHidd_SerialUnitAB
) {
482 D(bug("SerialUnit Class ok\n"));
483 cl
->UserData
= (APTR
)csd
;
487 free_serialunitclass(csd
);
492 ReturnPtr("init_serialunitclass", OOP_Class
*, cl
);
496 void free_serialunitclass(struct class_static_data
*csd
)
498 EnterFunc(bug("free_serialhiddclass(csd=%p)\n", csd
));
501 OOP_RemoveClass(csd
->serialhiddclass
);
503 if(csd
->serialhiddclass
) OOP_DisposeObject((OOP_Object
*) csd
->serialhiddclass
);
504 csd
->serialhiddclass
= NULL
;
507 ReturnVoid("free_serialhiddclass");
511 UWORD
get_ustcnt(struct HIDDSerialUnitData
* data
)
514 switch (data
->datalength
) {
515 case 8: ustcnt
|= EITHER8OR7
;
519 switch (data
->stopbits
) {
520 case 1: /* 1 stopbit */
524 case 2: /* 2 stopbits */
531 if (TRUE
== data
->parity
) {
534 switch (data
->paritytype
) {
541 if (data
->baudrate
< 1200) {
542 ustcnt
|= /*RXFE|RXHE|*/ RXRE
| /* TXEE|*/ TXHE
;
543 } else if (data
->baudrate
< 9600) {
544 ustcnt
|= /* RXHE|*/ RXRE
| /* TXEE|*/ TXHE
;
552 struct baud_rate_settings
560 * For a default 33.16Mhz system clock
562 static const struct baud_rate_settings brs
[] =
579 BOOL
set_baudrate(struct HIDDSerialUnitData
* data
, ULONG speed
)
581 /* set the speed on the UART now */
582 #warning Which bits to set in ubaud???
587 if (speed
< MINSPEED
|| speed
> MAXSPEED
)
590 while (~0 != brs
[i
].baudrate
) {
591 if (speed
== brs
[i
].baudrate
) {
592 ubaud
|= (((UWORD
)brs
[i
].divider
) << 8) | brs
[i
].prescaler
;
598 if (FALSE
== found
) {
604 ULONG _prescaler
= 0;
606 * Try to calculate the parameters for this odd baudrate.
607 * Don't know whether this is correct...
609 while (divider
> 0) {
610 prescaler
= (2073600/(1<<divider
))/speed
;
612 * Calculate backwards and see how good this
613 * result is (due to integer rounding of the
614 * previous divisions).
619 if (prescaler
< 65) {
620 val
= prescaler
*(1<<divider
);
624 _prescaler
= prescaler
;
631 ubaud
|= (((UWORD
)_divider
) << 8) | (65-_prescaler
);
634 serial_out_w(data
, UBAUD
, ubaud
);
638 /* Serial interrupts */
643 #define SysBase (hw->sysBase)
644 #define csd ((struct class_static_data *)(irq->h_Data))
646 void serial_int_13(HIDDT_IRQ_Handler
*irq
, HIDDT_IRQ_HwInfo
*hw
)