Subversion Repositories HelenOS

Rev

Rev 4667 | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 4667 Rev 4677
Line 1... Line 1...
1
#include <unistd.h>
1
#include <unistd.h>
2
#include <ddi.h>
2
#include <ddi.h>
3
#include <libarch/ddi.h>
3
#include <libarch/ddi.h>
-
 
4
#include <ipc/ipc.h>
-
 
5
#include <ipc/services.h>
-
 
6
#include <ipc/serial.h>
-
 
7
#include <ipc/devmap.h>
-
 
8
#include <ipc/ns.h>
-
 
9
#include <bool.h>
-
 
10
#include <errno.h>
-
 
11
#include <async.h>
4
#include <stdio.h>
12
#include <stdio.h>
-
 
13
#include <futex.h>
-
 
14
#include <assert.h>
-
 
15
#include <adt/list.h>
-
 
16
#include <string.h>
5
 
17
 
6
#include "isa.h"
18
#include "isa.h"
7
#include "serial.h"
19
#include "serial.h"
8
 
20
 
9
#define NAME "serial"
21
#define NAME "serial"
10
 
22
 
11
#define REG_COUNT 7
23
#define REG_COUNT 7
12
#define COM1 0x3F8
-
 
13
#define COM2 0x2F8
-
 
14
 
24
 
-
 
25
#define MAX_NAME_LEN 8
-
 
26
 
-
 
27
struct serial_dev {
-
 
28
    link_t link;
-
 
29
    char name[MAX_NAME_LEN];
-
 
30
    int handle;
-
 
31
    bool client_connected;
-
 
32
    ioport8_t *port;
-
 
33
    void *phys_addr;
-
 
34
    bridge_to_isa_t *parent;
-
 
35
};
-
 
36
 
-
 
37
typedef struct serial_dev serial_dev_t;
-
 
38
 
-
 
39
static void * serial_phys_addresses[] = { (void *)0x3F8, (void *)0x2F8 };
-
 
40
static int serial_phys_addr_cnt = sizeof(serial_phys_addresses)/sizeof(void *);
-
 
41
// number, which should be assigned to a newly found serial device - increment first, then assign to the device
-
 
42
static int serial_idx = 0;
-
 
43
 
15
static ioport8_t *com1 = 0, *com2 = 0;
44
static int serial_driver_phone = -1;
-
 
45
 
-
 
46
LIST_INITIALIZE(serial_devices_list);
-
 
47
 
-
 
48
static atomic_t serial_futex = FUTEX_INITIALIZER;
-
 
49
 
16
 
50
 
17
static void serial_init_port(ioport8_t *port);
51
static void serial_init_port(ioport8_t *port);
18
static void serial_write_8(ioport8_t *port, uint8_t c);
52
static void serial_write_8(ioport8_t *port, uint8_t c);
19
static bool is_transmit_empty(ioport8_t *port);
53
static bool is_transmit_empty(ioport8_t *port);
20
static uint8_t serial_read_8(ioport8_t *port);
54
static uint8_t serial_read_8(ioport8_t *port);
21
static bool serial_received(ioport8_t *port);
55
static bool serial_received(ioport8_t *port);
22
static void serial_probe(bridge_to_isa_t *parent);
56
static void serial_probe(bridge_to_isa_t *parent);
23
static void * serial_probe_port(void *phys_addr);
57
static ioport8_t * serial_probe_port(void *phys_addr);
-
 
58
static int serial_device_register(int driver_phone, char *name, int *handle);
-
 
59
static int serial_driver_register(char *name);
-
 
60
static void serial_putchar(serial_dev_t *dev, ipc_callid_t rid, ipc_call_t *request);
-
 
61
static void serial_getchar(serial_dev_t *dev, ipc_callid_t rid);
-
 
62
static void serial_client_conn(ipc_callid_t iid, ipc_call_t *icall);
24
 
63
 
25
static isa_drv_ops_t serial_isa_ops = {
64
static isa_drv_ops_t serial_isa_ops = {
26
    .probe = serial_probe  
65
    .probe = serial_probe  
27
};
66
};
28
 
67
 
Line 31... Line 70...
31
    .ops = &serial_isa_ops 
70
    .ops = &serial_isa_ops 
32
};
71
};
33
 
72
 
34
int serial_init()
73
int serial_init()
35
{
74
{
36
    // TODO: register this driver by generic isa bus driver
75
    // register driver by devmapper
-
 
76
    serial_driver_phone = serial_driver_register(NAME);
-
 
77
    if (serial_driver_phone < 0) {
-
 
78
        printf(NAME ": Unable to register driver\n");
-
 
79
        return false;
37
   
80
    }
-
 
81
       
-
 
82
    // register this driver by generic isa bus driver   
38
    isa_register_driver(&serial_isa_drv);
83
    isa_register_driver(&serial_isa_drv);
39
    return 1;
84
    return 1;
40
}
85
}
41
 
86
 
42
static bool serial_received(ioport8_t *port)
87
static bool serial_received(ioport8_t *port)
Line 75... Line 120...
75
    pio_write_8(port + 3, 0x07);    // 8 bits, no parity, two stop bits
120
    pio_write_8(port + 3, 0x07);    // 8 bits, no parity, two stop bits
76
    pio_write_8(port + 2, 0xC7);    // Enable FIFO, clear them, with 14-byte threshold
121
    pio_write_8(port + 2, 0xC7);    // Enable FIFO, clear them, with 14-byte threshold
77
    pio_write_8(port + 4, 0x0B);    // IRQs enabled, RTS/DSR set
122
    pio_write_8(port + 4, 0x0B);    // IRQs enabled, RTS/DSR set
78
}
123
}
79
 
124
 
-
 
125
static serial_dev_t * serial_alloc_dev()
-
 
126
{
-
 
127
    serial_dev_t *dev = (serial_dev_t *)malloc(sizeof(serial_dev_t));
-
 
128
    memset(dev, 0, sizeof(serial_dev_t));
-
 
129
    return dev;
-
 
130
}
-
 
131
 
-
 
132
static void serial_init_dev(serial_dev_t *dev, bridge_to_isa_t *parent, int idx)
-
 
133
{
-
 
134
    assert(dev != NULL);
-
 
135
   
-
 
136
    memset(dev, 0, sizeof(serial_dev_t));
-
 
137
    dev->parent = parent;
-
 
138
    dev->phys_addr = dev->parent->ops->absolutize(serial_phys_addresses[idx % serial_phys_addr_cnt]);
-
 
139
    snprintf(dev->name, MAX_NAME_LEN, "com%d", idx + 1);
-
 
140
    dev->client_connected = false; 
-
 
141
}
-
 
142
 
-
 
143
static bool serial_probe_dev(serial_dev_t *dev)
-
 
144
{
-
 
145
    assert(dev != NULL);
-
 
146
   
-
 
147
    printf(NAME " driver: probing %s \n", dev->name);
-
 
148
    return (dev->port = (ioport8_t *)serial_probe_port(dev->phys_addr)) != NULL;   
-
 
149
}
-
 
150
 
-
 
151
static void serial_delete_dev(serial_dev_t *dev) {
-
 
152
    free(dev);
-
 
153
}
-
 
154
 
80
static void serial_probe(bridge_to_isa_t *parent)
155
static void serial_probe(bridge_to_isa_t *parent)
81
{
156
{
82
    printf(NAME " driver: probe()\n"); 
157
    printf(NAME " driver: probe()\n"); 
83
 
-
 
84
    printf(NAME " driver: probing com1 \n");
-
 
85
    if (com1 = (ioport8_t *)serial_probe_port(parent->ops->absolutize(COM1))) {
-
 
86
        printf(NAME " driver: initializing com1 \n");
-
 
87
        serial_init_port(com1);
-
 
88
    }   else {
-
 
89
        printf(NAME " driver: com1 is not present \n");
-
 
90
    }
-
 
91
   
158
   
92
    printf(NAME " driver: probing com2 \n");
159
    serial_dev_t *dev = serial_alloc_dev();
-
 
160
   
-
 
161
    int i;
93
    if (com2 = (ioport8_t *)serial_probe_port(parent->ops->absolutize(COM2))) {
162
    for (i = 0; i < serial_phys_addr_cnt; i++) {       
-
 
163
        serial_init_dev(dev, parent, serial_idx);
-
 
164
        if (serial_probe_dev(dev)) {
94
        printf(NAME " driver: initializing com2 \n");
165
            printf(NAME " driver: initializing %s.\n", dev->name);
95
        serial_init_port(com2);
166
            serial_init_port(dev->port);
-
 
167
            if (EOK != serial_device_register(serial_driver_phone, dev->name, &(dev->handle))) {
-
 
168
                printf(NAME ": Unable to register device %s\n", dev->name);
-
 
169
            }  
-
 
170
            list_append(&(dev->link), &serial_devices_list);
-
 
171
            dev = serial_alloc_dev();
-
 
172
        } else {
-
 
173
            printf(NAME " driver: %s is not present \n", dev->name);
-
 
174
        }
-
 
175
        serial_idx++;
96
    }
176
    }
97
    else {
177
   
98
        printf(NAME " driver: com2 is not present \n");
178
    serial_delete_dev(dev);
99
    }  
-
 
100
}
179
}
101
 
180
 
102
// returns virtual address of the serial port, if the serial port is present at this physical address, NULL otherwise  
181
// returns virtual address of the serial port, if the serial port is present at this physical address, NULL otherwise  
103
static void * serial_probe_port(void *phys_addr)
182
static ioport8_t * serial_probe_port(void *phys_addr)
104
{
183
{
105
    ioport8_t *port_addr = NULL;
184
    ioport8_t *port_addr = NULL;
106
   
185
   
107
    if (pio_enable(phys_addr, REG_COUNT, (void **)(&port_addr))) {  // Gain control over port's registers.
186
    if (pio_enable(phys_addr, REG_COUNT, (void **)(&port_addr))) {  // Gain control over port's registers.
108
        printf(NAME ": Error - cannot gain the port %lx.\n", phys_addr);
187
        printf(NAME ": Error - cannot gain the port %lx.\n", phys_addr);
Line 123... Line 202...
123
    }
202
    }
124
    pio_write_8(port_addr + 4, olddata);
203
    pio_write_8(port_addr + 4, olddata);
125
   
204
   
126
    return port_addr;
205
    return port_addr;
127
}
206
}
-
 
207
 
-
 
208
 
-
 
209
static void serial_putchar(serial_dev_t *dev, ipc_callid_t rid, ipc_call_t *request)
-
 
210
{
-
 
211
    int c = IPC_GET_ARG1(*request);
-
 
212
    serial_write_8(dev->port, (uint8_t)c); 
-
 
213
    ipc_answer_0(rid, EOK);
-
 
214
}
-
 
215
 
-
 
216
static void serial_getchar(serial_dev_t *dev, ipc_callid_t rid)
-
 
217
{
-
 
218
    uint8_t c = serial_read_8(dev->port);  
-
 
219
    ipc_answer_1(rid, EOK, c);     
-
 
220
}
-
 
221
 
-
 
222
static serial_dev_t * serial_handle_to_dev(int handle) {
-
 
223
   
-
 
224
    futex_down(&serial_futex); 
-
 
225
   
-
 
226
    link_t *item = serial_devices_list.next;
-
 
227
    serial_dev_t *dev = NULL;
-
 
228
   
-
 
229
    while (item != &serial_devices_list) {
-
 
230
        dev = list_get_instance(item, serial_dev_t, link);
-
 
231
        if (dev->handle == handle) {
-
 
232
            futex_up(&serial_futex);
-
 
233
            return dev;
-
 
234
        }
-
 
235
        item = item->next;
-
 
236
    }
-
 
237
   
-
 
238
    futex_up(&serial_futex);
-
 
239
    return NULL;
-
 
240
}
-
 
241
 
-
 
242
 
-
 
243
/** Handle one connection to the driver.
-
 
244
 *
-
 
245
 * @param iid       Hash of the request that opened the connection.
-
 
246
 * @param icall     Call data of the request that opened the connection.
-
 
247
 */
-
 
248
static void serial_client_conn(ipc_callid_t iid, ipc_call_t *icall)
-
 
249
{  
-
 
250
    /*
-
 
251
     * Answer the first IPC_M_CONNECT_ME_TO call and remember the handle of the device to which the client connected.
-
 
252
     */
-
 
253
    int handle = IPC_GET_ARG1(*icall);
-
 
254
    serial_dev_t *dev = serial_handle_to_dev(handle);
-
 
255
   
-
 
256
    if (dev == NULL) {
-
 
257
        ipc_answer_0(iid, ENOENT);
-
 
258
        return;
-
 
259
    }
-
 
260
    if (dev->client_connected) {
-
 
261
        ipc_answer_0(iid, ELIMIT);
-
 
262
        return;
-
 
263
    }
-
 
264
   
-
 
265
    dev->client_connected = true;
-
 
266
    ipc_answer_0(iid, EOK);
-
 
267
   
-
 
268
    while (1) {
-
 
269
        ipc_callid_t callid;
-
 
270
        ipc_call_t call;
-
 
271
   
-
 
272
        callid = async_get_call(&call);
-
 
273
        switch  (IPC_GET_METHOD(call)) {
-
 
274
        case IPC_M_PHONE_HUNGUP:
-
 
275
            /*
-
 
276
             * The other side has hung up.
-
 
277
             * Answer the message and exit the fibril.
-
 
278
             */
-
 
279
            ipc_answer_0(callid, EOK);
-
 
280
            dev->client_connected = false;
-
 
281
            return;
-
 
282
            break;
-
 
283
        case SERIAL_GETCHAR:
-
 
284
            serial_getchar(dev, callid);
-
 
285
            break;
-
 
286
        case SERIAL_PUTCHAR:
-
 
287
            serial_putchar(dev, callid, &call);
-
 
288
            break;
-
 
289
        default:
-
 
290
            ipc_answer_0(callid, ENOTSUP);
-
 
291
            break;
-
 
292
        }
-
 
293
    }  
-
 
294
}
-
 
295
 
-
 
296
 
-
 
297
/**
-
 
298
 *  Register the driver with the given name and return its newly created phone.
-
 
299
 */
-
 
300
static int serial_driver_register(char *name)
-
 
301
{
-
 
302
    ipcarg_t retval;
-
 
303
    aid_t req;
-
 
304
    ipc_call_t answer;
-
 
305
    int phone;
-
 
306
    ipcarg_t callback_phonehash;
-
 
307
 
-
 
308
    phone = ipc_connect_me_to(PHONE_NS, SERVICE_DEVMAP, DEVMAP_DRIVER, 0);
-
 
309
 
-
 
310
    while (phone < 0) {
-
 
311
        usleep(10000);
-
 
312
        phone = ipc_connect_me_to(PHONE_NS, SERVICE_DEVMAP,
-
 
313
            DEVMAP_DRIVER, 0);
-
 
314
    }
-
 
315
   
-
 
316
    req = async_send_2(phone, DEVMAP_DRIVER_REGISTER, 0, 0, &answer);
-
 
317
 
-
 
318
    retval = ipc_data_write_start(phone, (char *) name, str_length(name) + 1);
-
 
319
 
-
 
320
    if (retval != EOK) {
-
 
321
        async_wait_for(req, NULL);
-
 
322
        return -1;
-
 
323
    }
-
 
324
 
-
 
325
    async_set_client_connection(serial_client_conn);  // set callback function which will serve client connections
-
 
326
 
-
 
327
    ipc_connect_to_me(phone, 0, 0, 0, &callback_phonehash);
-
 
328
    async_wait_for(req, &retval);
-
 
329
 
-
 
330
    return phone;
-
 
331
}
-
 
332
 
-
 
333
static int serial_device_register(int driver_phone, char *name, int *handle)
-
 
334
{
-
 
335
    ipcarg_t retval;
-
 
336
    aid_t req;
-
 
337
    ipc_call_t answer;
-
 
338
 
-
 
339
    req = async_send_2(driver_phone, DEVMAP_DEVICE_REGISTER, 0, 0, &answer);
-
 
340
 
-
 
341
    retval = ipc_data_write_start(driver_phone, (char *) name, str_length(name) + 1);
-
 
342
 
-
 
343
    if (retval != EOK) {
-
 
344
        async_wait_for(req, NULL);
-
 
345
        return retval;
-
 
346
    }
-
 
347
 
-
 
348
    async_wait_for(req, &retval);
-
 
349
 
-
 
350
    if (handle != NULL)
-
 
351
        *handle = -1;
-
 
352
   
-
 
353
    if (EOK == retval) {
-
 
354
        if (NULL != handle)
-
 
355
            *handle = (int) IPC_GET_ARG1(answer);
-
 
356
    }
-
 
357
   
-
 
358
    return retval;
-
 
359
}