]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/io/pcmcia/v2_0/src/pcmcia.c
Initial revision
[karo-tx-redboot.git] / packages / io / pcmcia / v2_0 / src / pcmcia.c
1 //==========================================================================
2 //
3 //      io/pcmcia/pcmcia.c
4 //
5 //      PCMCIA support (Card Services)
6 //
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12 //
13 // eCos is free software; you can redistribute it and/or modify it under
14 // the terms of the GNU General Public License as published by the Free
15 // Software Foundation; either version 2 or (at your option) any later version.
16 //
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
20 // for more details.
21 //
22 // You should have received a copy of the GNU General Public License along
23 // with eCos; if not, write to the Free Software Foundation, Inc.,
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25 //
26 // As a special exception, if other files instantiate templates or use macros
27 // or inline functions from this file, or you compile this file and link it
28 // with other works to produce a work based on this file, this file does not
29 // by itself cause the resulting work to be covered by the GNU General Public
30 // License. However the source code for this file must still be made available
31 // in accordance with section (3) of the GNU General Public License.
32 //
33 // This exception does not invalidate any other reasons why a work based on
34 // this file might be covered by the GNU General Public License.
35 //
36 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37 // at http://sources.redhat.com/ecos/ecos-license/
38 // -------------------------------------------
39 //####ECOSGPLCOPYRIGHTEND####
40 //==========================================================================
41 //#####DESCRIPTIONBEGIN####
42 //
43 // Author(s):    gthomas
44 // Contributors: gthomas
45 // Date:         2000-07-06
46 // Purpose:      PCMCIA support
47 // Description: 
48 //
49 //####DESCRIPTIONEND####
50 //
51 //==========================================================================
52
53 #include <pkgconf/io_pcmcia.h>
54
55 #include <cyg/io/pcmcia.h>
56 #include <cyg/infra/diag.h>
57
58 #if CYGHWR_IO_PCMCIA_DEVICE == 0
59 #error Need hardware package for PCMCIA support
60 #endif
61
62 #define CF_NUM_SLOTS CYGHWR_IO_PCMCIA_DEVICE
63 static struct cf_slot cf_slots[CF_NUM_SLOTS];
64
65 // Implementation routines
66 void cf_hwr_init(struct cf_slot *slot);
67 void cf_hwr_change_state(struct cf_slot *slot, int desired_state);
68 void cf_hwr_clear_interrupt(struct cf_slot *slot);
69
70 bool
71 cf_get_CIS(struct cf_slot *slot, unsigned char id, 
72            unsigned char *buf, int *len, int *ptr)
73 {
74     int i, size;
75     unsigned char *cis = slot->attr;
76     unsigned char *cis_end = cis + slot->attr_length;
77     cis += *ptr;
78     while (cis < cis_end) {
79         if (*cis == 0xFF) {
80             break;
81         }
82         if (*cis == id) {
83             size = *(cis+2) + 2;
84             for (i = 0;  i < size;  i++) {
85                 *buf++ = *cis;
86                 cis += 2;
87             }
88             *len = size;
89             *ptr = (unsigned long)(cis - slot->attr);
90             return true;
91         } else {
92             // Skip to next entry
93             cis += (*(cis+2) * 2) + 4;
94         }
95     }
96     return false;
97 }
98
99 void
100 cf_set_COR(struct cf_slot *slot, unsigned long cor, unsigned char val)
101 {
102     volatile unsigned char *cfg = slot->attr;
103     cfg[cor] = val;
104 }
105
106 static void
107 cf_parse_power_structure(unsigned char **buf)
108 {
109     unsigned char *bp = *buf;
110     unsigned char tpce_pd = *bp++;
111     unsigned char settings;
112     int indx;
113     for (indx = 6;  indx >= 0;  indx--) {
114         if (tpce_pd & (1<<indx)) {
115             settings = *bp++;  // main value
116             if (settings & 0x80) {
117                 bp++;  // extension byte - FIXME
118             }
119         }
120     }
121     *buf = bp;
122 }
123
124 static void
125 cf_parse_timing_structure(unsigned char **buf)
126 {
127     unsigned char *bp = *buf;
128     unsigned char tpce_td = *bp++;
129     if ((tpce_td & 0x1C) != 0x1C) {
130 //        diag_printf("READY = %x.%x\n",(tpce_td & 0x1C)>>2, *bp); 
131         bp++;
132     }
133     if ((tpce_td & 0x03) != 0x03) {
134 //        diag_printf("WAIT = %x.%x\n",(tpce_td & 0x03)>>0, *bp); 
135         bp++;
136     }
137     *buf = bp;
138 }
139
140 static void
141 cf_parse_IO_space_structure(unsigned char **buf, struct cf_io_space *io_space)
142 {
143     unsigned char *bp = *buf;
144     unsigned char tpce_io = *bp++;
145     unsigned char rd;
146     unsigned long base = 0, length = 0;
147     int i;
148     io_space->mode = (tpce_io & 0x60) >> 5;
149     if (tpce_io & 0x80) {
150         rd = *bp++;
151         io_space->num_addrs = (rd & 0x0F) + 1;
152         for (i = 0;  i < io_space->num_addrs;  i++) {
153             // Address
154             switch ((rd & 0x30) >> 4) {
155             case 0:
156                 break;  // Not present (shouldn't happen)
157             case 1:
158                 base = *bp++;
159                 break;
160             case 2:
161                 base = (bp[1] << 8) | bp[0];
162                 bp += 2;
163                 break;
164             case 3:                
165                 base = (bp[3] << 24) | (bp[2] << 16) | (bp[1] << 8) | bp[0];
166                 bp += 4;
167                 break;
168             }
169             io_space->base[i] = base;
170             // Length
171             switch ((rd & 0xC0) >> 6) {
172             case 0:
173                 break;  // Not present (shouldn't happen)
174             case 1:
175                 length = *bp++;
176                 break;
177             case 2:
178                 length = (bp[1] << 8) | bp[0];
179                 bp += 2;
180                 break;
181             case 3:                
182                 length = (bp[3] << 24) | (bp[2] << 16) | (bp[1] << 8) | bp[0];
183                 bp += 4;
184                 break;
185             }
186             length++;
187             io_space->size[i] = length;
188 //            diag_printf("IO addr %d - base: %x, length: %x\n", i, base, length);
189         }
190     }
191     *buf = bp;
192 }
193
194 bool
195 cf_parse_cftable(unsigned char *buf, int len, struct cf_cftable *cftable)
196 {
197     unsigned char tpce_indx, tpce_fs;
198     if (*buf++ != CF_CISTPL_CFTABLE_ENTRY) {
199         diag_printf("%s - called with invalid CIS: %x\n", __FUNCTION__, *--buf);
200         return false;
201     }
202     buf++;  // Skip length/link
203     tpce_indx = *buf++;
204     cftable->cor = tpce_indx & 0x3F;
205     if (tpce_indx & 0x80) {
206         cftable->interface = *buf++;
207     }
208     cftable->feature_select = tpce_fs = *buf++;
209     if (tpce_fs & 0x01) {
210         cf_parse_power_structure(&buf);
211     }
212     if (tpce_fs & 0x02) {
213         cf_parse_power_structure(&buf);
214     }
215     if (tpce_fs & 0x04) {
216         cf_parse_timing_structure(&buf);
217     }
218     if (tpce_fs & 0x08) {
219         cf_parse_IO_space_structure(&buf, &cftable->io_space);
220     }
221     return true;
222 }
223
224 bool
225 cf_parse_config(unsigned char *buf, int len, struct cf_config *config)
226 {
227     unsigned char tpcc_sz;
228     int i;
229     if (*buf++ != CF_CISTPL_CONFIG) {
230         diag_printf("%s - called with invalid CIS: %x\n", __FUNCTION__, *--buf);
231         return false;
232     }
233     buf++;  // Skip length/link
234     tpcc_sz = *buf++;
235     buf++;  // Skip 'last' pointer
236     config->base = 0;
237     for (i = (tpcc_sz & 0x03);  i >= 0;  i--) {
238         config->base = (config->base << 8) | buf[i];
239     }
240     buf += (tpcc_sz & 0x03) + 1;
241     config->mask_length = ((tpcc_sz & 0x3C) >> 2) + 1;
242     for (i = 0;  i < config->mask_length;  i++) {
243         config->mask[i] = *buf++;
244     }
245     return true;
246 }
247
248 //
249 // Return a pointer to the slot descriptor for a given slot
250 //
251 struct cf_slot *
252 cf_get_slot(int indx)
253 {
254     if ((indx >= 0) && (indx < CF_NUM_SLOTS)) {
255         return &cf_slots[indx];
256     } else {
257         diag_printf("PCMCIA: Invalid slot %d\n", indx);
258         return (struct cf_slot *)0;
259     }
260 }
261
262 //
263 // Initialize all PCMCIA (Compact Flash) slots
264 //
265 void
266 cf_init(void)
267 {
268     int i;
269     for (i = 0;  i < CF_NUM_SLOTS; i++) {
270         cf_slots[i].index = i;
271         cf_hwr_init(&cf_slots[i]);
272     }
273 }
274
275 //
276 // Transition a card/slot
277 //
278 void
279 cf_change_state(struct cf_slot *slot, int desired_state)
280 {
281     cf_hwr_change_state(slot, desired_state);
282 }
283
284 //
285 // Register an interrupt handler
286 //
287 void 
288 cf_register_handler(struct cf_slot *slot, 
289                     void (*handler)(int, int, void *), 
290                     void *param)
291 {
292     slot->irq_handler.handler = handler;
293     slot->irq_handler.param = param;
294 }
295
296 //
297 // Allow interrupt function to acknowledge interrupt
298 //
299 void
300 cf_clear_interrupt(struct cf_slot *slot)
301 {
302     cf_hwr_clear_interrupt(slot);
303 }
304