Updated PCI IDs to latest snapshot.
[tangerine.git] / arch / all-unix / hidd / serial / SerialUnitClass.c
blob9bc9e96e04a98d9c103d6f0a888fcce1e4d958bf
1 /*
2 Copyright © 1995-2006, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Serial Unit hidd class implementation.
6 Lang: english
7 */
9 /* Some POSIX includes */
10 #include <stdio.h>
11 #include <termios.h>
12 #include <unistd.h>
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
43 #undef timeval
45 #undef SDEBUG
46 #undef DEBUG
47 #define SDEBUG 1
48 #define DEBUG 1
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[] =
61 "/dev/ttyS0",
62 "/dev/ttyS1",
63 "/dev/ttyS2",
64 "/dev/ttyS3"
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;
75 ULONG unitnum = 0;
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)))
83 ULONG idx;
85 #define csd CSD(cl)
86 if (IS_HIDDSERIALUNIT_ATTR(tag->ti_Tag, idx))
87 #undef csd
89 switch (idx)
91 case aoHidd_SerialUnit_Unit:
92 unitnum = (ULONG)tag->ti_Data;
93 break;
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);
103 if (obj)
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);
139 } else {
140 // data->baudrate =
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)
182 ULONG error;
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,
190 SysBase);
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,
197 SysBase);
198 goto exit;
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);
226 obj = NULL;
227 } /* if (obj) */
229 D(bug("%s - an error occurred!\n",__FUNCTION__));
231 exit:
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,
249 SysBase);
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);
287 ULONG len = 0;
289 EnterFunc(bug("SerialUnit::Write()\n"));
291 * If the output is currently suspended then I don't do anything...
294 if (TRUE == data->stopped)
295 return 0;
297 D(bug("Writing %d bytes to fd %d (stream: %s)\n",
298 msg->Length,
299 data->filedescriptor,
300 msg->Outbuffer));
302 len = write(data->filedescriptor,
303 msg->Outbuffer,
304 msg->Length);
307 ReturnInt("SerialUnit::Write()",ULONG, len);
310 /***************************************************************************/
312 static ULONG valid_baudrates[] =
317 110,
318 134,
319 150,
320 200,
321 300,
322 600,
323 1200,
324 1800,
325 2400,
326 4800,
327 9600,
328 19200,
329 38400,
330 57600,
331 115200,
335 /*** unused due to cfsetspeed ***
337 static LONG unix_baudrates[] =
340 B50,
341 B75,
342 B110
343 B134,
344 B150,
345 B200,
346 B300,
347 B600,
348 B1200,
349 B1800,
350 B2400,
351 B4800,
352 B9600,
353 B19200,
354 B38400,
355 B57600,
356 B115200
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);
365 BOOL valid = FALSE;
367 if (msg->baudrate != data->baudrate)
369 int i = 0;
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));
383 else
385 data->baudrate = msg->baudrate;
386 D(bug("Adjusted to new baudrate %d!\n",msg->baudrate));
387 valid = TRUE;
390 i++;
391 } /* while */
392 } /* if */
393 return valid;
396 static UBYTE valid_datalengths[] =
405 static UBYTE unix_datalengths[] =
407 CS5,
408 CS6,
409 CS7,
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);
417 BOOL valid = TRUE;
418 int i = 0;
419 struct TagItem * tags = msg->tags;
421 while (TAG_END != tags[i].ti_Tag && TRUE == valid)
423 switch (tags[i].ti_Tag)
425 case TAG_DATALENGTH:
426 if ((UBYTE)tags[i].ti_Data != data->datalength)
428 int j = 0;
429 BOOL found = FALSE;
430 while (0 != valid_datalengths[j])
432 if ((UBYTE)tags[i].ti_Data == valid_datalengths[j])
434 found = TRUE;
435 data->datalength = unix_datalengths[j];
436 break;
439 j++;
441 valid = found;
444 break;
446 case TAG_STOP_BITS:
447 if (2 == tags[i].ti_Data) {
448 data->stopbits = 2;
449 } else
450 data->stopbits = 1;
451 break;
453 case TAG_PARITY:
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)
459 data->parity = TRUE;
460 data->paritytype = tags[i].ti_Data;
462 else
463 valid = FALSE;
464 break;
466 case TAG_PARITY_OFF:
467 data->parity = FALSE;
468 break;
470 case TAG_SKIP:
471 case TAG_IGNORE:
472 break;
474 default:
475 valid = FALSE;
477 i++;
480 settermios(data);
482 return valid;
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))
491 return 0;
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
503 * from upper layer.
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)
531 if (NULL != tags)
533 int i = 0;
534 BOOL end = FALSE;
535 while (FALSE == end)
537 switch (tags[i].ti_Tag)
539 case HIDDA_SerialUnit_BPSRate:
540 tags[i].ti_Data = (STACKIPTR)valid_baudrates;
541 break;
543 case HIDDA_SerialUnit_DataLength:
544 tags[i].ti_Data = (STACKIPTR)valid_datalengths;
545 break;
547 case TAG_DONE:
548 end = TRUE;
549 break;
551 i++;
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);
561 return 0;
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))
574 AROS_USERFUNC_INIT
576 struct HIDDSerialUnitData * data = iD;
577 ssize_t len;
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);
598 AROS_USERFUNC_EXIT
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))
606 AROS_USERFUNC_INIT
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)
622 return;
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);
628 AROS_USERFUNC_EXIT
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;
661 * Parity
663 if (FALSE == data->parity)
664 _termios.c_cflag &= ~(PARENB|PARODD);
665 else
667 _termios.c_cflag |= PARENB;
668 switch (data->paritytype)
670 case PARITY_EVEN:
671 _termios.c_cflag &= ~PARODD;
672 break;
674 case PARITY_ODD:
675 _termios.c_cflag |= PARODD;
676 break;
681 * Stop Bits
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"));
691 else
693 // D(bug("Adjusted to new termios!\n"));
696 } /* settermios */
698 /**************************************************************/
701 * Adapt the termios structure to the preferences
703 static void adapt_termios(struct termios * termios,
704 struct Preferences * prefs)
706 cfmakeraw(termios);
708 * Parity.
710 termios->c_cflag &= ~(PARENB|PARODD);
711 switch ((prefs->SerParShk >> 4) & 0x0f) {
712 case SPARITY_NONE:
713 termios->c_cflag &= ~(PARENB|PARODD);
714 break;
716 case SPARITY_EVEN:
717 termios->c_cflag |= PARENB;
718 break;
720 case SPARITY_ODD:
721 termios->c_cflag |= (PARODD|PARENB);
722 break;
724 case SPARITY_MARK:
725 case SPARITY_SPACE:
726 default:
727 break;
731 * Bit per character
733 termios->c_cflag &= ~CSIZE;
734 switch ((prefs->SerRWBits & 0x0f)) {
735 default: /* 8 bit */
736 case 0:
737 termios->c_cflag |= CS8;
738 break;
740 case 1: /* 7 bit */
741 termios->c_cflag |= CS7;
742 break;
744 case 2: /* 6 bit */
745 termios->c_cflag |= CS6;
746 break;
748 case 3: /* 5 bit */
749 termios->c_cflag |= CS5;
750 break;
754 * 2 stop bits ? default is '1'.
756 if (1 == (prefs->SerStopBuf >> 4))
757 termios->c_cflag |= CSTOPB;
758 else
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)) {
767 case SHSHAKE_XON:
768 termios->c_iflag |= (IXON|IXOFF);
769 break;
771 case SHSHAKE_RTS:
772 termios->c_cflag |= CRTSCTS;
773 break;
775 default:
776 break;
779 cfsetspeed(termios, prefs->BaudRate);
781 } /* adapt_termios */