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