1/*******************************************************************************
2 *
3 * Module Name: rsirq - IRQ resource descriptors
4 *              $Revision: 1.1.1.1 $
5 *
6 ******************************************************************************/
7
8/*
9 *  Copyright (C) 2000, 2001 R. Byron Moore
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 "acresrc.h"
29
30#define _COMPONENT          ACPI_RESOURCES
31	 MODULE_NAME         ("rsirq")
32
33
34/*******************************************************************************
35 *
36 * FUNCTION:    Acpi_rs_irq_resource
37 *
38 * PARAMETERS:  Byte_stream_buffer      - Pointer to the resource input byte
39 *                                        stream
40 *              Bytes_consumed          - u32 pointer that is filled with
41 *                                        the number of bytes consumed from
42 *                                        the Byte_stream_buffer
43 *              Output_buffer           - Pointer to the user's return buffer
44 *              Structure_size          - u32 pointer that is filled with
45 *                                        the number of bytes in the filled
46 *                                        in structure
47 *
48 * RETURN:      Status
49 *
50 * DESCRIPTION: Take the resource byte stream and fill out the appropriate
51 *              structure pointed to by the Output_buffer. Return the
52 *              number of bytes consumed from the byte stream.
53 *
54 ******************************************************************************/
55
56acpi_status
57acpi_rs_irq_resource (
58	u8                      *byte_stream_buffer,
59	u32                     *bytes_consumed,
60	u8                      **output_buffer,
61	u32                     *structure_size)
62{
63	u8                      *buffer = byte_stream_buffer;
64	acpi_resource           *output_struct = (acpi_resource *) *output_buffer;
65	u16                     temp16 = 0;
66	u8                      temp8 = 0;
67	u8                      index;
68	u8                      i;
69	u32                     struct_size = SIZEOF_RESOURCE (acpi_resource_irq);
70
71
72	FUNCTION_TRACE ("Rs_irq_resource");
73
74
75	/*
76	 * The number of bytes consumed are contained in the descriptor
77	 *  (Bits:0-1)
78	 */
79	temp8 = *buffer;
80	*bytes_consumed = (temp8 & 0x03) + 1;
81	output_struct->id = ACPI_RSTYPE_IRQ;
82
83	/*
84	 * Point to the 16-bits of Bytes 1 and 2
85	 */
86	buffer += 1;
87	MOVE_UNALIGNED16_TO_16 (&temp16, buffer);
88
89	output_struct->data.irq.number_of_interrupts = 0;
90
91	/* Decode the IRQ bits */
92
93	for (i = 0, index = 0; index < 16; index++) {
94		if((temp16 >> index) & 0x01) {
95			output_struct->data.irq.interrupts[i] = index;
96			i++;
97		}
98	}
99	output_struct->data.irq.number_of_interrupts = i;
100
101	/*
102	 * Calculate the structure size based upon the number of interrupts
103	 */
104	struct_size += (output_struct->data.irq.number_of_interrupts - 1) * 4;
105
106	/*
107	 * Point to Byte 3 if it is used
108	 */
109	if (4 == *bytes_consumed) {
110		buffer += 2;
111		temp8 = *buffer;
112
113		/*
114		 * Check for HE, LL or HL
115		 */
116		if (temp8 & 0x01) {
117			output_struct->data.irq.edge_level = EDGE_SENSITIVE;
118			output_struct->data.irq.active_high_low = ACTIVE_HIGH;
119		}
120
121		else {
122			if (temp8 & 0x8) {
123				output_struct->data.irq.edge_level = LEVEL_SENSITIVE;
124				output_struct->data.irq.active_high_low = ACTIVE_LOW;
125			}
126
127			else {
128				/*
129				 * Only _LL and _HE polarity/trigger interrupts
130				 * are allowed (ACPI spec v1.0b ection 6.4.2.1),
131				 * so an error will occur if we reach this point
132				 */
133				return_ACPI_STATUS (AE_BAD_DATA);
134			}
135		}
136
137		/*
138		 * Check for sharable
139		 */
140		output_struct->data.irq.shared_exclusive = (temp8 >> 3) & 0x01;
141	}
142
143	else {
144		/*
145		 * Assume Edge Sensitive, Active High, Non-Sharable
146		 * per ACPI Specification
147		 */
148		output_struct->data.irq.edge_level = EDGE_SENSITIVE;
149		output_struct->data.irq.active_high_low = ACTIVE_HIGH;
150		output_struct->data.irq.shared_exclusive = EXCLUSIVE;
151	}
152
153	/*
154	 * Set the Length parameter
155	 */
156	output_struct->length = struct_size;
157
158	/*
159	 * Return the final size of the structure
160	 */
161	*structure_size = struct_size;
162	return_ACPI_STATUS (AE_OK);
163}
164
165
166/*******************************************************************************
167 *
168 * FUNCTION:    Acpi_rs_irq_stream
169 *
170 * PARAMETERS:  Linked_list             - Pointer to the resource linked list
171 *              Output_buffer           - Pointer to the user's return buffer
172 *              Bytes_consumed          - u32 pointer that is filled with
173 *                                        the number of bytes of the
174 *                                        Output_buffer used
175 *
176 * RETURN:      Status
177 *
178 * DESCRIPTION: Take the linked list resource structure and fills in the
179 *              the appropriate bytes in a byte stream
180 *
181 ******************************************************************************/
182
183acpi_status
184acpi_rs_irq_stream (
185	acpi_resource           *linked_list,
186	u8                      **output_buffer,
187	u32                     *bytes_consumed)
188{
189	u8                      *buffer = *output_buffer;
190	u16                     temp16 = 0;
191	u8                      temp8 = 0;
192	u8                      index;
193	u8                      IRQinfo_byte_needed;
194
195
196	FUNCTION_TRACE ("Rs_irq_stream");
197
198
199	/*
200	 * The descriptor field is set based upon whether a third byte is
201	 * needed to contain the IRQ Information.
202	 */
203	if (EDGE_SENSITIVE == linked_list->data.irq.edge_level &&
204		ACTIVE_HIGH == linked_list->data.irq.active_high_low &&
205		EXCLUSIVE == linked_list->data.irq.shared_exclusive) {
206		*buffer = 0x22;
207		IRQinfo_byte_needed = FALSE;
208	}
209
210	else {
211		*buffer = 0x23;
212		IRQinfo_byte_needed = TRUE;
213	}
214
215	buffer += 1;
216	temp16 = 0;
217
218	/*
219	 * Loop through all of the interrupts and set the mask bits
220	 */
221	for(index = 0;
222		index < linked_list->data.irq.number_of_interrupts;
223		index++) {
224		temp8 = (u8) linked_list->data.irq.interrupts[index];
225		temp16 |= 0x1 << temp8;
226	}
227
228	MOVE_UNALIGNED16_TO_16 (buffer, &temp16);
229	buffer += 2;
230
231	/*
232	 * Set the IRQ Info byte if needed.
233	 */
234	if (IRQinfo_byte_needed) {
235		temp8 = 0;
236		temp8 = (u8) ((linked_list->data.irq.shared_exclusive &
237				 0x01) << 4);
238
239		if (LEVEL_SENSITIVE == linked_list->data.irq.edge_level &&
240			ACTIVE_LOW == linked_list->data.irq.active_high_low) {
241			temp8 |= 0x08;
242		}
243
244		else {
245			temp8 |= 0x01;
246		}
247
248		*buffer = temp8;
249		buffer += 1;
250	}
251
252	/*
253	 * Return the number of bytes consumed in this operation
254	 */
255	*bytes_consumed = POINTER_DIFF (buffer, *output_buffer);
256	return_ACPI_STATUS (AE_OK);
257}
258
259
260/*******************************************************************************
261 *
262 * FUNCTION:    Acpi_rs_extended_irq_resource
263 *
264 * PARAMETERS:  Byte_stream_buffer      - Pointer to the resource input byte
265 *                                        stream
266 *              Bytes_consumed          - u32 pointer that is filled with
267 *                                        the number of bytes consumed from
268 *                                        the Byte_stream_buffer
269 *              Output_buffer           - Pointer to the user's return buffer
270 *              Structure_size          - u32 pointer that is filled with
271 *                                        the number of bytes in the filled
272 *                                        in structure
273 *
274 * RETURN:      Status
275 *
276 * DESCRIPTION: Take the resource byte stream and fill out the appropriate
277 *              structure pointed to by the Output_buffer. Return the
278 *              number of bytes consumed from the byte stream.
279 *
280 ******************************************************************************/
281
282acpi_status
283acpi_rs_extended_irq_resource (
284	u8                      *byte_stream_buffer,
285	u32                     *bytes_consumed,
286	u8                      **output_buffer,
287	u32                     *structure_size)
288{
289	u8                      *buffer = byte_stream_buffer;
290	acpi_resource           *output_struct = (acpi_resource *) *output_buffer;
291	u16                     temp16 = 0;
292	u8                      temp8 = 0;
293	NATIVE_CHAR             *temp_ptr;
294	u8                      index;
295	u32                     struct_size = SIZEOF_RESOURCE (acpi_resource_ext_irq);
296
297
298	FUNCTION_TRACE ("Rs_extended_irq_resource");
299
300
301	/*
302	 * Point past the Descriptor to get the number of bytes consumed
303	 */
304	buffer += 1;
305	MOVE_UNALIGNED16_TO_16 (&temp16, buffer);
306
307	*bytes_consumed = temp16 + 3;
308	output_struct->id = ACPI_RSTYPE_EXT_IRQ;
309
310	/*
311	 * Point to the Byte3
312	 */
313	buffer += 2;
314	temp8 = *buffer;
315
316	output_struct->data.extended_irq.producer_consumer = temp8 & 0x01;
317
318	/*
319	 * Check for HE, LL or HL
320	 */
321	if(temp8 & 0x02) {
322		output_struct->data.extended_irq.edge_level = EDGE_SENSITIVE;
323		output_struct->data.extended_irq.active_high_low = ACTIVE_HIGH;
324	}
325
326	else {
327		if(temp8 & 0x4) {
328			output_struct->data.extended_irq.edge_level = LEVEL_SENSITIVE;
329			output_struct->data.extended_irq.active_high_low = ACTIVE_LOW;
330		}
331
332		else {
333			/*
334			 * Only _LL and _HE polarity/trigger interrupts
335			 * are allowed (ACPI spec v1.0b ection 6.4.2.1),
336			 * so an error will occur if we reach this point
337			 */
338			return_ACPI_STATUS (AE_BAD_DATA);
339		}
340	}
341
342	/*
343	 * Check for sharable
344	 */
345	output_struct->data.extended_irq.shared_exclusive = (temp8 >> 3) & 0x01;
346
347	/*
348	 * Point to Byte4 (IRQ Table length)
349	 */
350	buffer += 1;
351	temp8 = *buffer;
352
353	output_struct->data.extended_irq.number_of_interrupts = temp8;
354
355	/*
356	 * Add any additional structure size to properly calculate
357	 * the next pointer at the end of this function
358	 */
359	struct_size += (temp8 - 1) * 4;
360
361	/*
362	 * Point to Byte5 (First IRQ Number)
363	 */
364	buffer += 1;
365
366	/*
367	 * Cycle through every IRQ in the table
368	 */
369	for (index = 0; index < temp8; index++) {
370		output_struct->data.extended_irq.interrupts[index] =
371				(u32)*buffer;
372
373		/* Point to the next IRQ */
374
375		buffer += 4;
376	}
377
378	/*
379	 * This will leave us pointing to the Resource Source Index
380	 * If it is present, then save it off and calculate the
381	 * pointer to where the null terminated string goes:
382	 * Each Interrupt takes 32-bits + the 5 bytes of the
383	 * stream that are default.
384	 */
385	if (*bytes_consumed >
386		(u32)(output_struct->data.extended_irq.number_of_interrupts * 4) + 5) {
387		/* Dereference the Index */
388
389		temp8 = *buffer;
390		output_struct->data.extended_irq.resource_source.index = (u32) temp8;
391
392		/* Point to the String */
393
394		buffer += 1;
395
396		/*
397		 * Point the String pointer to the end of this structure.
398		 */
399		output_struct->data.extended_irq.resource_source.string_ptr =
400				(NATIVE_CHAR *)(output_struct + struct_size);
401
402		temp_ptr = output_struct->data.extended_irq.resource_source.string_ptr;
403
404		/* Copy the string into the buffer */
405
406		index = 0;
407
408		while (0x00 != *buffer) {
409			*temp_ptr = *buffer;
410
411			temp_ptr += 1;
412			buffer += 1;
413			index += 1;
414		}
415
416		/*
417		 * Add the terminating null
418		 */
419		*temp_ptr = 0x00;
420		output_struct->data.extended_irq.resource_source.string_length = index + 1;
421
422		/*
423		 * In order for the Struct_size to fall on a 32-bit boundary,
424		 * calculate the length of the string and expand the
425		 * Struct_size to the next 32-bit boundary.
426		 */
427		temp8 = (u8) (index + 1);
428		struct_size += ROUND_UP_TO_32_bITS (temp8);
429	}
430
431	else {
432		output_struct->data.extended_irq.resource_source.index = 0x00;
433		output_struct->data.extended_irq.resource_source.string_length = 0;
434		output_struct->data.extended_irq.resource_source.string_ptr = NULL;
435	}
436
437	/*
438	 * Set the Length parameter
439	 */
440	output_struct->length = struct_size;
441
442	/*
443	 * Return the final size of the structure
444	 */
445	*structure_size = struct_size;
446	return_ACPI_STATUS (AE_OK);
447}
448
449
450/*******************************************************************************
451 *
452 * FUNCTION:    Acpi_rs_extended_irq_stream
453 *
454 * PARAMETERS:  Linked_list             - Pointer to the resource linked list
455 *              Output_buffer           - Pointer to the user's return buffer
456 *              Bytes_consumed          - u32 pointer that is filled with
457 *                                        the number of bytes of the
458 *                                        Output_buffer used
459 *
460 * RETURN:      Status
461 *
462 * DESCRIPTION: Take the linked list resource structure and fills in the
463 *              the appropriate bytes in a byte stream
464 *
465 ******************************************************************************/
466
467acpi_status
468acpi_rs_extended_irq_stream (
469	acpi_resource           *linked_list,
470	u8                      **output_buffer,
471	u32                     *bytes_consumed)
472{
473	u8                      *buffer = *output_buffer;
474	u16                     *length_field;
475	u8                      temp8 = 0;
476	u8                      index;
477	NATIVE_CHAR             *temp_pointer = NULL;
478
479
480	FUNCTION_TRACE ("Rs_extended_irq_stream");
481
482
483	/*
484	 * The descriptor field is static
485	 */
486	*buffer = 0x89;
487	buffer += 1;
488
489	/*
490	 * Set a pointer to the Length field - to be filled in later
491	 */
492	length_field = (u16 *)buffer;
493	buffer += 2;
494
495	/*
496	 * Set the Interrupt vector flags
497	 */
498	temp8 = (u8)(linked_list->data.extended_irq.producer_consumer & 0x01);
499	temp8 |= ((linked_list->data.extended_irq.shared_exclusive & 0x01) << 3);
500
501	if (LEVEL_SENSITIVE == linked_list->data.extended_irq.edge_level &&
502	   ACTIVE_LOW == linked_list->data.extended_irq.active_high_low) {
503		temp8 |= 0x04;
504	}
505	else {
506		temp8 |= 0x02;
507	}
508
509	*buffer = temp8;
510	buffer += 1;
511
512	/*
513	 * Set the Interrupt table length
514	 */
515	temp8 = (u8) linked_list->data.extended_irq.number_of_interrupts;
516
517	*buffer = temp8;
518	buffer += 1;
519
520	for (index = 0; index < linked_list->data.extended_irq.number_of_interrupts;
521		 index++) {
522		MOVE_UNALIGNED32_TO_32 (buffer,
523				  &linked_list->data.extended_irq.interrupts[index]);
524		buffer += 4;
525	}
526
527	/*
528	 * Resource Source Index and Resource Source are optional
529	 */
530	if (0 != linked_list->data.extended_irq.resource_source.string_length) {
531		*buffer = (u8) linked_list->data.extended_irq.resource_source.index;
532		buffer += 1;
533
534		temp_pointer = (NATIVE_CHAR *) buffer;
535
536		/*
537		 * Copy the string
538		 */
539		STRCPY (temp_pointer,
540			linked_list->data.extended_irq.resource_source.string_ptr);
541
542		/*
543		 * Buffer needs to be set to the length of the sting + one for the
544		 * terminating null
545		 */
546		buffer += (STRLEN (linked_list->data.extended_irq.resource_source.string_ptr) + 1);
547	}
548
549	/*
550	 * Return the number of bytes consumed in this operation
551	 */
552	*bytes_consumed = POINTER_DIFF (buffer, *output_buffer);
553
554	/*
555	 * Set the length field to the number of bytes consumed
556	 * minus the header size (3 bytes)
557	 */
558	*length_field = (u16) (*bytes_consumed - 3);
559	return_ACPI_STATUS (AE_OK);
560}
561
562