revert between 56095 -> 55830 in arch
[AROS.git] / arch / ppc-sam440 / serial.hidd / SerialUnitClass.c
blob49d68cdcb8534ea41db507da011f356e70494c23
1 /*
2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Serial Unit hidd class implementation.
6 Lang: english
7 */
9 /*
10 Right now I am assuming that there is a 1.8432 MHZ crystal connected to
11 the 16550 UART.
15 #include <asm/io.h>
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>
33 #include <hidd/irq.h>
34 #include <intuition/preferences.h>
36 #include <devices/serial.h>
38 #include "serial_intern.h"
40 #undef SDEBUG
41 #undef DEBUG
42 #define SDEBUG 0
43 #define DEBUG 0
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,
60 int offset,
61 int value)
63 outb(value, data->baseaddr+offset);
66 static inline void serial_outp(struct HIDDSerialUnitData * data,
67 int offset,
68 int value)
70 outb_p(value, data->baseaddr+offset);
73 static inline unsigned int serial_in(struct HIDDSerialUnitData * data,
74 int offset)
76 return inb(data->baseaddr+offset);
79 static inline unsigned int serial_inp(struct HIDDSerialUnitData * data,
80 int offset)
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;
97 ULONG unitnum = 0;
99 EnterFunc(bug("SerialUnit::New()\n"));
101 tstate = msg->attrList;
102 while ((tag = NextTagItem(&tstate)))
104 ULONG idx;
106 #define csd CSD(cl->UserData)
107 if (IS_HIDDSERIALUNIT_ATTR(tag->ti_Tag, idx))
108 #undef csd
110 switch (idx)
112 case aoHidd_SerialUnit_Unit:
113 unitnum = (ULONG)tag->ti_Data;
114 break;
118 } /* while (tags to process) */
120 obj = (OOP_Object *)OOP_DoSuperMethod(cl, obj, (OOP_Msg)msg);
122 if (obj)
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);
135 } else {
136 data->datalength = 8;
137 data->parity = FALSE;
138 data->baudrate = 9600; /* will be initialize in set_baudrate() */
140 data->unitnum = unitnum;
142 Disable();
143 CSD(cl->UserData)->sd_Unit[data->unitnum] = data;
144 Enable();
146 D(bug("Unit %d at 0x0%x\n", data->unitnum, data->baseaddr));
148 /* Wake up UART */
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);
176 } /* if (obj) */
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);
189 Disable();
190 CSD(cl->UserData)->units[data->unitnum] = NULL;
191 Enable();
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"));
208 Disable();
209 data->DataReceivedCallBack = msg->DataReceived;
210 data->DataReceivedUserData = msg->DataReceivedUserData;
211 data->DataWriteCallBack = msg->WriteData;
212 data->DataWriteUserData = msg->WriteDataUserData;
213 Enable();
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;
224 ULONG count = 0;
226 EnterFunc(bug("SerialUnit::Write()\n"));
229 * If the output is currently stopped just don't do anything here.
231 if (TRUE == data->stopped)
232 return 0;
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++]);
242 len--;
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);
263 BOOL valid = FALSE;
265 if (msg->baudrate != data->baudrate)
267 valid = set_baudrate(data, msg->baudrate);
268 } /* if */
269 return valid;
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);
285 BOOL valid = TRUE;
286 int i = 0;
287 struct TagItem * tags = msg->tags;
289 while (TAG_END != tags[i].ti_Tag && TRUE == valid)
291 switch (tags[i].ti_Tag)
293 case TAG_DATALENGTH:
294 if ((BYTE)tags[i].ti_Data >= 5 && (BYTE)tags[i].ti_Data <= 8)
295 data->datalength = tags[i].ti_Data;
296 else
297 valid = FALSE;
298 break;
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;
305 else
306 valid = FALSE;
307 break;
309 case TAG_PARITY:
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)
315 data->parity = TRUE;
316 data->paritytype = tags[i].ti_Data;
318 else
319 valid = FALSE;
320 break;
322 case TAG_PARITY_OFF:
323 data->parity = FALSE;
324 break;
326 case TAG_SET_MCR:
327 serial_outp(data, UART_MCR, (tags[i].ti_Data & 0x0f) | 0x08);
328 break;
330 case TAG_SKIP:
331 case TAG_IGNORE:
332 break;
334 default:
335 valid = FALSE;
337 i++;
340 if (TRUE == valid)
341 serial_outp(data, UART_LCR, get_lcr(data));
343 return valid;
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
359 * from upper layer.
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)
386 if (NULL != tags)
388 int i = 0;
389 BOOL end = FALSE;
390 while (FALSE == end)
392 switch (tags[i].ti_Tag)
394 case HIDDA_SerialUnit_BPSRate:
395 tags[i].ti_Data = (STACKIPTR)valid_baudrates;
396 break;
398 case HIDDA_SerialUnit_DataLength:
399 tags[i].ti_Data = (STACKIPTR)valid_datalengths;
400 break;
402 case TAG_DONE:
403 end = TRUE;
404 break;
406 i++;
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);
415 UWORD status = 0;
416 UBYTE msr = serial_inp(data, UART_MSR);
417 UBYTE mcr = serial_inp(data, UART_MCR);
419 if (msr & UART_MSR_DCD)
420 status |= (1<<5);
421 if (msr & UART_MSR_DSR)
422 status |= (1<<3);
423 if (msr & UART_MSR_CTS)
424 status |= (1<<4);
426 if (mcr & UART_MCR_DTR)
427 status |= (1<<7);
428 if (mcr & UART_MCR_RTS)
429 status |= (1<<6); /* old RKMs say 'ready to send' */
430 return status;
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))
443 AROS_USERFUNC_INIT
445 struct HIDDSerialUnitData * data = iD;
446 int len = 0;
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);
465 return;
467 AROS_USERFUNC_EXIT
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))
475 AROS_USERFUNC_INIT
477 ULONG bytes = 0;
478 struct HIDDSerialUnitData * data = iD;
481 * If the output is currently stopped just don't do
482 * anything here.
484 if (TRUE == data->stopped)
485 return 0;
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);
494 return bytes;
496 AROS_USERFUNC_EXIT
500 /* some help routines */
502 unsigned char get_lcr(struct HIDDSerialUnitData * data)
504 char lcr;
505 switch (data->datalength)
507 case 5: lcr = 0;
508 break;
510 case 6: lcr = 1;
511 break;
513 case 7: lcr = 2;
514 break;
516 case 8: lcr = 3;
517 break;
519 default: lcr = 3;
522 switch (data->stopbits)
524 case 1: /* 1 stopbit */
525 /* nothing to do */
526 break;
528 case 3: /* 1.5 stopbits (is this supported ?!!!) */
529 if (data->datalength == 5)
530 lcr |= (1 << 2);
531 break;
533 case 2: /* 2 stopbits */
534 if (data->datalength >= 6 && data->datalength <= 8)
535 lcr |= (1 << 2);
536 break;
538 default:
539 break;
542 if (TRUE == data->parity)
544 lcr |= (1 << 3);
546 switch (data->paritytype)
548 case PARITY_EVEN:
549 lcr |= (1 << 4);
550 break;
552 case PARITY_1:
553 lcr |= (1 << 5);
554 break;
556 case PARITY_0:
557 lcr |= (1 << 4) | (1 << 5);
558 break;
563 if (TRUE == data->breakcontrol)
564 lcr |= (1 << 6);
565 return lcr;
568 unsigned char get_fcr(ULONG baudrate)
570 unsigned char fcr;
571 fcr = (1 << 0);
574 Depending on the baudrate set the fifo interrupt threshold to a
575 different value.
578 if (baudrate < 1200)
579 fcr |= (3 << 6);
580 else
581 if (baudrate < 9600)
582 fcr |= (2 << 6);
583 else
584 if (baudrate < 38400)
585 fcr |= (1 << 6);
587 return fcr;
590 BOOL set_baudrate(struct HIDDSerialUnitData * data, ULONG speed)
592 int quot;
594 if (!(speed >= 50 && speed <= 115200))
595 return FALSE;
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);
606 return TRUE;
609 /* Serial interrupts */
611 void serial_int(void *data, void *data2);
613 struct HIDDSerialUnitData *unit = data;
615 if (unit)
616 code = serial_inp(unit, UART_IIR) & 0x07;
618 switch (code)
620 case UART_IIR_RLSI:
621 (void)serial_inp(unit, UART_LSR);
622 break;
624 case UART_IIR_RDI:
625 if (unit) {
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));
631 break;
633 case UART_IIR_MSI:
634 (void)serial_inp(unit, UART_MSR);
635 break;
637 case UART_IIR_THRI:
638 if (unit)
639 if (0 == serialunit_write_more_data(unit, NULL, SysBase))
640 (void)serial_inp(unit, UART_IIR);
641 break;
645 static void adapt_data(struct HIDDSerialUnitData * data,
646 struct Preferences * prefs)
649 * Parity.
651 data->parity = TRUE;
653 switch ((prefs->SerParShk >> 4) & 0x0f) {
655 case SPARITY_NONE:
656 default: /* DEFAULT !! */
657 data->parity = FALSE;
658 break;
660 case SPARITY_EVEN:
661 data->paritytype = PARITY_EVEN;
662 break;
664 case SPARITY_ODD:
665 data->paritytype = PARITY_ODD;
666 break;
668 case SPARITY_MARK:
669 data->paritytype = PARITY_1;
670 break;
671 case SPARITY_SPACE:
672 data->paritytype = PARITY_0;
673 break;
678 * Bit per character
680 switch ((prefs->SerRWBits & 0x0f)) {
681 default: /* 8 bit */
682 case 0:
683 data->datalength = 8;
684 break;
686 case 1: /* 7 bit */
687 data->datalength = 7;
688 break;
690 case 2: /* 6 bit */
691 data->datalength = 6;
692 break;
694 case 3: /* 5 bit */
695 data->datalength = 5;
696 break;
700 * 2 stop bits ? default is '1'.
702 if (1 == (prefs->SerStopBuf >> 4))
703 data->stopbits = 2;
704 else
705 data->stopbits = 1;
708 * Handshake to be used.
710 // MISSING!