nckernel
0.1
Main Page
Related Pages
Modules
Data Structures
Files
File List
Globals
All
Data Structures
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Macros
Groups
Pages
arch
x86
driver
serial
src
serial.c
Go to the documentation of this file.
1
#include <
slibc.h
>
2
#include <
sys/types.h
>
3
#include <
sys/io.h
>
4
#include <
stdio.h
>
5
#include <
errno.h
>
6
#include <
stdarg.h
>
7
#include <
stdlib.h
>
8
#include <
stddef.h
>
9
#include <
assert.h
>
10
11
#include <
list.h
>
12
13
#include <
object.h
>
14
#include <
vfs.h
>
15
#include <
device.h
>
16
#include <
serial.h
>
17
#include <
interrupt.h
>
18
#include <
isr.h
>
19
20
#include <
debug.h
>
21
22
static
unsigned
int
COM[] = { 0x3F8, 0x2F8, 0x3E8, 0x2E8 };
23
static
LIST_HEAD
(s_serial);
24
25
struct
context
{
26
int
setup
;
27
int
parity
;
28
int
stop
;
29
int
data
;
30
int
baudrate
;
31
int
validate
;
32
};
33
34
enum
port_offset
{
35
DATA
= 0x00,
36
INTR_ENABLE
= 0x01,
37
BAUD_LO
= 0x00,
38
BAUD_HI
= 0x01,
39
FIFO
= 0x02,
40
LINE_CTRL
= 0x03,
41
MODEM_CTRL
= 0x04,
42
LINE_STATUS
= 0x05,
43
MODEM_STATUS
= 0x06,
44
SCRATCH
= 0x07,
45
};
46
47
#define DATA5 0x00
48
#define DATA6 0x01
49
#define DATA7 0x02
50
#define DATA8 0x03
51
52
#define STOPBITS1 0x00
53
#define STOPBITS2 0x01
54
55
#define NO_PARITY 0x00
56
#define ODD_PARITY 0x01
57
#define EVEN_PARITY 0x02
58
59
#define SERIAL_MAX_SPEED 115200
60
61
enum
IER
{
62
RX
= 0x01,
63
TX
= 0x02,
64
RX_STAT
= 0x04,
/*< Enable Receiver Line Status Interrupt */
65
MODEM_STAT
= 0x08,
66
SLEEP_MODE
= 0x10,
67
LOW_POWER
= 0x20,
68
};
69
70
static
int
serial_isr(
int
sub_irq,
void
*
info
,
void
*data)
71
{
72
//printf("%s\n", __func__);
73
return
0;
74
}
75
76
static
inline
void
apply_setup(
struct
ninfo
*
ninfo
,
struct
nctx
*ctx)
77
{
78
struct
ninfo_dev
*dev;
79
struct
context
*priv;
80
unsigned
char
value;
81
int
divisor;
82
int
id;
83
84
dev = ninfo->
priv
;
85
priv = ctx->
priv
;
86
87
id
=
MINOR
(dev->
device
);
88
90
outb
(COM[
id
] + 1, 0x00);
91
92
divisor =
SERIAL_MAX_SPEED
/ priv->
baudrate
;
93
outb
(COM[
id
] + 3, 0x80);
95
outb
(COM[
id
] + 0, (
unsigned
char
)divisor);
96
outb
(COM[
id
] + 1, (
unsigned
char
)(divisor>>4));
97
98
value = priv->
data
& 0x03;
99
value |= ((priv->
stop
& 0x1) << 2);
100
value |= ((priv->
parity
& 0x07) << 3);
101
outb
(COM[
id
] + 3, value);
102
104
outb
(COM[
id
] + 4,
RX
|
TX
|
MODEM_STAT
);
105
}
106
107
int
serial_open
(
struct
ninfo *ninfo,
struct
nctx
*ctx)
108
{
109
int
id;
110
struct
ninfo_dev
*dev;
111
struct
context
*priv;
112
int
ret;
113
int
irq;
114
115
dev = ninfo->
priv
;
116
117
id
=
MINOR
(dev->
device
);
118
if
(
id
> (
sizeof
(COM) /
sizeof
(COM[0]))) {
119
return
-
ENODEV
;
120
}
121
122
priv =
malloc
(
sizeof
(*priv));
123
if
(!priv) {
124
return
-
ENOMEM
;
125
}
126
127
ctx->
priv
= priv;
128
ctx->
offset
= 0;
129
131
irq = (
id
% 2) ?
IRQ_NR_SERIAL_ODD
:
IRQ_NR_SERIAL_EVEN
;
132
ret =
register_irq
(irq,
NORMAL_PRIORITY
, serial_isr,
NULL
);
133
if
(ret < 0) {
134
free
(priv);
135
return
ret;
136
}
137
138
return
0;
139
}
140
141
int
serial_read
(
struct
ninfo *ninfo,
struct
nctx
*ctx,
void
*buf,
size_t
size)
142
{
143
struct
context
*priv;
144
145
priv = ctx->
priv
;
146
if
(priv->
setup
) {
147
return
-
EBUSY
;
148
}
149
150
/* READ: inb(COM[ctx->id]) */
151
return
0;
152
}
153
154
int
serial_write
(
struct
ninfo *ninfo,
struct
nctx
*ctx,
155
const
void
*buf,
size_t
size)
156
{
157
struct
context
*priv;
158
priv = ctx->
priv
;
159
160
if
(priv->
setup
) {
161
return
-
EBUSY
;
162
}
163
164
/* WRITE: outb(COM[ctx->id], buffer[0]) */
165
return
0;
166
}
167
168
int
serial_ioctl
(
struct
ninfo *ninfo,
struct
nctx
*ctx,
int
request,
va_list
va)
169
{
170
struct
context
*priv;
171
172
priv = ctx->
priv
;
173
174
switch
(request) {
175
case
SERIAL_CMD_ENTER_SETUP
:
176
if
(!priv->
setup
) {
177
priv->
setup
= 1;
178
priv->
validate
= 0;
179
}
180
break
;
181
case
SERIAL_CMD_BAUDRATE
:
182
priv->
baudrate
=
va_arg
(va,
int
);
183
priv->
validate
|= 0x01;
184
break
;
185
case
SERIAL_CMD_PARITY
:
186
priv->
parity
=
va_arg
(va,
int
);
187
priv->
validate
|= 0x02;
188
break
;
189
case
SERIAL_CMD_STOP
:
190
priv->
stop
=
va_arg
(va,
int
);
191
priv->
validate
|= 0x04;
192
break
;
193
case
SERIAL_CMD_DATA
:
194
priv->
data
=
va_arg
(va,
int
);
195
priv->
validate
|= 0x08;
196
break
;
197
case
SERIAL_CMD_LEAVE_SETUP
:
198
if
(priv->
setup
) {
199
if
(priv->
validate
== 0x0F) {
200
apply_setup(ninfo, ctx);
201
}
202
203
priv->
setup
= 0;
204
}
205
break
;
206
default
:
207
return
-
EINVAL
;
208
}
209
210
return
0;
211
}
212
213
int
serial_close
(
struct
ninfo *ninfo,
struct
nctx
*ctx)
214
{
215
struct
ninfo_dev
*dev;
216
int
irq;
217
int
ret;
218
219
dev = ninfo->
priv
;
220
//priv = ctx->priv;
221
222
irq = (
MINOR
(dev->
device
) % 2) ?
IRQ_NR_SERIAL_ODD
:
IRQ_NR_SERIAL_EVEN
;
223
227
ret =
unregister_irq
(irq, serial_isr,
NULL
);
228
229
free
(ctx->
priv
);
230
ctx->
priv
=
NULL
;
231
return
ret;
232
}
233
234
static
struct
ninfo_ops
serial_ops = {
235
.
open
=
serial_open
,
236
.read =
serial_read
,
237
.write =
serial_write
,
238
.ioctl =
serial_ioctl
,
239
.close =
serial_close
,
240
};
241
242
int
serial_init
(
void
)
243
{
244
struct
ninfo *parent;
245
struct
ninfo *ninfo;
246
247
parent =
vfs_get_ninfo
(
NULL
,
NULL
,
"/dev"
);
248
if
(!parent) {
249
return
-
EFAULT
;
250
}
251
252
ninfo =
vfs_new_dev_ninfo
(
NULL
, parent,
253
"com1"
,
DEVICE_COM1
, &serial_ops);
254
if
(!ninfo) {
255
return
-
EFAULT
;
256
}
257
258
ninfo =
vfs_new_dev_ninfo
(
NULL
, parent,
259
"com2"
,
DEVICE_COM2
, &serial_ops);
260
if
(!ninfo) {
261
goto
out;
262
}
263
264
ninfo =
vfs_new_dev_ninfo
(
NULL
, parent,
265
"com3"
,
DEVICE_COM3
, &serial_ops);
266
if
(!ninfo) {
267
goto
out;
268
}
269
270
ninfo =
vfs_new_dev_ninfo
(
NULL
, parent,
271
"com4"
,
DEVICE_COM4
, &serial_ops);
272
if
(!ninfo) {
273
goto
out;
274
}
275
276
out:
277
return
0;
278
}
279
280
/* End of a file */
Generated on Thu Nov 7 2013 02:45:25 for nckernel by
1.8.4