source: mainline/uspace/srv/drivers/serial/serial.c@ a78fa2a

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a78fa2a was 1f8657b, checked in by Lenka Trochtova <trochtova.lenka@…>, 15 years ago

serial port probing

  • Property mode set to 100644
File size: 6.6 KB
Line 
1/*
2 * Copyright (c) 2010 Lenka Trochtova
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/**
30 * @defgroup serial Serial port driver.
31 * @brief HelenOS serial port driver.
32 * @{
33 */
34
35/** @file
36 */
37
38#include <assert.h>
39#include <stdio.h>
40#include <errno.h>
41#include <bool.h>
42#include <fibril_synch.h>
43#include <stdlib.h>
44#include <string.h>
45#include <ctype.h>
46#include <macros.h>
47#include <malloc.h>
48#include <dirent.h>
49#include <fcntl.h>
50#include <sys/stat.h>
51#include <ddi.h>
52#include <libarch/ddi.h>
53
54#include <driver.h>
55#include <resource.h>
56
57#include <devman.h>
58#include <ipc/devman.h>
59#include <device/hw_res.h>
60
61#include "cyclic_buffer.h"
62
63#define NAME "serial"
64
65#define REG_COUNT 7
66
67typedef struct serial_dev_data {
68 bool client_connected;
69 int irq;
70 uint32_t io_addr;
71 ioport8_t *port;
72 cyclic_buffer_t input_buffer;
73 fibril_mutex_t mutex;
74} serial_dev_data_t;
75
76static serial_dev_data_t * create_serial_dev_data()
77{
78 serial_dev_data_t *data = (serial_dev_data_t *)malloc(sizeof(serial_dev_data_t));
79 if (NULL != data) {
80 memset(data, 0, sizeof(serial_dev_data_t));
81 fibril_mutex_initialize(&data->mutex);
82 }
83 return data;
84}
85
86static void delete_serial_dev_data(serial_dev_data_t *data)
87{
88 if (NULL != data) {
89 free(data);
90 }
91}
92
93static device_class_t serial_dev_class;
94
95static bool serial_add_device(device_t *dev);
96
97/** The serial port device driver's standard operations.
98 */
99static driver_ops_t serial_ops = {
100 .add_device = &serial_add_device
101};
102
103/** The serial port device driver structure.
104 */
105static driver_t serial_driver = {
106 .name = NAME,
107 .driver_ops = &serial_ops
108};
109
110static void serial_dev_cleanup(device_t *dev)
111{
112 if (NULL != dev->driver_data) {
113 delete_serial_dev_data((serial_dev_data_t*)dev->driver_data);
114 dev->driver_data = NULL;
115 }
116
117 if (dev->parent_phone > 0) {
118 ipc_hangup(dev->parent_phone);
119 dev->parent_phone = 0;
120 }
121}
122
123static bool serial_pio_enable(device_t *dev)
124{
125 printf(NAME ": serial_pio_enable = %s\n", dev->name);
126
127 serial_dev_data_t *data = (serial_dev_data_t *)dev->driver_data;
128
129 // Gain control over port's registers.
130 if (pio_enable((void *)data->io_addr, REG_COUNT, (void **)(&data->port))) {
131 printf(NAME ": error - cannot gain the port %lx for device %s.\n", data->io_addr, dev->name);
132 return false;
133 }
134
135 return true;
136}
137
138static bool serial_dev_probe(device_t *dev)
139{
140 printf(NAME ": serial_dev_probe dev = %s\n", dev->name);
141
142 serial_dev_data_t *data = (serial_dev_data_t *)dev->driver_data;
143 ioport8_t *port_addr = data->port;
144 bool res = true;
145 uint8_t olddata;
146
147 olddata = pio_read_8(port_addr + 4);
148
149 pio_write_8(port_addr + 4, 0x10);
150 if (pio_read_8(port_addr + 6) & 0xf0) {
151 res = false;
152 }
153
154 pio_write_8(port_addr + 4, 0x1f);
155 if ((pio_read_8(port_addr + 6) & 0xf0) != 0xf0) {
156 res = false;
157 }
158
159 pio_write_8(port_addr + 4, olddata);
160
161 if (!res) {
162 printf(NAME ": device %s is not present.\n", dev->name);
163 }
164
165 return res;
166}
167
168static bool serial_dev_initialize(device_t *dev)
169{
170 printf(NAME ": serial_dev_initialize dev = %s\n", dev->name);
171
172 hw_resource_list_t hw_resources;
173 memset(&hw_resources, 0, sizeof(hw_resource_list_t));
174
175 // allocate driver data for the device
176 serial_dev_data_t *data = create_serial_dev_data();
177 if (NULL == data) {
178 return false;
179 }
180 dev->driver_data = data;
181
182 // connect to the parent's driver
183 dev->parent_phone = devman_parent_device_connect(dev->handle, IPC_FLAG_BLOCKING);
184 if (dev->parent_phone <= 0) {
185 printf(NAME ": failed to connect to the parent driver of the device %s.\n", dev->name);
186 goto failed;
187 }
188
189 // get hw resources
190
191 if (!get_hw_resources(dev->parent_phone, &hw_resources)) {
192 printf(NAME ": failed to get hw resources for the device %s.\n", dev->name);
193 goto failed;
194 }
195
196 size_t i;
197 hw_resource_t *res;
198 bool irq = false;
199 bool ioport = false;
200
201 for (i = 0; i < hw_resources.count; i++) {
202 res = &hw_resources.resources[i];
203 switch (res->type) {
204 case INTERRUPT:
205 data->irq = res->res.interrupt.irq;
206 irq = true;
207 printf(NAME ": the %s device was asigned irq = 0x%x.\n", dev->name, data->irq);
208 break;
209 case IO_RANGE:
210 data->io_addr = res->res.io_range.address;
211 if (res->res.io_range.size < REG_COUNT) {
212 printf(NAME ": i/o range assigned to the device %s is too small.\n", dev->name);
213 goto failed;
214 }
215 ioport = true;
216 printf(NAME ": the %s device was asigned i/o address = 0x%x.\n", dev->name, data->io_addr);
217 break;
218 }
219 }
220
221 if (!irq || !ioport) {
222 printf(NAME ": missing hw resource(s) for the device %s.\n", dev->name);
223 goto failed;
224 }
225
226 clean_hw_resource_list(&hw_resources);
227 return true;
228
229failed:
230 serial_dev_cleanup(dev);
231 clean_hw_resource_list(&hw_resources);
232 return false;
233}
234
235static bool serial_add_device(device_t *dev)
236{
237 printf(NAME ": serial_add_device, device handle = %d\n", dev->handle);
238
239 if (!serial_dev_initialize(dev)) {
240 return false;
241 }
242
243 if (!serial_pio_enable(dev)) {
244 serial_dev_cleanup(dev);
245 return false;
246 }
247
248 if (!serial_dev_probe(dev)) {
249 serial_dev_cleanup(dev);
250 return false;
251 }
252
253 // TODO interrupt and serial port initialization (baud rate etc.)
254
255 return true;
256}
257
258static void serial_init()
259{
260 // TODO
261 serial_dev_class.id = 0;
262}
263
264int main(int argc, char *argv[])
265{
266 printf(NAME ": HelenOS serial port driver\n");
267 serial_init();
268 return driver_main(&serial_driver);
269}
270
271/**
272 * @}
273 */
Note: See TracBrowser for help on using the repository browser.