1/*  This file is part of the program psim.
2
3    Copyright (C) 1994-1996, Andrew Cagney <cagney@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 _HW_EEPROM_C_
22#define _HW_EEPROM_C_
23
24#include "device_table.h"
25
26#ifdef HAVE_STRING_H
27#include <string.h>
28#else
29#ifdef HAVE_STRINGS_H
30#include <strings.h>
31#endif
32#endif
33
34
35/* DEVICE
36
37
38   eeprom - JEDEC? compatible electricaly erasable programable device
39
40
41   DESCRIPTION
42
43
44   This device implements a small byte addressable EEPROM.
45   Programming is performed using the same write sequences as used by
46   standard modern EEPROM components.  Writes occure in real time, the
47   device returning a progress value until the programing has been
48   completed.
49
50   It is based on the AMD 29F040 component.
51
52
53   PROPERTIES
54
55
56   reg = <address> <size> (required)
57
58   Determine where the device lives in the parents address space.
59
60
61   nr-sectors = <integer> (required)
62
63   When erasing an entire sector is cleared at a time.  This specifies
64   the number of sectors in the EEPROM component.
65
66
67   sector-size = <integer> (required)
68
69   The number of bytes in a sector.  When erasing, memory chunks of
70   this size are cleared.
71
72   NOTE: The product nr-sectors * sector-size does not need to map the
73   size specified in the reg property.  If the specified size is
74   smaller part of the eeprom will not be accessible while if it is
75   larger the addresses will wrap.
76
77
78   byte-write-delay = <integer> (required)
79
80   Number of clock ticks before the programming of a single byte
81   completes.
82
83
84   sector-start-delay = <integer> (required)
85
86   When erasing sectors, the number of clock ticks after the sector
87   has been specified that the actual erase process commences.
88
89
90   erase-delay = <intger> (required)
91
92   Number of clock ticks before an erase program completes
93
94
95   manufacture-code = <integer> (required)
96
97   The one byte value returned when the auto-select manufacturer code
98   is read.
99
100
101   device-code = <integer> (required)
102
103   The one byte value returned when the auto-select device code is
104   read.
105
106
107   input-file = <file-name> (optional)
108
109   Initialize the eeprom using the specified binary file.
110
111
112   output-file = <file-name> (optional)
113
114   When ever the eeprom is updated, save the modified image into the
115   specified file.
116
117
118   EXAMPLES
119
120
121   Enable tracing of the eeprom:
122
123   |  bash$ psim -t eeprom-device \
124
125
126   Configure something very like the Amd Am29F040 - 512byte EEPROM
127   (but a bit faster):
128
129   |  -o '/eeprom@0xfff00000/reg 0xfff00000 0x80000' \
130   |  -o '/eeprom@0xfff00000/nr-sectors 8' \
131   |  -o '/eeprom@0xfff00000/sector-size 0x10000' \
132   |  -o '/eeprom@0xfff00000/byte-write-delay 1000' \
133   |  -o '/eeprom@0xfff00000/sector-start-delay 100' \
134   |  -o '/eeprom@0xfff00000/erase-delay 1000' \
135   |  -o '/eeprom@0xfff00000/manufacture-code 0x01' \
136   |  -o '/eeprom@0xfff00000/device-code 0xa4' \
137
138
139   Initialize the eeprom from the file <</dev/zero>>:
140
141   |  -o '/eeprom@0xfff00000/input-file /dev/zero'
142
143
144   BUGS
145
146
147   */
148
149typedef enum {
150  read_reset,
151  write_nr_2,
152  write_nr_3,
153  write_nr_4,
154  write_nr_5,
155  write_nr_6,
156  byte_program,
157  byte_programming,
158  chip_erase,
159  sector_erase,
160  sector_erase_suspend,
161  autoselect,
162} hw_eeprom_states;
163
164static const char *
165state2a(hw_eeprom_states state)
166{
167  switch (state) {
168  case read_reset: return "read_reset";
169  case write_nr_2: return "write_nr_2";
170  case write_nr_3: return "write_nr_3";
171  case write_nr_4: return "write_nr_4";
172  case write_nr_5: return "write_nr_5";
173  case write_nr_6: return "write_nr_6";
174  case byte_program: return "byte_program";
175  case byte_programming: return "byte_programming";
176  case chip_erase: return "chip_erase";
177  case sector_erase: return "sector_erase";
178  case sector_erase_suspend: return "sector_erase_suspend";
179  case autoselect: return "autoselect";
180  }
181  return NULL;
182}
183
184typedef struct _hw_eeprom_device {
185  /* general */
186  hw_eeprom_states state;
187  unsigned8 *memory;
188  unsigned sizeof_memory;
189  unsigned erase_delay;
190  signed64 program_start_time;
191  signed64 program_finish_time;
192  unsigned8 manufacture_code;
193  unsigned8 device_code;
194  unsigned8 toggle_bit;
195  /* initialization */
196  const char *input_file_name;
197  const char *output_file_name;
198  /* for sector and sector programming */
199  hw_eeprom_states sector_state;
200  unsigned8 *sectors;
201  unsigned nr_sectors;
202  unsigned sizeof_sector;
203  unsigned sector_start_delay;
204  unsigned sector_start_time;
205  /* byte and byte programming */
206  unsigned byte_write_delay;
207  unsigned_word byte_program_address;
208  unsigned8 byte_program_byte;
209} hw_eeprom_device;
210
211typedef struct _hw_eeprom_reg_spec {
212  unsigned32 base;
213  unsigned32 size;
214} hw_eeprom_reg_spec;
215
216static void
217hw_eeprom_init_data(device *me)
218{
219  hw_eeprom_device *eeprom = (hw_eeprom_device*)device_data(me);
220
221  /* have we any input or output files */
222  if (device_find_property(me, "input-file") != NULL)
223    eeprom->input_file_name = device_find_string_property(me, "input-file");
224  if (device_find_property(me, "output-file") != NULL)
225    eeprom->input_file_name = device_find_string_property(me, "output-file");
226
227  /* figure out the sectors in the eeprom */
228  if (eeprom->sectors == NULL) {
229    eeprom->nr_sectors = device_find_integer_property(me, "nr-sectors");
230    eeprom->sizeof_sector = device_find_integer_property(me, "sector-size");
231    eeprom->sectors = zalloc(eeprom->nr_sectors);
232  }
233  else
234    memset(eeprom->sectors, 0, eeprom->nr_sectors);
235
236  /* initialize the eeprom */
237  if (eeprom->memory == NULL) {
238    eeprom->sizeof_memory = eeprom->sizeof_sector * eeprom->nr_sectors;
239    eeprom->memory = zalloc(eeprom->sizeof_memory);
240  }
241  else
242    memset(eeprom->memory, 0, eeprom->sizeof_memory);
243  if (eeprom->input_file_name != NULL) {
244    int i;
245    FILE *input_file = fopen(eeprom->input_file_name, "r");
246    if (input_file == NULL) {
247      perror("eeprom");
248      device_error(me, "Failed to open input file %s\n", eeprom->input_file_name);
249    }
250    for (i = 0; i < eeprom->sizeof_memory; i++) {
251      if (fread(&eeprom->memory[i], 1, 1, input_file) != 1)
252	break;
253    }
254    fclose(input_file);
255  }
256
257  /* timing */
258  eeprom->byte_write_delay = device_find_integer_property(me, "byte-write-delay");
259  eeprom->sector_start_delay = device_find_integer_property(me, "sector-start-delay");
260  eeprom->erase_delay = device_find_integer_property(me, "erase-delay");
261
262  /* misc */
263  eeprom->manufacture_code = device_find_integer_property(me, "manufacture-code");
264  eeprom->device_code = device_find_integer_property(me, "device-code");
265}
266
267
268static void
269invalid_read(device *me,
270	     hw_eeprom_states state,
271	     unsigned_word address,
272	     const char *reason)
273{
274  DTRACE(eeprom, ("Invalid read to 0x%lx while in state %s (%s)\n",
275		  (unsigned long)address,
276		  state2a(state),
277		  reason));
278}
279
280static void
281invalid_write(device *me,
282	      hw_eeprom_states state,
283	      unsigned_word address,
284	      unsigned8 data,
285	      const char *reason)
286{
287  DTRACE(eeprom, ("Invalid write of 0x%lx to 0x%lx while in state %s (%s)\n",
288		  (unsigned long)data,
289		  (unsigned long)address,
290		  state2a(state),
291		  reason));
292}
293
294static void
295dump_eeprom(device *me,
296	    hw_eeprom_device *eeprom)
297{
298  if (eeprom->output_file_name != NULL) {
299    int i;
300    FILE *output_file = fopen(eeprom->output_file_name, "w");
301    if (output_file == NULL) {
302      perror("eeprom");
303      device_error(me, "Failed to open output file %s\n",
304		   eeprom->output_file_name);
305    }
306    for (i = 0; i < eeprom->sizeof_memory; i++) {
307      if (fwrite(&eeprom->memory[i], 1, 1, output_file) != 1)
308	break;
309    }
310    fclose(output_file);
311  }
312}
313
314
315/* program a single byte of eeprom */
316
317static void
318start_programming_byte(device *me,
319		       hw_eeprom_device *eeprom,
320		       unsigned_word address,
321		       unsigned8 new_byte)
322{
323  unsigned8 old_byte = eeprom->memory[address];
324  DTRACE(eeprom, ("start-programing-byte - address 0x%lx, new 0x%lx, old 0x%lx\n",
325		  (unsigned long)address,
326		  (unsigned long)new_byte,
327		  (unsigned long)old_byte));
328  eeprom->byte_program_address = address;
329  /* : old new : ~old : new&~old
330     :  0   0  :   1  :    0
331     :  0   1  :   1  :    1     -- can not set a bit
332     :  1   0  :   0  :    0
333     :  1   1  :   0  :    0 */
334  if (~old_byte & new_byte)
335    invalid_write(me, eeprom->state, address, new_byte, "setting cleared bit");
336  /* : old new : old&new
337     :  0   0  :    0
338     :  0   1  :    0
339     :  1   0  :    0
340     :  1   1  :    1 */
341  eeprom->byte_program_byte = new_byte & old_byte;
342  eeprom->memory[address] = ~new_byte & ~0x24; /* LE-bits 5:3 zero */
343  eeprom->program_start_time = device_event_queue_time(me);
344  eeprom->program_finish_time = (eeprom->program_start_time
345				 + eeprom->byte_write_delay);
346}
347
348static void
349finish_programming_byte(device *me,
350			hw_eeprom_device *eeprom)
351{
352  DTRACE(eeprom, ("finish-programming-byte - address 0x%lx, byte 0x%lx\n",
353		  (unsigned long)eeprom->byte_program_address,
354		  (unsigned long)eeprom->byte_program_byte));
355  eeprom->memory[eeprom->byte_program_address] = eeprom->byte_program_byte;
356  dump_eeprom(me, eeprom);
357}
358
359
360/* erase the eeprom completly */
361
362static void
363start_erasing_chip(device *me,
364		   hw_eeprom_device *eeprom)
365{
366  DTRACE(eeprom, ("start-erasing-chip\n"));
367  memset(eeprom->memory, 0, eeprom->sizeof_memory);
368  eeprom->program_start_time = device_event_queue_time(me);
369  eeprom->program_finish_time = (eeprom->program_start_time
370				 + eeprom->erase_delay);
371}
372
373static void
374finish_erasing_chip(device *me,
375		    hw_eeprom_device *eeprom)
376{
377  DTRACE(eeprom, ("finish-erasing-chip\n"));
378  memset(eeprom->memory, 0xff, eeprom->sizeof_memory);
379  dump_eeprom(me, eeprom);
380}
381
382
383/* erase a single sector of the eeprom */
384
385static void
386start_erasing_sector(device *me,
387		     hw_eeprom_device *eeprom,
388		     unsigned_word address)
389{
390  int sector = address / eeprom->sizeof_sector;
391  DTRACE(eeprom, ("start-erasing-sector - address 0x%lx, sector %d\n",
392		  (unsigned long)address, sector));
393  ASSERT(sector < eeprom->nr_sectors);
394  eeprom->sectors[sector] = 1;
395  memset(eeprom->memory + sector * eeprom->sizeof_sector,
396	 0x4, eeprom->sizeof_sector);
397  eeprom->program_start_time = device_event_queue_time(me);
398  eeprom->sector_start_time = (eeprom->program_start_time
399			       + eeprom->sector_start_delay);
400  eeprom->program_finish_time = (eeprom->sector_start_time
401				 + eeprom->erase_delay);
402
403}
404
405static void
406finish_erasing_sector(device *me,
407		      hw_eeprom_device *eeprom)
408{
409  int sector;
410  DTRACE(eeprom, ("finish-erasing-sector\n"));
411  for (sector = 0; sector < eeprom->nr_sectors; sector++) {
412    if (eeprom->sectors[sector]) {
413      eeprom->sectors[sector] = 0;
414      memset(eeprom->memory + sector * eeprom->sizeof_sector,
415	     0xff, eeprom->sizeof_sector);
416    }
417  }
418  dump_eeprom(me, eeprom);
419}
420
421
422/* eeprom reads */
423
424static unsigned8
425toggle(hw_eeprom_device *eeprom,
426       unsigned8 byte)
427{
428  eeprom->toggle_bit = eeprom->toggle_bit ^ 0x40; /* le-bit 6 */
429  return eeprom->toggle_bit ^ byte;
430}
431
432static unsigned8
433read_byte(device *me,
434	  hw_eeprom_device *eeprom,
435	  unsigned_word address)
436{
437  /* may need multiple iterations of this */
438  while (1) {
439    switch (eeprom->state) {
440
441    case read_reset:
442      return eeprom->memory[address];
443
444    case autoselect:
445      if ((address & 0xff) == 0x00)
446	return eeprom->manufacture_code;
447      else if ((address & 0xff) == 0x01)
448	return eeprom->device_code;
449      else
450	return 0; /* not certain about this */
451
452    case byte_programming:
453      if (device_event_queue_time(me) > eeprom->program_finish_time) {
454	finish_programming_byte(me, eeprom);
455	eeprom->state = read_reset;
456	continue;
457      }
458      else if (address == eeprom->byte_program_address) {
459	return toggle(eeprom, eeprom->memory[address]);
460      }
461      else {
462	/* trash that memory location */
463	invalid_read(me, eeprom->state, address, "not byte program address");
464	eeprom->memory[address] = (eeprom->memory[address]
465				   & eeprom->byte_program_byte);
466	return toggle(eeprom, eeprom->memory[eeprom->byte_program_address]);
467      }
468
469    case chip_erase:
470      if (device_event_queue_time(me) > eeprom->program_finish_time) {
471	finish_erasing_chip(me, eeprom);
472	eeprom->state = read_reset;
473	continue;
474      }
475      else {
476	return toggle(eeprom, eeprom->memory[address]);
477      }
478
479    case sector_erase:
480      if (device_event_queue_time(me) > eeprom->program_finish_time) {
481	finish_erasing_sector(me, eeprom);
482	eeprom->state = read_reset;
483	continue;
484      }
485      else if (!eeprom->sectors[address / eeprom->sizeof_sector]) {
486	/* read to wrong sector */
487	invalid_read(me, eeprom->state, address, "sector not being erased");
488	return toggle(eeprom, eeprom->memory[address]) & ~0x8;
489      }
490      else if (device_event_queue_time(me) > eeprom->sector_start_time) {
491	return toggle(eeprom, eeprom->memory[address]) | 0x8;
492      }
493      else {
494	return toggle(eeprom, eeprom->memory[address]) & ~0x8;
495      }
496
497    case sector_erase_suspend:
498      if (!eeprom->sectors[address / eeprom->sizeof_sector]) {
499	return eeprom->memory[address];
500      }
501      else {
502	invalid_read(me, eeprom->state, address, "sector being erased");
503	return eeprom->memory[address];
504      }
505
506    default:
507      invalid_read(me, eeprom->state, address, "invalid state");
508      return eeprom->memory[address];
509
510    }
511  }
512  return 0;
513}
514
515static unsigned
516hw_eeprom_io_read_buffer(device *me,
517			 void *dest,
518			 int space,
519			 unsigned_word addr,
520			 unsigned nr_bytes,
521			 cpu *processor,
522			 unsigned_word cia)
523{
524  hw_eeprom_device *eeprom = (hw_eeprom_device*)device_data(me);
525  int i;
526  for (i = 0; i < nr_bytes; i++) {
527    unsigned_word address = (addr + i) % eeprom->sizeof_memory;
528    unsigned8 byte = read_byte(me, eeprom, address);
529    ((unsigned8*)dest)[i] = byte;
530  }
531  return nr_bytes;
532}
533
534
535/* eeprom writes */
536
537static void
538write_byte(device *me,
539	   hw_eeprom_device *eeprom,
540	   unsigned_word address,
541	   unsigned8 data)
542{
543  /* may need multiple transitions to process a write */
544  while (1) {
545    switch (eeprom->state) {
546
547    case read_reset:
548      if (address == 0x5555 && data == 0xaa)
549	eeprom->state = write_nr_2;
550      else if (data == 0xf0)
551	eeprom->state = read_reset;
552      else {
553	invalid_write(me, eeprom->state, address, data, "unexpected");
554	eeprom->state = read_reset;
555      }
556      return;
557
558    case write_nr_2:
559      if (address == 0x2aaa && data == 0x55)
560	eeprom->state = write_nr_3;
561      else {
562	invalid_write(me, eeprom->state, address, data, "unexpected");
563	eeprom->state = read_reset;
564      }
565      return;
566
567    case write_nr_3:
568      if (address == 0x5555 && data == 0xf0)
569	eeprom->state = read_reset;
570      else if (address == 0x5555 && data == 0x90)
571	eeprom->state = autoselect;
572      else if (address == 0x5555 && data == 0xa0) {
573	eeprom->state = byte_program;
574      }
575      else if (address == 0x5555 && data == 0x80)
576	eeprom->state = write_nr_4;
577      else {
578	invalid_write(me, eeprom->state, address, data, "unexpected");
579	eeprom->state = read_reset;
580      }
581      return;
582
583    case write_nr_4:
584      if (address == 0x5555 && data == 0xaa)
585	eeprom->state = write_nr_5;
586      else {
587	invalid_write(me, eeprom->state, address, data, "unexpected");
588	eeprom->state = read_reset;
589      }
590      return;
591
592    case write_nr_5:
593      if (address == 0x2aaa && data == 0x55)
594	eeprom->state = write_nr_6;
595      else {
596	invalid_write(me, eeprom->state, address, data, "unexpected");
597	eeprom->state = read_reset;
598      }
599      return;
600
601    case write_nr_6:
602      if (address == 0x5555 && data == 0x10) {
603	start_erasing_chip(me, eeprom);
604	eeprom->state = chip_erase;
605      }
606      else {
607	start_erasing_sector(me, eeprom, address);
608	eeprom->sector_state = read_reset;
609	eeprom->state = sector_erase;
610      }
611      return;
612
613    case autoselect:
614      if (data == 0xf0)
615	eeprom->state = read_reset;
616      else if (address == 0x5555 && data == 0xaa)
617	eeprom->state = write_nr_2;
618      else {
619	invalid_write(me, eeprom->state, address, data, "unsupported address");
620	eeprom->state = read_reset;
621      }
622      return;
623
624    case byte_program:
625      start_programming_byte(me, eeprom, address, data);
626      eeprom->state = byte_programming;
627      return;
628
629    case byte_programming:
630      if (device_event_queue_time(me) > eeprom->program_finish_time) {
631	finish_programming_byte(me, eeprom);
632	eeprom->state = read_reset;
633	continue;
634      }
635      /* ignore it */
636      return;
637
638    case chip_erase:
639      if (device_event_queue_time(me) > eeprom->program_finish_time) {
640	finish_erasing_chip(me, eeprom);
641	eeprom->state = read_reset;
642	continue;
643      }
644      /* ignore it */
645      return;
646
647    case sector_erase:
648      if (device_event_queue_time(me) > eeprom->program_finish_time) {
649	finish_erasing_sector(me, eeprom);
650	eeprom->state = eeprom->sector_state;
651	continue;
652      }
653      else if (device_event_queue_time(me) > eeprom->sector_start_time
654	       && data == 0xb0) {
655	eeprom->sector_state = read_reset;
656	eeprom->state = sector_erase_suspend;
657      }
658      else {
659	if (eeprom->sector_state == read_reset
660	    && address == 0x5555 && data == 0xaa)
661	  eeprom->sector_state = write_nr_2;
662	else if (eeprom->sector_state == write_nr_2
663		 && address == 0x2aaa && data == 0x55)
664	  eeprom->sector_state = write_nr_3;
665	else if (eeprom->sector_state == write_nr_3
666		 && address == 0x5555 && data == 0x80)
667	  eeprom->sector_state = write_nr_4;
668	else if (eeprom->sector_state == write_nr_4
669		 && address == 0x5555 && data == 0xaa)
670	  eeprom->sector_state = write_nr_5;
671	else if (eeprom->sector_state == write_nr_5
672		 && address == 0x2aaa && data == 0x55)
673	  eeprom->sector_state = write_nr_6;
674	else if (eeprom->sector_state == write_nr_6
675		 && address != 0x5555 && data == 0x30) {
676	  if (device_event_queue_time(me) > eeprom->sector_start_time) {
677	    DTRACE(eeprom, ("sector erase command after window closed\n"));
678	    eeprom->sector_state = read_reset;
679	  }
680	  else {
681	    start_erasing_sector(me, eeprom, address);
682	    eeprom->sector_state = read_reset;
683	  }
684	}
685	else {
686	  invalid_write(me, eeprom->state, address, data, state2a(eeprom->sector_state));
687	  eeprom->state = read_reset;
688	}
689      }
690      return;
691
692    case sector_erase_suspend:
693      if (data == 0x30)
694	eeprom->state = sector_erase;
695      else {
696	invalid_write(me, eeprom->state, address, data, "not resume command");
697	eeprom->state = read_reset;
698      }
699      return;
700
701    }
702  }
703}
704
705static unsigned
706hw_eeprom_io_write_buffer(device *me,
707			  const void *source,
708			  int space,
709			  unsigned_word addr,
710			  unsigned nr_bytes,
711			  cpu *processor,
712			  unsigned_word cia)
713{
714  hw_eeprom_device *eeprom = (hw_eeprom_device*)device_data(me);
715  int i;
716  for (i = 0; i < nr_bytes; i++) {
717    unsigned_word address = (addr + i) % eeprom->sizeof_memory;
718    unsigned8 byte = ((unsigned8*)source)[i];
719    write_byte(me, eeprom, address, byte);
720  }
721  return nr_bytes;
722}
723
724
725/* An instance of the eeprom */
726
727typedef struct _hw_eeprom_instance {
728  unsigned_word pos;
729  hw_eeprom_device *eeprom;
730  device *me;
731} hw_eeprom_instance;
732
733static void
734hw_eeprom_instance_delete(device_instance *instance)
735{
736  hw_eeprom_instance *data = device_instance_data(instance);
737  free(data);
738}
739
740static int
741hw_eeprom_instance_read(device_instance *instance,
742			void *buf,
743			unsigned_word len)
744{
745  hw_eeprom_instance *data = device_instance_data(instance);
746  int i;
747  if (data->eeprom->state != read_reset)
748    DITRACE(eeprom, ("eeprom not idle during instance read\n"));
749  for (i = 0; i < len; i++) {
750    ((unsigned8*)buf)[i] = data->eeprom->memory[data->pos];
751    data->pos = (data->pos + 1) % data->eeprom->sizeof_memory;
752  }
753  return len;
754}
755
756static int
757hw_eeprom_instance_write(device_instance *instance,
758			 const void *buf,
759			 unsigned_word len)
760{
761  hw_eeprom_instance *data = device_instance_data(instance);
762  int i;
763  if (data->eeprom->state != read_reset)
764    DITRACE(eeprom, ("eeprom not idle during instance write\n"));
765  for (i = 0; i < len; i++) {
766    data->eeprom->memory[data->pos] = ((unsigned8*)buf)[i];
767    data->pos = (data->pos + 1) % data->eeprom->sizeof_memory;
768  }
769  dump_eeprom(data->me, data->eeprom);
770  return len;
771}
772
773static int
774hw_eeprom_instance_seek(device_instance *instance,
775		      unsigned_word pos_hi,
776		      unsigned_word pos_lo)
777{
778  hw_eeprom_instance *data = device_instance_data(instance);
779  if (pos_lo >= data->eeprom->sizeof_memory)
780    device_error(data->me, "seek value 0x%lx out of range\n",
781		 (unsigned long)pos_lo);
782  data->pos = pos_lo;
783  return 0;
784}
785
786static const device_instance_callbacks hw_eeprom_instance_callbacks = {
787  hw_eeprom_instance_delete,
788  hw_eeprom_instance_read,
789  hw_eeprom_instance_write,
790  hw_eeprom_instance_seek,
791};
792
793static device_instance *
794hw_eeprom_create_instance(device *me,
795			  const char *path,
796			  const char *args)
797{
798  hw_eeprom_device *eeprom = device_data(me);
799  hw_eeprom_instance *data = ZALLOC(hw_eeprom_instance);
800  data->eeprom = eeprom;
801  data->me = me;
802  return device_create_instance_from(me, NULL,
803				     data,
804				     path, args,
805				     &hw_eeprom_instance_callbacks);
806}
807
808
809
810static device_callbacks const hw_eeprom_callbacks = {
811  { generic_device_init_address,
812    hw_eeprom_init_data },
813  { NULL, }, /* address */
814  { hw_eeprom_io_read_buffer,
815    hw_eeprom_io_write_buffer }, /* IO */
816  { NULL, }, /* DMA */
817  { NULL, }, /* interrupt */
818  { NULL, }, /* unit */
819  hw_eeprom_create_instance,
820};
821
822static void *
823hw_eeprom_create(const char *name,
824		 const device_unit *unit_address,
825		 const char *args)
826{
827  hw_eeprom_device *eeprom = ZALLOC(hw_eeprom_device);
828  return eeprom;
829}
830
831
832
833const device_descriptor hw_eeprom_device_descriptor[] = {
834  { "eeprom", hw_eeprom_create, &hw_eeprom_callbacks },
835  { NULL },
836};
837
838#endif /* _HW_EEPROM_C_ */
839