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