2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2012 Free Software Foundation, Inc.
5 * GRUB is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * GRUB is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
19 #include <grub/serial.h>
20 #include <grub/types.h>
22 #include <grub/misc.h>
24 #include <grub/time.h>
25 #include <grub/i18n.h>
27 GRUB_MOD_LICENSE ("GPLv3+");
29 struct grub_escc_descriptor
31 volatile grub_uint8_t
*escc_ctrl
;
32 volatile grub_uint8_t
*escc_data
;
36 do_real_config (struct grub_serial_port
*port
)
38 grub_uint8_t bitsspec
;
39 grub_uint8_t parity_stop_spec
;
43 /* Make sure the port is waiting for address now. */
44 (void) *port
->escc_desc
->escc_ctrl
;
45 switch (port
->config
.speed
)
48 *port
->escc_desc
->escc_ctrl
= 13;
49 *port
->escc_desc
->escc_ctrl
= 0;
50 *port
->escc_desc
->escc_ctrl
= 12;
51 *port
->escc_desc
->escc_ctrl
= 0;
52 *port
->escc_desc
->escc_ctrl
= 14;
53 *port
->escc_desc
->escc_ctrl
= 1;
54 *port
->escc_desc
->escc_ctrl
= 11;
55 *port
->escc_desc
->escc_ctrl
= 0x50;
58 *port
->escc_desc
->escc_ctrl
= 13;
59 *port
->escc_desc
->escc_ctrl
= 0;
60 *port
->escc_desc
->escc_ctrl
= 12;
61 *port
->escc_desc
->escc_ctrl
= 1;
62 *port
->escc_desc
->escc_ctrl
= 14;
63 *port
->escc_desc
->escc_ctrl
= 1;
64 *port
->escc_desc
->escc_ctrl
= 11;
65 *port
->escc_desc
->escc_ctrl
= 0x50;
70 switch (port
->config
.parity
)
72 case GRUB_SERIAL_PARITY_NONE
:
73 parity_stop_spec
|= 0;
75 case GRUB_SERIAL_PARITY_ODD
:
76 parity_stop_spec
|= 1;
78 case GRUB_SERIAL_PARITY_EVEN
:
79 parity_stop_spec
|= 3;
83 switch (port
->config
.stop_bits
)
85 case GRUB_SERIAL_STOP_BITS_1
:
86 parity_stop_spec
|= 0x4;
88 case GRUB_SERIAL_STOP_BITS_1_5
:
89 parity_stop_spec
|= 0x8;
91 case GRUB_SERIAL_STOP_BITS_2
:
92 parity_stop_spec
|= 0xc;
96 *port
->escc_desc
->escc_ctrl
= 4;
97 *port
->escc_desc
->escc_ctrl
= 0x40 | parity_stop_spec
;
99 bitsspec
= port
->config
.word_len
- 5;
100 bitsspec
= ((bitsspec
>> 1) | (bitsspec
<< 1)) & 3;
102 *port
->escc_desc
->escc_ctrl
= 3;
103 *port
->escc_desc
->escc_ctrl
= (bitsspec
<< 6) | 0x1;
105 port
->configured
= 1;
112 serial_hw_fetch (struct grub_serial_port
*port
)
114 do_real_config (port
);
116 *port
->escc_desc
->escc_ctrl
= 0;
117 if (*port
->escc_desc
->escc_ctrl
& 1)
118 return *port
->escc_desc
->escc_data
;
122 /* Put a character. */
124 serial_hw_put (struct grub_serial_port
*port
, const int c
)
126 grub_uint64_t endtime
;
128 do_real_config (port
);
130 if (port
->broken
> 5)
131 endtime
= grub_get_time_ms ();
132 else if (port
->broken
> 1)
133 endtime
= grub_get_time_ms () + 50;
135 endtime
= grub_get_time_ms () + 200;
136 /* Wait until the transmitter holding register is empty. */
139 *port
->escc_desc
->escc_ctrl
= 0;
140 if (*port
->escc_desc
->escc_ctrl
& 4)
142 if (grub_get_time_ms () > endtime
)
145 /* There is something wrong. But what can I do? */
153 *port
->escc_desc
->escc_data
= c
;
156 /* Initialize a serial device. PORT is the port number for a serial device.
157 SPEED is a DTE-DTE speed which must be one of these: 2400, 4800, 9600,
158 19200, 38400, 57600 and 115200. WORD_LEN is the word length to be used
159 for the device. Likewise, PARITY is the type of the parity and
160 STOP_BIT_LEN is the length of the stop bit. The possible values for
161 WORD_LEN, PARITY and STOP_BIT_LEN are defined in the header file as
164 serial_hw_configure (struct grub_serial_port
*port
__attribute__ ((unused
)),
165 struct grub_serial_config
*config
__attribute__ ((unused
)))
167 if (config
->speed
!= 38400 && config
->speed
!= 57600)
168 return grub_error (GRUB_ERR_BAD_ARGUMENT
,
169 N_("unsupported serial port speed"));
171 if (config
->parity
!= GRUB_SERIAL_PARITY_NONE
172 && config
->parity
!= GRUB_SERIAL_PARITY_ODD
173 && config
->parity
!= GRUB_SERIAL_PARITY_EVEN
)
174 return grub_error (GRUB_ERR_BAD_ARGUMENT
,
175 N_("unsupported serial port parity"));
177 if (config
->stop_bits
!= GRUB_SERIAL_STOP_BITS_1
178 && config
->stop_bits
!= GRUB_SERIAL_STOP_BITS_1_5
179 && config
->stop_bits
!= GRUB_SERIAL_STOP_BITS_2
)
180 return grub_error (GRUB_ERR_BAD_ARGUMENT
,
181 N_("unsupported serial port stop bits number"));
183 if (config
->word_len
< 5 || config
->word_len
> 8)
184 return grub_error (GRUB_ERR_BAD_ARGUMENT
,
185 N_("unsupported serial port word length"));
187 port
->config
= *config
;
188 port
->configured
= 0;
190 /* FIXME: should check if the serial terminal was found. */
192 return GRUB_ERR_NONE
;
195 struct grub_serial_driver grub_escc_driver
=
197 .configure
= serial_hw_configure
,
198 .fetch
= serial_hw_fetch
,
202 static struct grub_escc_descriptor escc_descs
[2];
203 static char *macio
= 0;
206 add_device (grub_addr_t addr
, int channel
)
208 struct grub_serial_port
*port
;
210 struct grub_serial_config config
=
214 .parity
= GRUB_SERIAL_PARITY_NONE
,
215 .stop_bits
= GRUB_SERIAL_STOP_BITS_1
218 escc_descs
[channel
].escc_ctrl
219 = (volatile grub_uint8_t
*) (grub_addr_t
) addr
;
220 escc_descs
[channel
].escc_data
= escc_descs
[channel
].escc_ctrl
+ 16;
222 port
= grub_zalloc (sizeof (*port
));
229 port
->name
= grub_xasprintf ("escc-ch-%c", channel
+ 'a');
236 port
->escc_desc
= &escc_descs
[channel
];
238 port
->driver
= &grub_escc_driver
;
240 err
= port
->driver
->configure (port
, &config
);
244 grub_serial_register (port
);
248 find_macio (struct grub_ieee1275_devalias
*alias
)
250 if (grub_strcmp (alias
->type
, "mac-io") != 0)
252 macio
= grub_strdup (alias
->path
);
258 grub_uint32_t macio_addr
[4];
259 grub_uint32_t escc_addr
[2];
260 grub_ieee1275_phandle_t dev
;
261 struct grub_ieee1275_devalias alias
;
264 grub_ieee1275_devices_iterate (find_macio
);
268 FOR_IEEE1275_DEVCHILDREN(macio
, alias
)
269 if (grub_strcmp (alias
.type
, "escc") == 0)
271 escc
= grub_strdup (alias
.path
);
274 grub_ieee1275_devalias_free (&alias
);
281 if (grub_ieee1275_finddevice (macio
, &dev
))
287 if (grub_ieee1275_get_integer_property (dev
, "assigned-addresses",
288 macio_addr
, sizeof (macio_addr
), 0))
295 if (grub_ieee1275_finddevice (escc
, &dev
))
302 if (grub_ieee1275_get_integer_property (dev
, "reg",
303 escc_addr
, sizeof (escc_addr
), 0))
310 add_device (macio_addr
[2] + escc_addr
[0] + 32, 0);
311 add_device (macio_addr
[2] + escc_addr
[0], 1);