Home | History | Annotate | Line # | Download | only in ppc
      1 /*  This file is part of the program psim.
      2 
      3     Copyright (C) 1994-1996, Andrew Cagney <cagney (at) highland.com.au>
      4 
      5     This program is free software; you can redistribute it and/or modify
      6     it under the terms of the GNU General Public License as published by
      7     the Free Software Foundation; either version 3 of the License, or
      8     (at your option) any later version.
      9 
     10     This program is distributed in the hope that it will be useful,
     11     but WITHOUT ANY WARRANTY; without even the implied warranty of
     12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13     GNU General Public License for more details.
     14 
     15     You should have received a copy of the GNU General Public License
     16     along with this program; if not, see <http://www.gnu.org/licenses/>.
     17 
     18     */
     19 
     20 
     21 #ifndef _DEVICE_TABLE_C_
     22 #define _DEVICE_TABLE_C_
     23 
     24 #include "device_table.h"
     25 
     26 #include <stdlib.h>
     27 #include <ctype.h>
     28 
     29 
     30 /* Helper functions */
     31 
     32 
     33 /* Go through the devices various reg properties for those that
     34    specify attach addresses */
     35 
     36 
     37 void
     38 generic_device_init_address(device *me)
     39 {
     40   static const char *(reg_property_names[]) = {
     41     "attach-addresses",
     42     "assigned-addresses",
     43     "reg",
     44     "alternate-reg" ,
     45     NULL
     46   };
     47   const char **reg_property_name;
     48   for (reg_property_name = reg_property_names;
     49        *reg_property_name != NULL;
     50        reg_property_name++) {
     51     if (device_find_property(me, *reg_property_name) != NULL) {
     52       reg_property_spec reg;
     53       int reg_entry;
     54       for (reg_entry = 0;
     55 	   device_find_reg_array_property(me, *reg_property_name, reg_entry,
     56 					  &reg);
     57 	   reg_entry++) {
     58 	unsigned_word attach_address;
     59 	int attach_space;
     60 	unsigned attach_size;
     61 	if (!device_address_to_attach_address(device_parent(me),
     62 					      &reg.address,
     63 					      &attach_space, &attach_address,
     64 					      me))
     65 	  continue;
     66 	if (!device_size_to_attach_size(device_parent(me),
     67 					&reg.size,
     68 					&attach_size, me))
     69 	  continue;
     70 	device_attach_address(device_parent(me),
     71 			      attach_callback,
     72 			      attach_space, attach_address, attach_size,
     73 			      access_read_write_exec,
     74 			      me);
     75       }
     76       /* if first option matches don't try for any others */
     77       if (reg_property_name == reg_property_names)
     78 	break;
     79     }
     80   }
     81 }
     82 
     83 int
     84 generic_device_unit_decode(device *bus,
     85 			   const char *unit,
     86 			   device_unit *phys)
     87 {
     88   memset(phys, 0, sizeof(device_unit));
     89   if (unit == NULL)
     90     return 0;
     91   else {
     92     int nr_cells = 0;
     93     const int max_nr_cells = device_nr_address_cells(bus);
     94     while (1) {
     95       char *end = NULL;
     96       unsigned long val;
     97       val = strtoul(unit, &end, 0);
     98       /* parse error? */
     99       if (unit == end)
    100 	return -1;
    101       /* two many cells? */
    102       if (nr_cells >= max_nr_cells)
    103 	return -1;
    104       /* save it */
    105       phys->cells[nr_cells] = val;
    106       nr_cells++;
    107       unit = end;
    108       /* more to follow? */
    109       if (isspace(*unit) || *unit == '\0')
    110 	break;
    111       if (*unit != ',')
    112 	return -1;
    113       unit++;
    114     }
    115     if (nr_cells < max_nr_cells) {
    116       /* shift everything to correct position */
    117       int i;
    118       for (i = 1; i <= nr_cells; i++)
    119 	phys->cells[max_nr_cells - i] = phys->cells[nr_cells - i];
    120       for (i = 0; i < (max_nr_cells - nr_cells); i++)
    121 	phys->cells[i] = 0;
    122     }
    123     phys->nr_cells = max_nr_cells;
    124     return max_nr_cells;
    125   }
    126 }
    127 
    128 int
    129 generic_device_unit_encode(device *bus,
    130 			   const device_unit *phys,
    131 			   char *buf,
    132 			   int sizeof_buf)
    133 {
    134   int i;
    135   int len;
    136   char *pos = buf;
    137   /* skip leading zero's */
    138   for (i = 0; i < phys->nr_cells; i++) {
    139     if (phys->cells[i] != 0)
    140       break;
    141   }
    142   /* don't output anything if empty */
    143   if (phys->nr_cells == 0) {
    144     strcpy(pos, "");
    145     len = 0;
    146   }
    147   else if (i == phys->nr_cells) {
    148     /* all zero */
    149     strcpy(pos, "0");
    150     len = 1;
    151   }
    152   else {
    153     for (; i < phys->nr_cells; i++) {
    154       if (pos != buf) {
    155 	strcat(pos, ",");
    156 	pos = strchr(pos, '\0');
    157       }
    158       if (phys->cells[i] < 10)
    159 	sprintf(pos, "%ld", (unsigned long)phys->cells[i]);
    160       else
    161 	sprintf(pos, "0x%lx", (unsigned long)phys->cells[i]);
    162       pos = strchr(pos, '\0');
    163     }
    164     len = pos - buf;
    165   }
    166   if (len >= sizeof_buf)
    167     error("generic_unit_encode - buffer overflow\n");
    168   return len;
    169 }
    170 
    171 int
    172 generic_device_address_to_attach_address(device *me,
    173 					 const device_unit *address,
    174 					 int *attach_space,
    175 					 unsigned_word *attach_address,
    176 					 device *client)
    177 {
    178   int i;
    179   for (i = 0; i < address->nr_cells - 2; i++) {
    180     if (address->cells[i] != 0)
    181       device_error(me, "Only 32bit addresses supported");
    182   }
    183   if (address->nr_cells >= 2)
    184     *attach_space = address->cells[address->nr_cells - 2];
    185   else
    186     *attach_space = 0;
    187   *attach_address = address->cells[address->nr_cells - 1];
    188   return 1;
    189 }
    190 
    191 int
    192 generic_device_size_to_attach_size(device *me,
    193 				   const device_unit *size,
    194 				   unsigned *nr_bytes,
    195 				   device *client)
    196 {
    197   int i;
    198   for (i = 0; i < size->nr_cells - 1; i++) {
    199     if (size->cells[i] != 0)
    200       device_error(me, "Only 32bit sizes supported");
    201   }
    202   *nr_bytes = size->cells[0];
    203   return *nr_bytes;
    204 }
    205 
    206 
    207 /* ignore/passthrough versions of each function */
    208 
    209 void
    210 passthrough_device_address_attach(device *me,
    211 				  attach_type attach,
    212 				  int space,
    213 				  unsigned_word addr,
    214 				  unsigned nr_bytes,
    215 				  access_type access,
    216 				  device *client) /*callback/default*/
    217 {
    218   device_attach_address(device_parent(me), attach,
    219 			space, addr, nr_bytes,
    220 			access,
    221 			client);
    222 }
    223 
    224 void
    225 passthrough_device_address_detach(device *me,
    226 				  attach_type attach,
    227 				  int space,
    228 				  unsigned_word addr,
    229 				  unsigned nr_bytes,
    230 				  access_type access,
    231 				  device *client) /*callback/default*/
    232 {
    233   device_detach_address(device_parent(me), attach,
    234 			space, addr, nr_bytes, access,
    235 			client);
    236 }
    237 
    238 unsigned
    239 passthrough_device_dma_read_buffer(device *me,
    240 				   void *dest,
    241 				   int space,
    242 				   unsigned_word addr,
    243 				   unsigned nr_bytes)
    244 {
    245   return device_dma_read_buffer(device_parent(me), dest,
    246 				space, addr, nr_bytes);
    247 }
    248 
    249 unsigned
    250 passthrough_device_dma_write_buffer(device *me,
    251 			     const void *source,
    252 			     int space,
    253 			     unsigned_word addr,
    254 			     unsigned nr_bytes,
    255 			     int violate_read_only_section)
    256 {
    257   return device_dma_write_buffer(device_parent(me), source,
    258 				 space, addr,
    259 				 nr_bytes,
    260 				 violate_read_only_section);
    261 }
    262 
    263 int
    264 ignore_device_unit_decode(device *me,
    265 			  const char *unit,
    266 			  device_unit *phys)
    267 {
    268   memset(phys, 0, sizeof(device_unit));
    269   return 0;
    270 }
    271 
    272 
    273 static const device_callbacks passthrough_callbacks = {
    274   { NULL, }, /* init */
    275   { passthrough_device_address_attach,
    276     passthrough_device_address_detach, },
    277   { NULL, }, /* IO */
    278   { passthrough_device_dma_read_buffer, passthrough_device_dma_write_buffer, },
    279   { NULL, }, /* interrupt */
    280   { generic_device_unit_decode,
    281     generic_device_unit_encode, },
    282 };
    283 
    284 
    285 static const device_descriptor ob_device_table[] = {
    286   /* standard OpenBoot devices */
    287   { "aliases", NULL, &passthrough_callbacks },
    288   { "options", NULL, &passthrough_callbacks },
    289   { "chosen", NULL, &passthrough_callbacks },
    290   { "packages", NULL, &passthrough_callbacks },
    291   { "cpus", NULL, &passthrough_callbacks },
    292   { "openprom", NULL, &passthrough_callbacks },
    293   { "init", NULL, &passthrough_callbacks },
    294   { NULL },
    295 };
    296 
    297 const device_descriptor *const device_table[] = {
    298   ob_device_table,
    299 #include "hw.c"
    300   NULL,
    301 };
    302 
    303 
    304 #endif /* _DEVICE_TABLE_C_ */
    305