···11+/*****************************************************************************
22+ * pce *
33+ *****************************************************************************/
44+55+/*****************************************************************************
66+ * File name: src/drivers/char/char-tios.c *
77+ * Created: 2009-03-06 by Hampa Hug <hampa@hampa.ch> *
88+ * Copyright: (C) 2009 Hampa Hug <hampa@hampa.ch> *
99+ *****************************************************************************/
1010+1111+/*****************************************************************************
1212+ * This program is free software. You can redistribute it and / or modify it *
1313+ * under the terms of the GNU General Public License version 2 as published *
1414+ * by the Free Software Foundation. *
1515+ * *
1616+ * This program is distributed in the hope that it will be useful, but *
1717+ * WITHOUT ANY WARRANTY, without even the implied warranty of *
1818+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General *
1919+ * Public License for more details. *
2020+ *****************************************************************************/
2121+2222+2323+#include <stdlib.h>
2424+#include <limits.h>
2525+2626+#include <fcntl.h>
2727+#include <sys/ioctl.h>
2828+#include <sys/poll.h>
2929+#include <sys/stat.h>
3030+#include <sys/types.h>
3131+#include <termios.h>
3232+#include <unistd.h>
3333+3434+#include <drivers/char/char.h>
3535+#include <drivers/char/char-tios.h>
3636+3737+3838+/*
3939+ * Check if file descriptor fd is readable and/or writeable
4040+ */
4141+static
4242+int chr_tios_check_fd (int fd, int rd, int wr)
4343+{
4444+ int r;
4545+ struct pollfd pfd[1];
4646+4747+ if (fd < 0) {
4848+ return (0);
4949+ }
5050+5151+ pfd[0].fd = fd;
5252+ pfd[0].events = (rd ? POLLIN : 0) | (wr ? POLLOUT : 0);
5353+5454+ r = poll (pfd, 1, 0);
5555+5656+ if (r < 0) {
5757+ return (0);
5858+ }
5959+6060+ if ((pfd[0].revents & (POLLIN | POLLOUT)) == 0) {
6161+ return (0);
6262+ }
6363+6464+ return (1);
6565+}
6666+6767+static
6868+void chr_tios_close (char_drv_t *cdrv)
6969+{
7070+ char_tios_t *drv;
7171+7272+ drv = cdrv->ext;
7373+7474+ if (drv->fname != NULL) {
7575+ free (drv->fname);
7676+ }
7777+7878+ if (drv->fd >= 0) {
7979+ close (drv->fd);
8080+ }
8181+8282+ free (drv);
8383+}
8484+8585+static
8686+unsigned chr_tios_read (char_drv_t *cdrv, void *buf, unsigned cnt)
8787+{
8888+ char_tios_t *drv;
8989+ ssize_t r;
9090+9191+ drv = cdrv->ext;
9292+9393+ if (chr_tios_check_fd (drv->fd, 1, 0) == 0) {
9494+ return (0);
9595+ }
9696+9797+ if (cnt > SSIZE_MAX) {
9898+ cnt = SSIZE_MAX;
9999+ }
100100+101101+ r = read (drv->fd, buf, cnt);
102102+103103+ if (r <= 0) {
104104+ return (0);
105105+ }
106106+107107+ return (r);
108108+}
109109+110110+static
111111+unsigned chr_tios_write (char_drv_t *cdrv, const void *buf, unsigned cnt)
112112+{
113113+ char_tios_t *drv;
114114+ ssize_t r;
115115+116116+ drv = cdrv->ext;
117117+118118+ if (drv->fd < 0) {
119119+ return (cnt);
120120+ }
121121+122122+ if (chr_tios_check_fd (drv->fd, 0, 1) == 0) {
123123+ return (0);
124124+ }
125125+126126+ if (cnt > SSIZE_MAX) {
127127+ cnt = SSIZE_MAX;
128128+ }
129129+130130+ r = write (drv->fd, buf, cnt);
131131+132132+ if (r <= 0) {
133133+ return (0);
134134+ }
135135+136136+ return (r);
137137+}
138138+139139+static
140140+int chr_tios_get_ctl (char_drv_t *cdrv, unsigned *ctl)
141141+{
142142+ char_tios_t *drv;
143143+ int val;
144144+145145+ drv = cdrv->ext;
146146+147147+ *ctl = 0;
148148+149149+ if (drv->fd >= 0) {
150150+ ioctl (drv->fd, TIOCMGET, &val);
151151+ }
152152+ else {
153153+ val = TIOCM_DSR | TIOCM_CTS | TIOCM_CD;
154154+ }
155155+156156+ *ctl |= (val & TIOCM_DSR) ? PCE_CHAR_DSR : 0;
157157+ *ctl |= (val & TIOCM_CTS) ? PCE_CHAR_CTS : 0;
158158+ *ctl |= (val & TIOCM_CD) ? PCE_CHAR_CD : 0;
159159+ *ctl |= (val & TIOCM_RI) ? PCE_CHAR_RI : 0;
160160+161161+ *ctl |= PCE_CHAR_DSR;
162162+ *ctl |= PCE_CHAR_CTS;
163163+164164+ return (0);
165165+}
166166+167167+static
168168+int chr_tios_set_ctl (char_drv_t *cdrv, unsigned ctl)
169169+{
170170+ char_tios_t *drv;
171171+ int val;
172172+173173+ drv = cdrv->ext;
174174+175175+ if (drv->fd < 0) {
176176+ return (0);
177177+ }
178178+179179+ ioctl (drv->fd, TIOCMGET, &val);
180180+ val &= ~(TIOCM_DTR | TIOCM_RTS);
181181+ val |= (ctl & PCE_CHAR_DTR) ? TIOCM_DTR : 0;
182182+ val |= (ctl & PCE_CHAR_RTS) ? TIOCM_RTS : 0;
183183+ ioctl (drv->fd, TIOCMSET, &val);
184184+185185+ return (0);
186186+}
187187+188188+static
189189+int chr_tios_set_params (char_drv_t *cdrv, unsigned long bps, unsigned bpc, unsigned parity, unsigned stop)
190190+{
191191+ char_tios_t *drv;
192192+ struct termios tio;
193193+ speed_t spd;
194194+195195+ drv = cdrv->ext;
196196+197197+ if (drv->fd < 0) {
198198+ return (0);
199199+ }
200200+201201+ if (tcgetattr (drv->fd, &tio)) {
202202+ return (1);
203203+ }
204204+205205+ tio.c_iflag &= ~INPCK; /* Input parity check */
206206+ tio.c_iflag &= ~ISTRIP; /* Strip to 7 bits */
207207+ tio.c_iflag &= ~IGNBRK; /* Ignore break conditions */
208208+ tio.c_iflag &= ~BRKINT; /* SIGINT on break condition */
209209+ tio.c_iflag &= ~IGNCR; /* Discard CR on intput */
210210+ tio.c_iflag &= ~ICRNL; /* Convert CR to LF on input */
211211+ tio.c_iflag &= ~INLCR; /* Convert LF to CR on input */
212212+ tio.c_iflag &= ~IXOFF; /* Enable input flow control */
213213+ tio.c_iflag &= ~IXON; /* Enable output flow control */
214214+ tio.c_iflag &= ~IXANY; /* Any character as START */
215215+ tio.c_iflag &= ~IMAXBEL; /* Send BEL on buffer overflow */
216216+217217+ tio.c_oflag &= ~OPOST; /* Enable output post processing */
218218+219219+ tio.c_cflag |= CLOCAL; /* Don't use modem control lines */
220220+ tio.c_cflag &= ~HUPCL; /* Hang up modem on device close */
221221+ tio.c_cflag |= CREAD; /* Input can be read */
222222+ tio.c_cflag &= ~CRTSCTS;
223223+224224+ tio.c_lflag &= ~ICANON; /* Canonical mode */
225225+ tio.c_lflag &= ~ECHO; /* Enable echo */
226226+ tio.c_lflag &= ~ECHOE; /* Enable echo */
227227+#ifdef ECHOPRT
228228+ tio.c_lflag &= ~ECHOPRT; /* Enable echo */
229229+#endif
230230+ tio.c_lflag &= ~ECHOK; /* Enable echo */
231231+ tio.c_lflag &= ~ECHONL; /* Enable echo */
232232+#ifdef ECHOCTL
233233+ tio.c_lflag &= ~ECHOCTL; /* Enable echo */
234234+#endif
235235+ tio.c_lflag &= ~ISIG; /* Enable signals on special characters */
236236+ tio.c_lflag |= NOFLSH; /* Don't flush queues on special characters */
237237+238238+ tio.c_cflag &= ~CSIZE;
239239+240240+ switch (bpc) {
241241+ case 8:
242242+ tio.c_cflag |= CS8;
243243+ break;
244244+245245+ case 7:
246246+ tio.c_cflag |= CS7;
247247+ break;
248248+249249+ case 6:
250250+ tio.c_cflag |= CS6;
251251+ break;
252252+253253+ case 5:
254254+ tio.c_cflag |= CS5;
255255+ break;
256256+257257+ default:
258258+ tio.c_cflag |= CS8;
259259+ break;
260260+ }
261261+262262+ if (stop == 1) {
263263+ tio.c_cflag &= ~CSTOPB;
264264+ }
265265+ else {
266266+ tio.c_cflag |= CSTOPB;
267267+ }
268268+269269+ switch (parity) {
270270+ case 0:
271271+ tio.c_cflag &= ~PARENB;
272272+ break;
273273+274274+ case 1: /* odd */
275275+ tio.c_cflag |= PARENB;
276276+ tio.c_cflag |= PARODD;
277277+ break;
278278+279279+ case 2: /* even */
280280+ tio.c_cflag |= PARENB;
281281+ tio.c_cflag &= ~PARODD;
282282+ break;
283283+284284+ case 3: /* mark */
285285+ case 4: /* space */
286286+ /* termios does not support these */
287287+ tio.c_cflag |= PARENB;
288288+ tio.c_cflag &= ~PARODD;
289289+ break;
290290+291291+ default:
292292+ tio.c_cflag &= !PARENB;
293293+ break;
294294+ }
295295+296296+ if (bps < ((50 + 75) / 2)) {
297297+ spd = B50;
298298+ }
299299+ else if (bps < ((75 + 110) / 2)) {
300300+ spd = B75;
301301+ }
302302+ else if (bps < ((110 + 134) / 2)) {
303303+ spd = B110;
304304+ }
305305+ else if (bps < ((134 + 150) / 2)) {
306306+ spd = B134;
307307+ }
308308+ else if (bps < ((150 + 200) / 2)) {
309309+ spd = B150;
310310+ }
311311+ else if (bps < ((200 + 300) / 2)) {
312312+ spd = B200;
313313+ }
314314+ else if (bps < ((300 + 600) / 2)) {
315315+ spd = B300;
316316+ }
317317+ else if (bps < ((600 + 1200) / 2)) {
318318+ spd = B600;
319319+ }
320320+ else if (bps < ((1200 + 2400) / 2)) {
321321+ spd = B1200;
322322+ }
323323+ else if (bps < ((2400 + 4800) / 2)) {
324324+ spd = B2400;
325325+ }
326326+ else if (bps < ((4800 + 9600) / 2)) {
327327+ spd = B4800;
328328+ }
329329+ else if (bps < ((9600 + 19200) / 2)) {
330330+ spd = B9600;
331331+ }
332332+ else if (bps < ((19200 + 38400) / 2)) {
333333+ spd = B19200;
334334+ }
335335+#ifdef B38400
336336+ else if (bps < ((38400 + 57600) / 2)) {
337337+ spd = B38400;
338338+ }
339339+#endif
340340+#ifdef B57600
341341+ else if (bps < ((57600 + 115200) / 2)) {
342342+ spd = B57600;
343343+ }
344344+#endif
345345+#ifdef B115200
346346+ else if (bps < ((115200 + 230400) / 2)) {
347347+ spd = B115200;
348348+ }
349349+#endif
350350+ else {
351351+ spd = B9600;
352352+ }
353353+354354+ cfsetispeed (&tio, spd);
355355+ cfsetospeed (&tio, spd);
356356+357357+ tio.c_cc[VMIN] = 1;
358358+ tio.c_cc[VTIME] = 0;
359359+360360+ if (tcsetattr (drv->fd, TCSANOW, &tio)) {
361361+ return (1);
362362+ }
363363+364364+ tcflush (drv->fd, TCIOFLUSH);
365365+366366+ return (0);
367367+}
368368+369369+static
370370+int chr_tios_init (char_tios_t *drv, const char *name)
371371+{
372372+ chr_init (&drv->cdrv, drv);
373373+374374+ drv->cdrv.close = chr_tios_close;
375375+ drv->cdrv.read = chr_tios_read;
376376+ drv->cdrv.write = chr_tios_write;
377377+ drv->cdrv.get_ctl = chr_tios_get_ctl;
378378+ drv->cdrv.set_ctl = chr_tios_set_ctl;
379379+ drv->cdrv.set_params = chr_tios_set_params;
380380+381381+ drv->fd = -1;
382382+383383+ drv->fname = chr_get_option (name, "file", 1);
384384+385385+ if (drv->fname != NULL) {
386386+ drv->fd = open (drv->fname, O_RDWR | O_NOCTTY);
387387+388388+ if (drv->fd < 0) {
389389+ return (1);
390390+ }
391391+392392+ chr_tios_set_params (&drv->cdrv, 9600, 8, 0, 1);
393393+ }
394394+395395+ return (0);
396396+}
397397+398398+char_drv_t *chr_tios_open (const char *name)
399399+{
400400+ char_tios_t *drv;
401401+402402+ drv = malloc (sizeof (char_tios_t));
403403+404404+ if (drv == NULL) {
405405+ return (NULL);
406406+ }
407407+408408+ if (chr_tios_init (drv, name)) {
409409+ chr_tios_close (&drv->cdrv);
410410+411411+ return (NULL);
412412+ }
413413+414414+ return (&drv->cdrv);
415415+}
+41
src/drivers/char/char-tios.h
···11+/*****************************************************************************
22+ * pce *
33+ *****************************************************************************/
44+55+/*****************************************************************************
66+ * File name: src/drivers/char/char-tios.h *
77+ * Created: 2009-03-06 by Hampa Hug <hampa@hampa.ch> *
88+ * Copyright: (C) 2009 Hampa Hug <hampa@hampa.ch> *
99+ *****************************************************************************/
1010+1111+/*****************************************************************************
1212+ * This program is free software. You can redistribute it and / or modify it *
1313+ * under the terms of the GNU General Public License version 2 as published *
1414+ * by the Free Software Foundation. *
1515+ * *
1616+ * This program is distributed in the hope that it will be useful, but *
1717+ * WITHOUT ANY WARRANTY, without even the implied warranty of *
1818+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General *
1919+ * Public License for more details. *
2020+ *****************************************************************************/
2121+2222+2323+#ifndef PCE_DRIVERS_CHAR_TIOS_H
2424+#define PCE_DRIVERS_CHAR_TIOS_H 1
2525+2626+2727+#include <stdio.h>
2828+2929+#include <drivers/char/char.h>
3030+3131+3232+typedef struct char_tios_t {
3333+ char_drv_t cdrv;
3434+3535+ char *fname;
3636+3737+ int fd;
3838+} char_tios_t;
3939+4040+4141+#endif