- Send the SCM reply packet with the final status after completing the requested...
[reactos.git] / reactos / drivers / bus / acpi / resource / rsirq.c
1 /*******************************************************************************
2 *
3 * Module Name: rsirq - Acpi_rs_irq_resource,
4 * Acpi_rs_irq_stream
5 * Acpi_rs_extended_irq_resource
6 * Acpi_rs_extended_irq_stream
7 * $Revision: 1.1 $
8 *
9 ******************************************************************************/
10
11 /*
12 * Copyright (C) 2000, 2001 R. Byron Moore
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 */
28
29
30 #include <acpi.h>
31
32 #define _COMPONENT ACPI_RESOURCES
33 MODULE_NAME ("rsirq")
34
35
36 /*******************************************************************************
37 *
38 * FUNCTION: Acpi_rs_irq_resource
39 *
40 * PARAMETERS: Byte_stream_buffer - Pointer to the resource input byte
41 * stream
42 * Bytes_consumed - u32 pointer that is filled with
43 * the number of bytes consumed from
44 * the Byte_stream_buffer
45 * Output_buffer - Pointer to the user's return buffer
46 * Structure_size - u32 pointer that is filled with
47 * the number of bytes in the filled
48 * in structure
49 *
50 * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code
51 *
52 * DESCRIPTION: Take the resource byte stream and fill out the appropriate
53 * structure pointed to by the Output_buffer. Return the
54 * number of bytes consumed from the byte stream.
55 *
56 ******************************************************************************/
57
58 ACPI_STATUS
59 acpi_rs_irq_resource (
60 u8 *byte_stream_buffer,
61 u32 *bytes_consumed,
62 u8 **output_buffer,
63 u32 *structure_size)
64 {
65 u8 *buffer = byte_stream_buffer;
66 RESOURCE *output_struct = (RESOURCE *) * output_buffer;
67 u16 temp16 = 0;
68 u8 temp8 = 0;
69 u8 index;
70 u8 i;
71 u32 struct_size = sizeof (IRQ_RESOURCE) +
72 RESOURCE_LENGTH_NO_DATA;
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 = 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 (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
163 return (AE_OK);
164 }
165
166
167 /*******************************************************************************
168 *
169 * FUNCTION: Acpi_rs_irq_stream
170 *
171 * PARAMETERS: Linked_list - Pointer to the resource linked list
172 * Output_buffer - Pointer to the user's return buffer
173 * Bytes_consumed - u32 pointer that is filled with
174 * the number of bytes of the
175 * Output_buffer used
176 *
177 * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code
178 *
179 * DESCRIPTION: Take the linked list resource structure and fills in the
180 * the appropriate bytes in a byte stream
181 *
182 ******************************************************************************/
183
184 ACPI_STATUS
185 acpi_rs_irq_stream (
186 RESOURCE *linked_list,
187 u8 **output_buffer,
188 u32 *bytes_consumed)
189 {
190 u8 *buffer = *output_buffer;
191 u16 temp16 = 0;
192 u8 temp8 = 0;
193 u8 index;
194 u8 IRQinfo_byte_needed;
195
196
197 /*
198 * The descriptor field is set based upon whether a third byte is
199 * needed to contain the IRQ Information.
200 */
201 if (EDGE_SENSITIVE == linked_list->data.irq.edge_level &&
202 ACTIVE_HIGH == linked_list->data.irq.active_high_low &&
203 EXCLUSIVE == linked_list->data.irq.shared_exclusive) {
204 *buffer = 0x22;
205 IRQinfo_byte_needed = FALSE;
206 }
207 else {
208 *buffer = 0x23;
209 IRQinfo_byte_needed = TRUE;
210 }
211
212 buffer += 1;
213 temp16 = 0;
214
215 /*
216 * Loop through all of the interrupts and set the mask bits
217 */
218 for(index = 0;
219 index < linked_list->data.irq.number_of_interrupts;
220 index++) {
221 temp8 = (u8) linked_list->data.irq.interrupts[index];
222 temp16 |= 0x1 << temp8;
223 }
224
225 MOVE_UNALIGNED16_TO_16 (buffer, &temp16);
226 buffer += 2;
227
228 /*
229 * Set the IRQ Info byte if needed.
230 */
231 if (IRQinfo_byte_needed) {
232 temp8 = 0;
233 temp8 = (u8) ((linked_list->data.irq.shared_exclusive &
234 0x01) << 4);
235
236 if (LEVEL_SENSITIVE == linked_list->data.irq.edge_level &&
237 ACTIVE_LOW == linked_list->data.irq.active_high_low) {
238 temp8 |= 0x08;
239 }
240
241 else {
242 temp8 |= 0x01;
243 }
244
245 *buffer = temp8;
246 buffer += 1;
247 }
248
249 /*
250 * Return the number of bytes consumed in this operation
251 */
252 *bytes_consumed = (u32) ((NATIVE_UINT) buffer -
253 (NATIVE_UINT) *output_buffer);
254
255 return (AE_OK);
256 }
257
258
259 /*******************************************************************************
260 *
261 * FUNCTION: Acpi_rs_extended_irq_resource
262 *
263 * PARAMETERS: Byte_stream_buffer - Pointer to the resource input byte
264 * stream
265 * Bytes_consumed - u32 pointer that is filled with
266 * the number of bytes consumed from
267 * the Byte_stream_buffer
268 * Output_buffer - Pointer to the user's return buffer
269 * Structure_size - u32 pointer that is filled with
270 * the number of bytes in the filled
271 * in structure
272 *
273 * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code
274 *
275 * DESCRIPTION: Take the resource byte stream and fill out the appropriate
276 * structure pointed to by the Output_buffer. Return the
277 * number of bytes consumed from the byte stream.
278 *
279 ******************************************************************************/
280
281 ACPI_STATUS
282 acpi_rs_extended_irq_resource (
283 u8 *byte_stream_buffer,
284 u32 *bytes_consumed,
285 u8 **output_buffer,
286 u32 *structure_size)
287 {
288 u8 *buffer = byte_stream_buffer;
289 RESOURCE *output_struct = (RESOURCE *) * output_buffer;
290 u16 temp16 = 0;
291 u8 temp8 = 0;
292 u8 index;
293 u32 struct_size = sizeof (EXTENDED_IRQ_RESOURCE) +
294 RESOURCE_LENGTH_NO_DATA;
295
296
297 /*
298 * Point past the Descriptor to get the number of bytes consumed
299 */
300 buffer += 1;
301 MOVE_UNALIGNED16_TO_16 (&temp16, buffer);
302
303 *bytes_consumed = temp16 + 3;
304 output_struct->id = extended_irq;
305
306 /*
307 * Point to the Byte3
308 */
309 buffer += 2;
310 temp8 = *buffer;
311
312 output_struct->data.extended_irq.producer_consumer = temp8 & 0x01;
313
314 /*
315 * Check for HE, LL or HL
316 */
317 if(temp8 & 0x02) {
318 output_struct->data.extended_irq.edge_level = EDGE_SENSITIVE;
319 output_struct->data.extended_irq.active_high_low = ACTIVE_HIGH;
320 }
321
322 else {
323 if(temp8 & 0x4) {
324 output_struct->data.extended_irq.edge_level = LEVEL_SENSITIVE;
325 output_struct->data.extended_irq.active_high_low = ACTIVE_LOW;
326 }
327
328 else {
329 /*
330 * Only _LL and _HE polarity/trigger interrupts
331 * are allowed (ACPI spec v1.0b ection 6.4.2.1),
332 * so an error will occur if we reach this point
333 */
334 return (AE_BAD_DATA);
335 }
336 }
337
338 /*
339 * Check for sharable
340 */
341 output_struct->data.extended_irq.shared_exclusive =
342 (temp8 >> 3) & 0x01;
343
344 /*
345 * Point to Byte4 (IRQ Table length)
346 */
347 buffer += 1;
348 temp8 = *buffer;
349
350 output_struct->data.extended_irq.number_of_interrupts = temp8;
351
352 /*
353 * Add any additional structure size to properly calculate
354 * the next pointer at the end of this function
355 */
356 struct_size += (temp8 - 1) * 4;
357
358 /*
359 * Point to Byte5 (First IRQ Number)
360 */
361 buffer += 1;
362
363 /*
364 * Cycle through every IRQ in the table
365 */
366 for (index = 0; index < temp8; index++) {
367 output_struct->data.extended_irq.interrupts[index] =
368 (u32)*buffer;
369
370 /* Point to the next IRQ */
371
372 buffer += 4;
373 }
374
375 /*
376 * This will leave us pointing to the Resource Source Index
377 * If it is present, then save it off and calculate the
378 * pointer to where the null terminated string goes:
379 * Each Interrupt takes 32-bits + the 5 bytes of the
380 * stream that are default.
381 */
382 if (*bytes_consumed >
383 (u32)(output_struct->data.extended_irq.number_of_interrupts *
384 4) + 5) {
385 /* Dereference the Index */
386
387 temp8 = *buffer;
388 output_struct->data.extended_irq.resource_source_index =
389 (u32)temp8;
390
391 /* Point to the String */
392
393 buffer += 1;
394
395 /* Copy the string into the buffer */
396
397 index = 0;
398
399 while (0x00 != *buffer) {
400 output_struct->data.extended_irq.resource_source[index] =
401 *buffer;
402
403 buffer += 1;
404 index += 1;
405 }
406
407 /*
408 * Add the terminating null
409 */
410 output_struct->data.extended_irq.resource_source[index] = 0x00;
411 output_struct->data.extended_irq.resource_source_string_length =
412 index + 1;
413
414 /*
415 * In order for the Struct_size to fall on a 32-bit boundry,
416 * calculate the length of the string and expand the
417 * Struct_size to the next 32-bit boundry.
418 */
419 temp8 = (u8) (index + 1);
420 temp8 = (u8) ROUND_UP_TO_32_bITS (temp8);
421 }
422
423 else {
424 output_struct->data.extended_irq.resource_source_index = 0x00;
425 output_struct->data.extended_irq.resource_source_string_length = 0;
426 output_struct->data.extended_irq.resource_source[0] = 0x00;
427 }
428
429 /*
430 * Set the Length parameter
431 */
432 output_struct->length = struct_size;
433
434 /*
435 * Return the final size of the structure
436 */
437 *structure_size = struct_size;
438
439 return (AE_OK);
440 }
441
442
443 /*******************************************************************************
444 *
445 * FUNCTION: Acpi_rs_extended_irq_stream
446 *
447 * PARAMETERS: Linked_list - Pointer to the resource linked list
448 * Output_buffer - Pointer to the user's return buffer
449 * Bytes_consumed - u32 pointer that is filled with
450 * the number of bytes of the
451 * Output_buffer used
452 *
453 * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code
454 *
455 * DESCRIPTION: Take the linked list resource structure and fills in the
456 * the appropriate bytes in a byte stream
457 *
458 ******************************************************************************/
459
460 ACPI_STATUS
461 acpi_rs_extended_irq_stream (
462 RESOURCE *linked_list,
463 u8 **output_buffer,
464 u32 *bytes_consumed)
465 {
466 u8 *buffer = *output_buffer;
467 u16 *length_field;
468 u8 temp8 = 0;
469 u8 index;
470 NATIVE_CHAR *temp_pointer = NULL;
471
472
473 /*
474 * The descriptor field is static
475 */
476 *buffer = 0x89;
477 buffer += 1;
478
479 /*
480 * Set a pointer to the Length field - to be filled in later
481 */
482
483 length_field = (u16 *)buffer;
484 buffer += 2;
485
486 /*
487 * Set the Interrupt vector flags
488 */
489 temp8 = (u8)(linked_list->data.extended_irq.producer_consumer & 0x01);
490
491 temp8 |= ((linked_list->data.extended_irq.shared_exclusive & 0x01) << 3);
492
493 if (LEVEL_SENSITIVE == linked_list->data.extended_irq.edge_level &&
494 ACTIVE_LOW == linked_list->data.extended_irq.active_high_low) {
495 temp8 |= 0x04;
496 }
497 else {
498 temp8 |= 0x02;
499 }
500
501 *buffer = temp8;
502 buffer += 1;
503
504 /*
505 * Set the Interrupt table length
506 */
507 temp8 = (u8) linked_list->data.extended_irq.number_of_interrupts;
508
509 *buffer = temp8;
510 buffer += 1;
511
512 for (index = 0;
513 index < linked_list->data.extended_irq.number_of_interrupts;
514 index++) {
515 MOVE_UNALIGNED32_TO_32 (buffer,
516 &linked_list->data.extended_irq.interrupts[index]);
517 buffer += 4;
518 }
519
520 /*
521 * Resource Source Index and Resource Source are optional
522 */
523 if (0 != linked_list->data.extended_irq.resource_source_string_length) {
524 *buffer = (u8) linked_list->data.extended_irq.resource_source_index;
525 buffer += 1;
526
527 temp_pointer = (NATIVE_CHAR *) buffer;
528
529 /*
530 * Copy the string
531 */
532 STRCPY (temp_pointer, linked_list->data.extended_irq.resource_source);
533
534 /*
535 * Buffer needs to be set to the length of the sting + one for the
536 * terminating null
537 */
538 buffer += (STRLEN (linked_list->data.extended_irq.resource_source) + 1);
539 }
540
541 /*
542 * Return the number of bytes consumed in this operation
543 */
544 *bytes_consumed = (u32) ((NATIVE_UINT) buffer -
545 (NATIVE_UINT) *output_buffer);
546
547 /*
548 * Set the length field to the number of bytes consumed
549 * minus the header size (3 bytes)
550 */
551 *length_field = (u16) (*bytes_consumed - 3);
552
553 return (AE_OK);
554 }
555