[ACPI] ACPICA 20050916
[linux-2.6] / drivers / acpi / resources / rsirq.c
1 /*******************************************************************************
2  *
3  * Module Name: rsirq - IRQ resource descriptors
4  *
5  ******************************************************************************/
6
7 /*
8  * Copyright (C) 2000 - 2005, 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 #include <acpi/acpi.h>
45 #include <acpi/acresrc.h>
46
47 #define _COMPONENT          ACPI_RESOURCES
48 ACPI_MODULE_NAME("rsirq")
49
50 /*******************************************************************************
51  *
52  * FUNCTION:    acpi_rs_irq_resource
53  *
54  * PARAMETERS:  byte_stream_buffer      - Pointer to the resource input byte
55  *                                        stream
56  *              bytes_consumed          - Pointer to where the number of bytes
57  *                                        consumed the byte_stream_buffer is
58  *                                        returned
59  *              output_buffer           - Pointer to the return data buffer
60  *              structure_size          - Pointer to where the number of bytes
61  *                                        in the return data struct is returned
62  *
63  * RETURN:      Status
64  *
65  * DESCRIPTION: Take the resource byte stream and fill out the appropriate
66  *              structure pointed to by the output_buffer. Return the
67  *              number of bytes consumed from the byte stream.
68  *
69  ******************************************************************************/
70 acpi_status
71 acpi_rs_irq_resource(u8 * byte_stream_buffer,
72                      acpi_size * bytes_consumed,
73                      u8 ** output_buffer, acpi_size * structure_size)
74 {
75         u8 *buffer = byte_stream_buffer;
76         struct acpi_resource *output_struct = (void *)*output_buffer;
77         u16 temp16 = 0;
78         u8 temp8 = 0;
79         u8 index;
80         u8 i;
81         acpi_size struct_size = ACPI_SIZEOF_RESOURCE(struct acpi_resource_irq);
82
83         ACPI_FUNCTION_TRACE("rs_irq_resource");
84
85         /*
86          * The number of bytes consumed are contained in the descriptor
87          * (Bits:0-1)
88          */
89         temp8 = *buffer;
90         *bytes_consumed = (temp8 & 0x03) + 1;
91         output_struct->type = ACPI_RSTYPE_IRQ;
92
93         /* Point to the 16-bits of Bytes 1 and 2 */
94
95         buffer += 1;
96         ACPI_MOVE_16_TO_16(&temp16, buffer);
97
98         output_struct->data.irq.number_of_interrupts = 0;
99
100         /* Decode the IRQ bits */
101
102         for (i = 0, index = 0; index < 16; index++) {
103                 if ((temp16 >> index) & 0x01) {
104                         output_struct->data.irq.interrupts[i] = index;
105                         i++;
106                 }
107         }
108
109         /* Zero interrupts is valid */
110
111         output_struct->data.irq.number_of_interrupts = i;
112         if (i > 0) {
113                 /* Calculate the structure size based upon the number of interrupts */
114
115                 struct_size += ((acpi_size) i - 1) * 4;
116         }
117
118         /* Point to Byte 3 if it is used */
119
120         if (4 == *bytes_consumed) {
121                 buffer += 2;
122                 temp8 = *buffer;
123
124                 /* Check for HE, LL interrupts */
125
126                 switch (temp8 & 0x09) {
127                 case 0x01:      /* HE */
128                         output_struct->data.irq.edge_level =
129                             ACPI_EDGE_SENSITIVE;
130                         output_struct->data.irq.active_high_low =
131                             ACPI_ACTIVE_HIGH;
132                         break;
133
134                 case 0x08:      /* LL */
135                         output_struct->data.irq.edge_level =
136                             ACPI_LEVEL_SENSITIVE;
137                         output_struct->data.irq.active_high_low =
138                             ACPI_ACTIVE_LOW;
139                         break;
140
141                 default:
142                         /*
143                          * Only _LL and _HE polarity/trigger interrupts
144                          * are allowed (ACPI spec, section "IRQ Format")
145                          * so 0x00 and 0x09 are illegal.
146                          */
147                         ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
148                                           "Invalid interrupt polarity/trigger in resource list, %X\n",
149                                           temp8));
150                         return_ACPI_STATUS(AE_BAD_DATA);
151                 }
152
153                 /* Check for sharable */
154
155                 output_struct->data.irq.shared_exclusive = (temp8 >> 3) & 0x01;
156         } else {
157                 /*
158                  * Assume Edge Sensitive, Active High, Non-Sharable
159                  * per ACPI Specification
160                  */
161                 output_struct->data.irq.edge_level = ACPI_EDGE_SENSITIVE;
162                 output_struct->data.irq.active_high_low = ACPI_ACTIVE_HIGH;
163                 output_struct->data.irq.shared_exclusive = ACPI_EXCLUSIVE;
164         }
165
166         /* Set the Length parameter */
167
168         output_struct->length = (u32) struct_size;
169
170         /* Return the final size of the structure */
171
172         *structure_size = struct_size;
173         return_ACPI_STATUS(AE_OK);
174 }
175
176 /*******************************************************************************
177  *
178  * FUNCTION:    acpi_rs_irq_stream
179  *
180  * PARAMETERS:  Resource                - Pointer to the resource linked list
181  *              output_buffer           - Pointer to the user's return buffer
182  *              bytes_consumed          - Pointer to where the number of bytes
183  *                                        used in the output_buffer is returned
184  *
185  * RETURN:      Status
186  *
187  * DESCRIPTION: Take the linked list resource structure and fills in the
188  *              the appropriate bytes in a byte stream
189  *
190  ******************************************************************************/
191
192 acpi_status
193 acpi_rs_irq_stream(struct acpi_resource *resource,
194                    u8 ** output_buffer, acpi_size * bytes_consumed)
195 {
196         u8 *buffer = *output_buffer;
197         u16 temp16 = 0;
198         u8 temp8 = 0;
199         u8 index;
200         u8 IRqinfo_byte_needed;
201
202         ACPI_FUNCTION_TRACE("rs_irq_stream");
203
204         /*
205          * The descriptor field is set based upon whether a third byte is
206          * needed to contain the IRQ Information.
207          */
208         if (ACPI_EDGE_SENSITIVE == resource->data.irq.edge_level &&
209             ACPI_ACTIVE_HIGH == resource->data.irq.active_high_low &&
210             ACPI_EXCLUSIVE == resource->data.irq.shared_exclusive) {
211                 *buffer = ACPI_RDESC_TYPE_IRQ_FORMAT | 0x02;
212                 IRqinfo_byte_needed = FALSE;
213         } else {
214                 *buffer = ACPI_RDESC_TYPE_IRQ_FORMAT | 0x03;
215                 IRqinfo_byte_needed = TRUE;
216         }
217
218         buffer += 1;
219         temp16 = 0;
220
221         /* Loop through all of the interrupts and set the mask bits */
222
223         for (index = 0;
224              index < resource->data.irq.number_of_interrupts; index++) {
225                 temp8 = (u8) resource->data.irq.interrupts[index];
226                 temp16 |= 0x1 << temp8;
227         }
228
229         ACPI_MOVE_16_TO_16(buffer, &temp16);
230         buffer += 2;
231
232         /* Set the IRQ Info byte if needed. */
233
234         if (IRqinfo_byte_needed) {
235                 temp8 = 0;
236                 temp8 = (u8) ((resource->data.irq.shared_exclusive &
237                                0x01) << 4);
238
239                 if (ACPI_LEVEL_SENSITIVE == resource->data.irq.edge_level &&
240                     ACPI_ACTIVE_LOW == resource->data.irq.active_high_low) {
241                         temp8 |= 0x08;
242                 } else {
243                         temp8 |= 0x01;
244                 }
245
246                 *buffer = temp8;
247                 buffer += 1;
248         }
249
250         /* Return the number of bytes consumed in this operation */
251
252         *bytes_consumed = ACPI_PTR_DIFF(buffer, *output_buffer);
253         return_ACPI_STATUS(AE_OK);
254 }
255
256 /*******************************************************************************
257  *
258  * FUNCTION:    acpi_rs_extended_irq_resource
259  *
260  * PARAMETERS:  byte_stream_buffer      - Pointer to the resource input byte
261  *                                        stream
262  *              bytes_consumed          - Pointer to where the number of bytes
263  *                                        consumed the byte_stream_buffer is
264  *                                        returned
265  *              output_buffer           - Pointer to the return data buffer
266  *              structure_size          - Pointer to where the number of bytes
267  *                                        in the return data struct is returned
268  *
269  * RETURN:      Status
270  *
271  * DESCRIPTION: Take the resource byte stream and fill out the appropriate
272  *              structure pointed to by the output_buffer. Return the
273  *              number of bytes consumed from the byte stream.
274  *
275  ******************************************************************************/
276
277 acpi_status
278 acpi_rs_extended_irq_resource(u8 * byte_stream_buffer,
279                               acpi_size * bytes_consumed,
280                               u8 ** output_buffer, acpi_size * structure_size)
281 {
282         u8 *buffer = byte_stream_buffer;
283         struct acpi_resource *output_struct = (void *)*output_buffer;
284         u16 temp16 = 0;
285         u8 temp8 = 0;
286         u8 *temp_ptr;
287         u8 index;
288         acpi_size struct_size =
289             ACPI_SIZEOF_RESOURCE(struct acpi_resource_ext_irq);
290
291         ACPI_FUNCTION_TRACE("rs_extended_irq_resource");
292
293         /* Get the Descriptor Length field */
294
295         buffer += 1;
296         ACPI_MOVE_16_TO_16(&temp16, buffer);
297
298         /* Validate minimum descriptor length */
299
300         if (temp16 < 6) {
301                 return_ACPI_STATUS(AE_AML_BAD_RESOURCE_LENGTH);
302         }
303
304         *bytes_consumed = temp16 + 3;
305         output_struct->type = ACPI_RSTYPE_EXT_IRQ;
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 Interrupt Mode
316          *
317          * The definition of an Extended IRQ changed between ACPI spec v1.0b
318          * and ACPI spec 2.0 (section 6.4.3.6 in both).
319          *
320          * - Edge/Level are defined opposite in the table vs the headers
321          */
322         output_struct->data.extended_irq.edge_level =
323             (temp8 & 0x2) ? ACPI_EDGE_SENSITIVE : ACPI_LEVEL_SENSITIVE;
324
325         /* Check Interrupt Polarity */
326
327         output_struct->data.extended_irq.active_high_low = (temp8 >> 2) & 0x1;
328
329         /* Check for sharable */
330
331         output_struct->data.extended_irq.shared_exclusive = (temp8 >> 3) & 0x01;
332
333         /* Point to Byte4 (IRQ Table length) */
334
335         buffer += 1;
336         temp8 = *buffer;
337
338         /* Must have at least one IRQ */
339
340         if (temp8 < 1) {
341                 return_ACPI_STATUS(AE_AML_BAD_RESOURCE_LENGTH);
342         }
343
344         output_struct->data.extended_irq.number_of_interrupts = temp8;
345
346         /*
347          * Add any additional structure size to properly calculate
348          * the next pointer at the end of this function
349          */
350         struct_size += (temp8 - 1) * 4;
351
352         /* Point to Byte5 (First IRQ Number) */
353
354         buffer += 1;
355
356         /* Cycle through every IRQ in the table */
357
358         for (index = 0; index < temp8; index++) {
359                 ACPI_MOVE_32_TO_32(&output_struct->data.extended_irq.
360                                    interrupts[index], buffer);
361
362                 /* Point to the next IRQ */
363
364                 buffer += 4;
365         }
366
367         /*
368          * This will leave us pointing to the Resource Source Index
369          * If it is present, then save it off and calculate the
370          * pointer to where the null terminated string goes:
371          * Each Interrupt takes 32-bits + the 5 bytes of the
372          * stream that are default.
373          *
374          * Note: Some resource descriptors will have an additional null, so
375          * we add 1 to the length.
376          */
377         if (*bytes_consumed >
378             ((acpi_size) output_struct->data.extended_irq.number_of_interrupts *
379              4) + (5 + 1)) {
380                 /* Dereference the Index */
381
382                 temp8 = *buffer;
383                 output_struct->data.extended_irq.resource_source.index =
384                     (u32) temp8;
385
386                 /* Point to the String */
387
388                 buffer += 1;
389
390                 /* Point the String pointer to the end of this structure. */
391
392                 output_struct->data.extended_irq.resource_source.string_ptr =
393                     (char *)((char *)output_struct + struct_size);
394
395                 temp_ptr = (u8 *)
396                     output_struct->data.extended_irq.resource_source.string_ptr;
397
398                 /* Copy the string into the buffer */
399
400                 index = 0;
401                 while (*buffer) {
402                         *temp_ptr = *buffer;
403
404                         temp_ptr += 1;
405                         buffer += 1;
406                         index += 1;
407                 }
408
409                 /* Add the terminating null */
410
411                 *temp_ptr = 0;
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 boundary,
417                  * calculate the length of the string and expand the
418                  * struct_size to the next 32-bit boundary.
419                  */
420                 temp8 = (u8) (index + 1);
421                 struct_size += ACPI_ROUND_UP_to_32_bITS(temp8);
422         } else {
423                 output_struct->data.extended_irq.resource_source.index = 0;
424                 output_struct->data.extended_irq.resource_source.string_length =
425                     0;
426                 output_struct->data.extended_irq.resource_source.string_ptr =
427                     NULL;
428         }
429
430         /* Set the Length parameter */
431
432         output_struct->length = (u32) struct_size;
433
434         /* Return the final size of the structure */
435
436         *structure_size = struct_size;
437         return_ACPI_STATUS(AE_OK);
438 }
439
440 /*******************************************************************************
441  *
442  * FUNCTION:    acpi_rs_extended_irq_stream
443  *
444  * PARAMETERS:  Resource                - Pointer to the resource linked list
445  *              output_buffer           - Pointer to the user's return buffer
446  *              bytes_consumed          - Pointer to where the number of bytes
447  *                                        used in the output_buffer is returned
448  *
449  * RETURN:      Status
450  *
451  * DESCRIPTION: Take the linked list resource structure and fills in the
452  *              the appropriate bytes in a byte stream
453  *
454  ******************************************************************************/
455
456 acpi_status
457 acpi_rs_extended_irq_stream(struct acpi_resource *resource,
458                             u8 ** output_buffer, acpi_size * bytes_consumed)
459 {
460         u8 *buffer = *output_buffer;
461         u16 *length_field;
462         u8 temp8 = 0;
463         u8 index;
464
465         ACPI_FUNCTION_TRACE("rs_extended_irq_stream");
466
467         /* Set the Descriptor Type field */
468
469         *buffer = ACPI_RDESC_TYPE_EXTENDED_XRUPT;
470         buffer += 1;
471
472         /* Save a pointer to the Length field - to be filled in later */
473
474         length_field = ACPI_CAST_PTR(u16, buffer);
475         buffer += 2;
476
477         /* Set the Interrupt vector flags */
478
479         temp8 = (u8) (resource->data.extended_irq.producer_consumer & 0x01);
480         temp8 |= ((resource->data.extended_irq.shared_exclusive & 0x01) << 3);
481
482         /*
483          * Set the Interrupt Mode
484          *
485          * The definition of an Extended IRQ changed between ACPI spec v1.0b
486          * and ACPI spec 2.0 (section 6.4.3.6 in both).  This code does not
487          * implement the more restrictive definition of 1.0b
488          *
489          * - Edge/Level are defined opposite in the table vs the headers
490          */
491         if (ACPI_EDGE_SENSITIVE == resource->data.extended_irq.edge_level) {
492                 temp8 |= 0x2;
493         }
494
495         /* Set the Interrupt Polarity */
496
497         temp8 |= ((resource->data.extended_irq.active_high_low & 0x1) << 2);
498
499         *buffer = temp8;
500         buffer += 1;
501
502         /* Set the Interrupt table length */
503
504         temp8 = (u8) resource->data.extended_irq.number_of_interrupts;
505
506         *buffer = temp8;
507         buffer += 1;
508
509         for (index = 0;
510              index < resource->data.extended_irq.number_of_interrupts;
511              index++) {
512                 ACPI_MOVE_32_TO_32(buffer,
513                                    &resource->data.extended_irq.
514                                    interrupts[index]);
515                 buffer += 4;
516         }
517
518         /* Resource Source Index and Resource Source are optional */
519
520         if (0 != resource->data.extended_irq.resource_source.string_length) {
521                 *buffer =
522                     (u8) resource->data.extended_irq.resource_source.index;
523                 buffer += 1;
524
525                 /* Copy the string */
526
527                 ACPI_STRCPY((char *)buffer,
528                             resource->data.extended_irq.resource_source.
529                             string_ptr);
530
531                 /*
532                  * Buffer needs to be set to the length of the string + one for the
533                  * terminating null
534                  */
535                 buffer +=
536                     (acpi_size) (ACPI_STRLEN
537                                  (resource->data.extended_irq.resource_source.
538                                   string_ptr) + 1);
539         }
540
541         /* Return the number of bytes consumed in this operation */
542
543         *bytes_consumed = ACPI_PTR_DIFF(buffer, *output_buffer);
544
545         /*
546          * Set the length field to the number of bytes consumed
547          * minus the header size (3 bytes)
548          */
549         *length_field = (u16) (*bytes_consumed - 3);
550         return_ACPI_STATUS(AE_OK);
551 }