1/*****************************************************************************
2 *
3 * Module Name: ectransx.c
4 *   $Revision: 1.1.1.1 $
5 *
6 *****************************************************************************/
7
8/*
9 *  Copyright (C) 2000, 2001 Andrew Grover
10 *
11 *  This program is free software; you can redistribute it and/or modify
12 *  it under the terms of the GNU General Public License as published by
13 *  the Free Software Foundation; either version 2 of the License, or
14 *  (at your option) any later version.
15 *
16 *  This program is distributed in the hope that it will be useful,
17 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 *  GNU General Public License for more details.
20 *
21 *  You should have received a copy of the GNU General Public License
22 *  along with this program; if not, write to the Free Software
23 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24 */
25
26
27#include <acpi.h>
28#include "ec.h"
29
30#define _COMPONENT		ACPI_EC
31	MODULE_NAME             ("ectransx")
32
33
34/****************************************************************************
35 *
36 * FUNCTION:    ec_io_wait
37 *
38 * PARAMETERS:
39 *
40 * RETURN:
41 *
42 * DESCRIPTION:
43 *
44 ****************************************************************************/
45
46acpi_status
47ec_io_wait (
48	EC_CONTEXT              *ec,
49	EC_EVENT                wait_event)
50{
51	EC_STATUS               ec_status = 0;
52	u32                     i = 100;
53
54	if (!ec || ((wait_event != EC_EVENT_OUTPUT_BUFFER_FULL)
55		&& (wait_event != EC_EVENT_INPUT_BUFFER_EMPTY))) {
56		return(AE_BAD_PARAMETER);
57	}
58
59	/*
60	 * Wait for Event:
61	 * ---------------
62	 * Poll the EC status register waiting for the event to occur.
63	 * Note that we'll wait a maximum of 1ms in 10us chunks.
64	 */
65	switch (wait_event) {
66
67	case EC_EVENT_OUTPUT_BUFFER_FULL:
68		do {
69			acpi_os_read_port(ec->status_port, &ec_status, 8);
70			if (ec_status & EC_FLAG_OUTPUT_BUFFER) {
71				return(AE_OK);
72			}
73			acpi_os_stall(10);
74		} while (--i>0);
75		break;
76
77	case EC_EVENT_INPUT_BUFFER_EMPTY:
78		do {
79			acpi_os_read_port(ec->status_port, &ec_status, 8);
80			if (!(ec_status & EC_FLAG_INPUT_BUFFER)) {
81				return(AE_OK);
82			}
83			acpi_os_stall(10);
84		} while (--i>0);
85		break;
86	}
87
88	return(AE_TIME);
89}
90
91
92/****************************************************************************
93 *
94 * FUNCTION:    ec_io_read
95 *
96 * PARAMETERS:
97 *
98 * RETURN:
99 *
100 * DESCRIPTION:
101 *
102 ****************************************************************************/
103
104acpi_status
105ec_io_read (
106	EC_CONTEXT              *ec,
107	u32		        io_port,
108	u8                      *data,
109	EC_EVENT                wait_event)
110{
111	acpi_status             status = AE_OK;
112
113	if (!ec || !data) {
114		return(AE_BAD_PARAMETER);
115	}
116
117	acpi_os_read_port(io_port, (u32*) data, 8);
118
119	if (wait_event) {
120		status = ec_io_wait(ec, wait_event);
121	}
122
123	return(status);
124}
125
126
127/****************************************************************************
128 *
129 * FUNCTION:    ec_io_write
130 *
131 * PARAMETERS:
132 *
133 * RETURN:
134 *
135 * DESCRIPTION:
136 *
137 ****************************************************************************/
138
139acpi_status
140ec_io_write (
141	EC_CONTEXT              *ec,
142	u32		       io_port,
143	u8                      data,
144	EC_EVENT                wait_event)
145{
146	acpi_status             status = AE_OK;
147
148	if (!ec) {
149		return(AE_BAD_PARAMETER);
150	}
151
152	acpi_os_write_port(io_port, data, 8);
153
154	if (wait_event) {
155		status = ec_io_wait(ec, wait_event);
156	}
157
158	return(status);
159}
160
161
162/****************************************************************************
163 *
164 * FUNCTION:    ec_read
165 *
166 * PARAMETERS:
167 *
168 * RETURN:
169 *
170 * DESCRIPTION:
171 *
172 ****************************************************************************/
173
174acpi_status
175ec_read (
176	EC_CONTEXT              *ec,
177	u8                      address,
178	u8                      *data)
179{
180	acpi_status             status = AE_OK;
181
182	FUNCTION_TRACE("ec_read");
183
184	if (!ec || !data) {
185		return_ACPI_STATUS(AE_BAD_PARAMETER);
186	}
187
188	if (ec->use_global_lock) {
189		status = acpi_acquire_global_lock();
190		if (ACPI_FAILURE(status)) {
191			ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "Could not acquire Global Lock\n"));
192			return_ACPI_STATUS(status);
193		}
194	}
195
196	status = ec_io_write(ec, ec->command_port, EC_COMMAND_READ,
197		EC_EVENT_INPUT_BUFFER_EMPTY);
198	if (ACPI_FAILURE(status)) {
199		ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "Unable to send 'read command' to EC.\n"));
200		return_ACPI_STATUS(status);
201	}
202
203	status = ec_io_write(ec, ec->data_port, address,
204		EC_EVENT_OUTPUT_BUFFER_FULL);
205	if (ACPI_FAILURE(status)) {
206		ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "Unable to send 'read address' to EC.\n"));
207		return_ACPI_STATUS(status);
208	}
209
210	status = ec_io_read(ec, ec->data_port, data, EC_EVENT_NONE);
211
212	if (ec->use_global_lock) {
213		acpi_release_global_lock();
214	}
215
216	ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Read data [%02x] from address [%02x] on ec [%02x].\n", (*data), address, ec->device_handle));
217
218	return_ACPI_STATUS(status);
219}
220
221
222/****************************************************************************
223 *
224 * FUNCTION:    ec_write
225 *
226 * PARAMETERS:
227 *
228 * RETURN:
229 *
230 * DESCRIPTION:
231 *
232 ****************************************************************************/
233
234acpi_status
235ec_write (
236	EC_CONTEXT              *ec,
237	u8                      address,
238	u8                      data)
239{
240	acpi_status             status = AE_OK;
241
242	FUNCTION_TRACE("ec_write");
243
244	if (!ec)
245		return_ACPI_STATUS(AE_BAD_PARAMETER);
246
247	if (ec->use_global_lock) {
248		status = acpi_acquire_global_lock();
249		if (ACPI_FAILURE(status)) {
250			ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "Could not acquire Global Lock\n"));
251			return_ACPI_STATUS(status);
252		}
253	}
254
255	status = ec_io_write(ec, ec->command_port, EC_COMMAND_WRITE,
256		EC_EVENT_INPUT_BUFFER_EMPTY);
257	if (ACPI_FAILURE(status)) {
258		ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "Unable to send 'write command' to EC.\n"));
259		return_ACPI_STATUS(status);
260	}
261
262	status = ec_io_write(ec, ec->data_port, address,
263		EC_EVENT_INPUT_BUFFER_EMPTY);
264	if (ACPI_FAILURE(status)) {
265		ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "Unable to send 'write address' to EC.\n"));
266		return_ACPI_STATUS(status);
267	}
268
269	status = ec_io_write(ec, ec->data_port, data,
270		EC_EVENT_INPUT_BUFFER_EMPTY);
271	if (ACPI_FAILURE(status)) {
272		ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "Unable to send 'write data' to EC.\n"));
273		return_ACPI_STATUS(status);
274	}
275
276	if (ec->use_global_lock) {
277		acpi_release_global_lock();
278	}
279
280	ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Wrote data [%02x] to address [%02x] on ec [%02x].\n", data, address, ec->device_handle));
281
282	return_ACPI_STATUS(status);
283}
284
285
286/****************************************************************************
287 *
288 * FUNCTION:    ec_transaction
289 *
290 * PARAMETERS:
291 *
292 * RETURN:
293 *
294 * DESCRIPTION:
295 *
296 ****************************************************************************/
297
298acpi_status
299ec_transaction (
300	EC_CONTEXT              *ec,
301	EC_REQUEST              *request)
302{
303	acpi_status             status = AE_OK;
304
305	FUNCTION_TRACE("ec_transaction");
306
307	if (!ec || !request) {
308		return_ACPI_STATUS(AE_BAD_PARAMETER);
309	}
310
311	/*
312	 * Obtain mutex to serialize all EC transactions.
313	 */
314	status = acpi_os_wait_semaphore(ec->mutex, 1, EC_DEFAULT_TIMEOUT);
315	if (ACPI_FAILURE(status)) {
316		return_ACPI_STATUS(status);
317	}
318
319	/*
320	 * Perform the transaction.
321	 */
322	switch (request->command) {
323
324	case EC_COMMAND_READ:
325		status = ec_read(ec, request->address, &(request->data));
326		break;
327
328	case EC_COMMAND_WRITE:
329		status = ec_write(ec, request->address, request->data);
330		break;
331
332	default:
333		status = AE_SUPPORT;
334		break;
335	}
336
337	/*
338	 * Signal the mutex to indicate transaction completion.
339	 */
340	acpi_os_signal_semaphore(ec->mutex, 1);
341
342	return_ACPI_STATUS(status);
343}
344