1 /*******************************************************************************
2  *
3  * Module Name: rsirq - IRQ resource descriptors
4  *
5  ******************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2004, R. Byron Moore
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions, and the following disclaimer,
16  *    without modification.
17  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18  *    substantially similar to the "NO WARRANTY" disclaimer below
19  *    ("Disclaimer") and any redistribution must be conditioned upon
20  *    including a substantially similar Disclaimer requirement for further
21  *    binary redistribution.
22  * 3. Neither the names of the above-listed copyright holders nor the names
23  *    of any contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * Alternatively, this software may be distributed under the terms of the
27  * GNU General Public License ("GPL") version 2 as published by the Free
28  * Software Foundation.
29  *
30  * NO WARRANTY
31  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41  * POSSIBILITY OF SUCH DAMAGES.
42  */
43 
44 
45 #include <acpi/acpi.h>
46 #include <acpi/acresrc.h>
47 
48 #define _COMPONENT          ACPI_RESOURCES
49 	 ACPI_MODULE_NAME    ("rsirq")
50 
51 
52 /*******************************************************************************
53  *
54  * FUNCTION:    acpi_rs_irq_resource
55  *
56  * PARAMETERS:  byte_stream_buffer      - Pointer to the resource input byte
57  *                                        stream
58  *              bytes_consumed          - Pointer to where the number of bytes
59  *                                        consumed the byte_stream_buffer is
60  *                                        returned
61  *              output_buffer           - Pointer to the return data buffer
62  *              structure_size          - Pointer to where the number of bytes
63  *                                        in the return data struct is returned
64  *
65  * RETURN:      Status
66  *
67  * DESCRIPTION: Take the resource byte stream and fill out the appropriate
68  *              structure pointed to by the output_buffer. Return the
69  *              number of bytes consumed from the byte stream.
70  *
71  ******************************************************************************/
72 
73 acpi_status
acpi_rs_irq_resource(u8 * byte_stream_buffer,acpi_size * bytes_consumed,u8 ** output_buffer,acpi_size * structure_size)74 acpi_rs_irq_resource (
75 	u8                              *byte_stream_buffer,
76 	acpi_size                       *bytes_consumed,
77 	u8                              **output_buffer,
78 	acpi_size                       *structure_size)
79 {
80 	u8                              *buffer = byte_stream_buffer;
81 	struct acpi_resource            *output_struct = (void *) *output_buffer;
82 	u16                             temp16 = 0;
83 	u8                              temp8 = 0;
84 	u8                              index;
85 	u8                              i;
86 	acpi_size                       struct_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_irq);
87 
88 
89 	ACPI_FUNCTION_TRACE ("rs_irq_resource");
90 
91 
92 	/*
93 	 * The number of bytes consumed are contained in the descriptor
94 	 *  (Bits:0-1)
95 	 */
96 	temp8 = *buffer;
97 	*bytes_consumed = (temp8 & 0x03) + 1;
98 	output_struct->id = ACPI_RSTYPE_IRQ;
99 
100 	/*
101 	 * Point to the 16-bits of Bytes 1 and 2
102 	 */
103 	buffer += 1;
104 	ACPI_MOVE_16_TO_16 (&temp16, buffer);
105 
106 	output_struct->data.irq.number_of_interrupts = 0;
107 
108 	/* Decode the IRQ bits */
109 
110 	for (i = 0, index = 0; index < 16; index++) {
111 		if ((temp16 >> index) & 0x01) {
112 			output_struct->data.irq.interrupts[i] = index;
113 			i++;
114 		}
115 	}
116 
117 	/* Zero interrupts is valid */
118 
119 	output_struct->data.irq.number_of_interrupts = i;
120 	if (i > 0) {
121 		/*
122 		 * Calculate the structure size based upon the number of interrupts
123 		 */
124 		struct_size += ((acpi_size) i - 1) * 4;
125 	}
126 
127 	/*
128 	 * Point to Byte 3 if it is used
129 	 */
130 	if (4 == *bytes_consumed) {
131 		buffer += 2;
132 		temp8 = *buffer;
133 
134 		/*
135 		 * Check for HE, LL interrupts
136 		 */
137 		switch (temp8 & 0x09) {
138 		case 0x01: /* HE */
139 			output_struct->data.irq.edge_level = ACPI_EDGE_SENSITIVE;
140 			output_struct->data.irq.active_high_low = ACPI_ACTIVE_HIGH;
141 			break;
142 
143 		case 0x08: /* LL */
144 			output_struct->data.irq.edge_level = ACPI_LEVEL_SENSITIVE;
145 			output_struct->data.irq.active_high_low = ACPI_ACTIVE_LOW;
146 			break;
147 
148 		default:
149 			/*
150 			 * Only _LL and _HE polarity/trigger interrupts
151 			 * are allowed (ACPI spec, section "IRQ Format")
152 			 * so 0x00 and 0x09 are illegal.
153 			 */
154 			ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
155 				"Invalid interrupt polarity/trigger in resource list, %X\n", temp8));
156 			return_ACPI_STATUS (AE_BAD_DATA);
157 		}
158 
159 		/*
160 		 * Check for sharable
161 		 */
162 		output_struct->data.irq.shared_exclusive = (temp8 >> 3) & 0x01;
163 	}
164 	else {
165 		/*
166 		 * Assume Edge Sensitive, Active High, Non-Sharable
167 		 * per ACPI Specification
168 		 */
169 		output_struct->data.irq.edge_level = ACPI_EDGE_SENSITIVE;
170 		output_struct->data.irq.active_high_low = ACPI_ACTIVE_HIGH;
171 		output_struct->data.irq.shared_exclusive = ACPI_EXCLUSIVE;
172 	}
173 
174 	/*
175 	 * Set the Length parameter
176 	 */
177 	output_struct->length = (u32) struct_size;
178 
179 	/*
180 	 * Return the final size of the structure
181 	 */
182 	*structure_size = struct_size;
183 	return_ACPI_STATUS (AE_OK);
184 }
185 
186 
187 /*******************************************************************************
188  *
189  * FUNCTION:    acpi_rs_irq_stream
190  *
191  * PARAMETERS:  linked_list             - Pointer to the resource linked list
192  *              output_buffer           - Pointer to the user's return buffer
193  *              bytes_consumed          - Pointer to where the number of bytes
194  *                                        used in the output_buffer is returned
195  *
196  * RETURN:      Status
197  *
198  * DESCRIPTION: Take the linked list resource structure and fills in the
199  *              the appropriate bytes in a byte stream
200  *
201  ******************************************************************************/
202 
203 acpi_status
acpi_rs_irq_stream(struct acpi_resource * linked_list,u8 ** output_buffer,acpi_size * bytes_consumed)204 acpi_rs_irq_stream (
205 	struct acpi_resource            *linked_list,
206 	u8                              **output_buffer,
207 	acpi_size                       *bytes_consumed)
208 {
209 	u8                              *buffer = *output_buffer;
210 	u16                             temp16 = 0;
211 	u8                              temp8 = 0;
212 	u8                              index;
213 	u8                              IRqinfo_byte_needed;
214 
215 
216 	ACPI_FUNCTION_TRACE ("rs_irq_stream");
217 
218 
219 	/*
220 	 * The descriptor field is set based upon whether a third byte is
221 	 * needed to contain the IRQ Information.
222 	 */
223 	if (ACPI_EDGE_SENSITIVE == linked_list->data.irq.edge_level &&
224 		ACPI_ACTIVE_HIGH == linked_list->data.irq.active_high_low &&
225 		ACPI_EXCLUSIVE == linked_list->data.irq.shared_exclusive) {
226 		*buffer = 0x22;
227 		IRqinfo_byte_needed = FALSE;
228 	}
229 	else {
230 		*buffer = 0x23;
231 		IRqinfo_byte_needed = TRUE;
232 	}
233 
234 	buffer += 1;
235 	temp16 = 0;
236 
237 	/*
238 	 * Loop through all of the interrupts and set the mask bits
239 	 */
240 	for(index = 0;
241 		index < linked_list->data.irq.number_of_interrupts;
242 		index++) {
243 		temp8 = (u8) linked_list->data.irq.interrupts[index];
244 		temp16 |= 0x1 << temp8;
245 	}
246 
247 	ACPI_MOVE_16_TO_16 (buffer, &temp16);
248 	buffer += 2;
249 
250 	/*
251 	 * Set the IRQ Info byte if needed.
252 	 */
253 	if (IRqinfo_byte_needed) {
254 		temp8 = 0;
255 		temp8 = (u8) ((linked_list->data.irq.shared_exclusive &
256 				 0x01) << 4);
257 
258 		if (ACPI_LEVEL_SENSITIVE == linked_list->data.irq.edge_level &&
259 			ACPI_ACTIVE_LOW == linked_list->data.irq.active_high_low) {
260 			temp8 |= 0x08;
261 		}
262 		else {
263 			temp8 |= 0x01;
264 		}
265 
266 		*buffer = temp8;
267 		buffer += 1;
268 	}
269 
270 	/*
271 	 * Return the number of bytes consumed in this operation
272 	 */
273 	*bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer);
274 	return_ACPI_STATUS (AE_OK);
275 }
276 
277 
278 /*******************************************************************************
279  *
280  * FUNCTION:    acpi_rs_extended_irq_resource
281  *
282  * PARAMETERS:  byte_stream_buffer      - Pointer to the resource input byte
283  *                                        stream
284  *              bytes_consumed          - Pointer to where the number of bytes
285  *                                        consumed the byte_stream_buffer is
286  *                                        returned
287  *              output_buffer           - Pointer to the return data buffer
288  *              structure_size          - Pointer to where the number of bytes
289  *                                        in the return data struct is returned
290  *
291  * RETURN:      Status
292  *
293  * DESCRIPTION: Take the resource byte stream and fill out the appropriate
294  *              structure pointed to by the output_buffer. Return the
295  *              number of bytes consumed from the byte stream.
296  *
297  ******************************************************************************/
298 
299 acpi_status
acpi_rs_extended_irq_resource(u8 * byte_stream_buffer,acpi_size * bytes_consumed,u8 ** output_buffer,acpi_size * structure_size)300 acpi_rs_extended_irq_resource (
301 	u8                              *byte_stream_buffer,
302 	acpi_size                       *bytes_consumed,
303 	u8                              **output_buffer,
304 	acpi_size                       *structure_size)
305 {
306 	u8                              *buffer = byte_stream_buffer;
307 	struct acpi_resource            *output_struct = (void *) *output_buffer;
308 	u16                             temp16 = 0;
309 	u8                              temp8 = 0;
310 	u8                              *temp_ptr;
311 	u8                              index;
312 	acpi_size                       struct_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_ext_irq);
313 
314 
315 	ACPI_FUNCTION_TRACE ("rs_extended_irq_resource");
316 
317 
318 	/*
319 	 * Point past the Descriptor to get the number of bytes consumed
320 	 */
321 	buffer += 1;
322 	ACPI_MOVE_16_TO_16 (&temp16, buffer);
323 
324 	/* Validate minimum descriptor length */
325 
326 	if (temp16 < 6) {
327 		return_ACPI_STATUS (AE_AML_BAD_RESOURCE_LENGTH);
328 	}
329 
330 	*bytes_consumed = temp16 + 3;
331 	output_struct->id = ACPI_RSTYPE_EXT_IRQ;
332 
333 	/*
334 	 * Point to the Byte3
335 	 */
336 	buffer += 2;
337 	temp8 = *buffer;
338 
339 	output_struct->data.extended_irq.producer_consumer = temp8 & 0x01;
340 
341 	/*
342 	 * Check for Interrupt Mode
343 	 *
344 	 * The definition of an Extended IRQ changed between ACPI spec v1.0b
345 	 * and ACPI spec 2.0 (section 6.4.3.6 in both).
346 	 *
347 	 * - Edge/Level are defined opposite in the table vs the headers
348 	 */
349 	output_struct->data.extended_irq.edge_level =
350 			   (temp8 & 0x2) ? ACPI_EDGE_SENSITIVE : ACPI_LEVEL_SENSITIVE;
351 
352 	/*
353 	 * Check Interrupt Polarity
354 	 */
355 	output_struct->data.extended_irq.active_high_low = (temp8 >> 2) & 0x1;
356 
357 	/*
358 	 * Check for sharable
359 	 */
360 	output_struct->data.extended_irq.shared_exclusive = (temp8 >> 3) & 0x01;
361 
362 	/*
363 	 * Point to Byte4 (IRQ Table length)
364 	 */
365 	buffer += 1;
366 	temp8 = *buffer;
367 
368 	/* Must have at least one IRQ */
369 
370 	if (temp8 < 1) {
371 		return_ACPI_STATUS (AE_AML_BAD_RESOURCE_LENGTH);
372 	}
373 
374 	output_struct->data.extended_irq.number_of_interrupts = temp8;
375 
376 	/*
377 	 * Add any additional structure size to properly calculate
378 	 * the next pointer at the end of this function
379 	 */
380 	struct_size += (temp8 - 1) * 4;
381 
382 	/*
383 	 * Point to Byte5 (First IRQ Number)
384 	 */
385 	buffer += 1;
386 
387 	/*
388 	 * Cycle through every IRQ in the table
389 	 */
390 	for (index = 0; index < temp8; index++) {
391 		ACPI_MOVE_32_TO_32 (
392 			&output_struct->data.extended_irq.interrupts[index], buffer);
393 
394 		/* Point to the next IRQ */
395 
396 		buffer += 4;
397 	}
398 
399 	/*
400 	 * This will leave us pointing to the Resource Source Index
401 	 * If it is present, then save it off and calculate the
402 	 * pointer to where the null terminated string goes:
403 	 * Each Interrupt takes 32-bits + the 5 bytes of the
404 	 * stream that are default.
405 	 *
406 	 * Note: Some resource descriptors will have an additional null, so
407 	 * we add 1 to the length.
408 	 */
409 	if (*bytes_consumed >
410 		((acpi_size) output_struct->data.extended_irq.number_of_interrupts * 4) + (5 + 1)) {
411 		/* Dereference the Index */
412 
413 		temp8 = *buffer;
414 		output_struct->data.extended_irq.resource_source.index = (u32) temp8;
415 
416 		/* Point to the String */
417 
418 		buffer += 1;
419 
420 		/*
421 		 * Point the String pointer to the end of this structure.
422 		 */
423 		output_struct->data.extended_irq.resource_source.string_ptr =
424 				(char *)((char *) output_struct + struct_size);
425 
426 		temp_ptr = (u8 *) output_struct->data.extended_irq.resource_source.string_ptr;
427 
428 		/* Copy the string into the buffer */
429 
430 		index = 0;
431 		while (0x00 != *buffer) {
432 			*temp_ptr = *buffer;
433 
434 			temp_ptr += 1;
435 			buffer += 1;
436 			index += 1;
437 		}
438 
439 		/*
440 		 * Add the terminating null
441 		 */
442 		*temp_ptr = 0x00;
443 		output_struct->data.extended_irq.resource_source.string_length = index + 1;
444 
445 		/*
446 		 * In order for the struct_size to fall on a 32-bit boundary,
447 		 * calculate the length of the string and expand the
448 		 * struct_size to the next 32-bit boundary.
449 		 */
450 		temp8 = (u8) (index + 1);
451 		struct_size += ACPI_ROUND_UP_to_32_bITS (temp8);
452 	}
453 	else {
454 		output_struct->data.extended_irq.resource_source.index = 0x00;
455 		output_struct->data.extended_irq.resource_source.string_length = 0;
456 		output_struct->data.extended_irq.resource_source.string_ptr = NULL;
457 	}
458 
459 	/*
460 	 * Set the Length parameter
461 	 */
462 	output_struct->length = (u32) struct_size;
463 
464 	/*
465 	 * Return the final size of the structure
466 	 */
467 	*structure_size = struct_size;
468 	return_ACPI_STATUS (AE_OK);
469 }
470 
471 
472 /*******************************************************************************
473  *
474  * FUNCTION:    acpi_rs_extended_irq_stream
475  *
476  * PARAMETERS:  linked_list             - Pointer to the resource linked list
477  *              output_buffer           - Pointer to the user's return buffer
478  *              bytes_consumed          - Pointer to where the number of bytes
479  *                                        used in the output_buffer is returned
480  *
481  * RETURN:      Status
482  *
483  * DESCRIPTION: Take the linked list resource structure and fills in the
484  *              the appropriate bytes in a byte stream
485  *
486  ******************************************************************************/
487 
488 acpi_status
acpi_rs_extended_irq_stream(struct acpi_resource * linked_list,u8 ** output_buffer,acpi_size * bytes_consumed)489 acpi_rs_extended_irq_stream (
490 	struct acpi_resource            *linked_list,
491 	u8                              **output_buffer,
492 	acpi_size                       *bytes_consumed)
493 {
494 	u8                              *buffer = *output_buffer;
495 	u16                             *length_field;
496 	u8                              temp8 = 0;
497 	u8                              index;
498 	char                            *temp_pointer = NULL;
499 
500 
501 	ACPI_FUNCTION_TRACE ("rs_extended_irq_stream");
502 
503 
504 	/*
505 	 * The descriptor field is static
506 	 */
507 	*buffer = 0x89;
508 	buffer += 1;
509 
510 	/*
511 	 * Set a pointer to the Length field - to be filled in later
512 	 */
513 	length_field = ACPI_CAST_PTR (u16, buffer);
514 	buffer += 2;
515 
516 	/*
517 	 * Set the Interrupt vector flags
518 	 */
519 	temp8 = (u8)(linked_list->data.extended_irq.producer_consumer & 0x01);
520 	temp8 |= ((linked_list->data.extended_irq.shared_exclusive & 0x01) << 3);
521 
522 	/*
523 	 * Set the Interrupt Mode
524 	 *
525 	 * The definition of an Extended IRQ changed between ACPI spec v1.0b
526 	 * and ACPI spec 2.0 (section 6.4.3.6 in both).  This code does not
527 	 * implement the more restrictive definition of 1.0b
528 	 *
529 	 * - Edge/Level are defined opposite in the table vs the headers
530 	 */
531 	if (ACPI_EDGE_SENSITIVE == linked_list->data.extended_irq.edge_level) {
532 		temp8 |= 0x2;
533 	}
534 
535 	/*
536 	 * Set the Interrupt Polarity
537 	 */
538 	temp8 |= ((linked_list->data.extended_irq.active_high_low & 0x1) << 2);
539 
540 	*buffer = temp8;
541 	buffer += 1;
542 
543 	/*
544 	 * Set the Interrupt table length
545 	 */
546 	temp8 = (u8) linked_list->data.extended_irq.number_of_interrupts;
547 
548 	*buffer = temp8;
549 	buffer += 1;
550 
551 	for (index = 0; index < linked_list->data.extended_irq.number_of_interrupts;
552 		 index++) {
553 		ACPI_MOVE_32_TO_32 (buffer,
554 				  &linked_list->data.extended_irq.interrupts[index]);
555 		buffer += 4;
556 	}
557 
558 	/*
559 	 * Resource Source Index and Resource Source are optional
560 	 */
561 	if (0 != linked_list->data.extended_irq.resource_source.string_length) {
562 		*buffer = (u8) linked_list->data.extended_irq.resource_source.index;
563 		buffer += 1;
564 
565 		temp_pointer = (char *) buffer;
566 
567 		/*
568 		 * Copy the string
569 		 */
570 		ACPI_STRCPY (temp_pointer,
571 			linked_list->data.extended_irq.resource_source.string_ptr);
572 
573 		/*
574 		 * Buffer needs to be set to the length of the sting + one for the
575 		 * terminating null
576 		 */
577 		buffer += (acpi_size)(ACPI_STRLEN (linked_list->data.extended_irq.resource_source.string_ptr) + 1);
578 	}
579 
580 	/*
581 	 * Return the number of bytes consumed in this operation
582 	 */
583 	*bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer);
584 
585 	/*
586 	 * Set the length field to the number of bytes consumed
587 	 * minus the header size (3 bytes)
588 	 */
589 	*length_field = (u16) (*bytes_consumed - 3);
590 	return_ACPI_STATUS (AE_OK);
591 }
592 
593