summaryrefslogtreecommitdiff
path: root/src/hal/drivers/serport.comp
blob: cd1e963725b990fc5fc8d1e9f6bb9b9ab86b185e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
component serport """Hardware driver for the digital I/O bits of the 8250 and 16550 serial port.

.B loadrt serport io=\\fIaddr[,addr...]\\fR
.PP
The pin numbers refer to the 9-pin serial pinout.  Keep in mind that these ports generally use rs232 voltages, not 0/5V signals.

Specify the I/O address of the serial ports using the module parameter
\\fBio=\\fIaddr[,addr...]\\fR.  These ports must not be in use by the kernel.
To free up the I/O ports after bootup, install setserial and execute a command
like:
.RS 
sudo setserial /dev/ttyS0 uart none
.RE
but it is best to ensure that the serial port is never used or configured by
the Linux kernel by setting a kernel commandline parameter or not loading
the serial kernel module if it is a modularized driver.
""";

pin out bit pin_1_in "Also called DCD (data carrier detect); pin 8 on the 25-pin serial pinout";
pin out bit pin_6_in "Also called DSR (data set ready); pin 6 on the 25-pin serial pinout";
pin out bit pin_8_in "Also called CTS (clear to send); pin 5 on the 25-pin serial pinout";
pin out bit pin_9_in "Also called RI (ring indicator); pin 22 on the 25-pin serial pinout";

pin out bit pin_1_in_not "Inverted version of pin-1-in";
pin out bit pin_6_in_not "Inverted version of pin-6-in";
pin out bit pin_8_in_not "Inverted version of pin-8-in";
pin out bit pin_9_in_not "Inverted version of pin-9-in";

pin in bit pin_3_out  "Also called TX (transmit data); pin 2 on the 25-pin serial pinout";
pin in bit pin_4_out "Also called DTR (data terminal ready); pin 20 on the 25-pin serial pinout";
pin in bit pin_7_out "Also called RTS (request to send); pin 4 on the 25-pin serial pinout";

param rw bit pin_3_out_invert;
param rw bit pin_4_out_invert;
param rw bit pin_7_out_invert;
param r u32 ioaddr;

option count_function;
option extra_setup;
option extra_cleanup;
option constructable no;

function read nofp;
function write nofp;

license "GPL";
;;

#include <asm/io.h>
#include <rtapi_errno.h>

#define MAX 8
int io[MAX] = {0,};
RTAPI_MP_ARRAY_INT(io, MAX, "I/O addresses of serial ports");

int get_count(void) {
    int i = 0;
    for(i=0; i<MAX && io[i]; i++) { /* Nothing */ }
    return i;
}

EXTRA_SETUP() {
    rtapi_print_msg(RTAPI_MSG_INFO, "requesting I/O region 0x%x\n",
			io[extra_arg]);
    if(!rtapi_request_region(io[extra_arg], 7, "serport")) {
	// set this I/O port to 0 so that EXTRA_CLEANUP does not release the IO
	// ports that were never requested.
	rtapi_print_msg(RTAPI_MSG_ERR,
	    "Could not register port at address 0x%x.  See\n"
	    "'man serport' for information on using 'setserial'\n"
	    "to make a port available to hal", io[extra_arg]);
        io[extra_arg] = 0; 
        return -EBUSY;
    }
    ioaddr = io[extra_arg];
    return 0;
}

EXTRA_CLEANUP() {
    int i;
    for(i=0; i < MAX && io[i]; i++) {
        rtapi_print_msg(RTAPI_MSG_INFO, "releasing I/O region 0x%x\n",
			io[i]);
        rtapi_release_region(io[i], 7);
    }
}

#define MSR (ioaddr + 6)
#define CTS (1<<4)
#define DSR (1<<5)
#define RI (1<<6)
#define DCD (1<<7)

#define MCR (ioaddr + 4)
#define DTR (1<<0)
#define RTS (1<<1)

#define LCR (ioaddr + 3)
#define BREAK (1<<6)

FUNCTION(read) { 
    int i = inb(MSR);

    pin_9_in = (i & RI) == 0;
    pin_9_in_not = (i & RI) == RI;

    pin_1_in = (i & DCD) == 0;
    pin_1_in_not = !(i & DCD) == DCD;

    pin_6_in = (i & DSR) == 0;
    pin_6_in_not = (i & DSR) == DSR;

    pin_8_in = (i & CTS) == 0;
    pin_8_in_not = (i & CTS) == CTS;
}

FUNCTION(write) {
    int i = 0, j=0;

    if(!pin_4_out ^ !pin_4_out_invert) i |= DTR;
    if(!pin_7_out ^ !pin_7_out_invert) i |= RTS;
    if(!pin_3_out ^ !pin_3_out_invert) j |= BREAK;

    outb(i, MCR);
    outb(j, LCR);
}