1/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/nsc/panel/platform.c,v 1.3tsi Exp $ */
2/*
3 * $Workfile: platform.c $
4 * $Revision: 1.1.1.1 $
5 *
6 * File Contents: This file contains platform dependent functions
7 *                which provide interface to that platform.
8 *
9 *
10 * SubModule:     Geode FlatPanel library
11 *
12 */
13
14/*
15 * NSC_LIC_ALTERNATIVE_PREAMBLE
16 *
17 * Revision 1.0
18 *
19 * National Semiconductor Alternative GPL-BSD License
20 *
21 * National Semiconductor Corporation licenses this software
22 * ("Software"):
23 *
24 * Panel Library
25 *
26 * under one of the two following licenses, depending on how the
27 * Software is received by the Licensee.
28 *
29 * If this Software is received as part of the Linux Framebuffer or
30 * other GPL licensed software, then the GPL license designated
31 * NSC_LIC_GPL applies to this Software; in all other circumstances
32 * then the BSD-style license designated NSC_LIC_BSD shall apply.
33 *
34 * END_NSC_LIC_ALTERNATIVE_PREAMBLE */
35
36/* NSC_LIC_BSD
37 *
38 * National Semiconductor Corporation Open Source License for
39 *
40 * Panel Library
41 *
42 * (BSD License with Export Notice)
43 *
44 * Copyright (c) 1999-2001
45 * National Semiconductor Corporation.
46 * All rights reserved.
47 *
48 * Redistribution and use in source and binary forms, with or without
49 * modification, are permitted provided that the following conditions
50 * are met:
51 *
52 *   * Redistributions of source code must retain the above copyright
53 *     notice, this list of conditions and the following disclaimer.
54 *
55 *   * Redistributions in binary form must reproduce the above
56 *     copyright notice, this list of conditions and the following
57 *     disclaimer in the documentation and/or other materials provided
58 *     with the distribution.
59 *
60 *   * Neither the name of the National Semiconductor Corporation nor
61 *     the names of its contributors may be used to endorse or promote
62 *     products derived from this software without specific prior
63 *     written permission.
64 *
65 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
66 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
67 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
68 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
69 * NATIONAL SEMICONDUCTOR CORPORATION OR CONTRIBUTORS BE LIABLE FOR ANY
70 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
71 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
72 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
73 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
74 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE,
75 * INTELLECTUAL PROPERTY INFRINGEMENT, OR OTHERWISE) ARISING IN ANY WAY
76 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
77 * OF SUCH DAMAGE.
78 *
79 * EXPORT LAWS: THIS LICENSE ADDS NO RESTRICTIONS TO THE EXPORT LAWS OF
80 * YOUR JURISDICTION. It is licensee's responsibility to comply with
81 * any export regulations applicable in licensee's jurisdiction. Under
82 * CURRENT (2001) U.S. export regulations this software
83 * is eligible for export from the U.S. and can be downloaded by or
84 * otherwise exported or reexported worldwide EXCEPT to U.S. embargoed
85 * destinations which include Cuba, Iraq, Libya, North Korea, Iran,
86 * Syria, Sudan, Afghanistan and any other country to which the U.S.
87 * has embargoed goods and services.
88 *
89 * END_NSC_LIC_BSD */
90
91/* NSC_LIC_GPL
92 *
93 * National Semiconductor Corporation Gnu General Public License for
94 *
95 * Panel Library
96 *
97 * (GPL License with Export Notice)
98 *
99 * Copyright (c) 1999-2001
100 * National Semiconductor Corporation.
101 * All rights reserved.
102 *
103 * Redistribution and use in source and binary forms, with or without
104 * modification, are permitted under the terms of the GNU General
105 * Public License as published by the Free Software Foundation; either
106 * version 2 of the License, or (at your option) any later version
107 *
108 * In addition to the terms of the GNU General Public License, neither
109 * the name of the National Semiconductor Corporation nor the names of
110 * its contributors may be used to endorse or promote products derived
111 * from this software without specific prior written permission.
112 *
113 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
114 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
115 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
116 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
117 * NATIONAL SEMICONDUCTOR CORPORATION OR CONTRIBUTORS BE LIABLE FOR ANY
118 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
119 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
120 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
121 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
122 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE,
123 * INTELLECTUAL PROPERTY INFRINGEMENT, OR OTHERWISE) ARISING IN ANY WAY
124 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
125 * OF SUCH DAMAGE. See the GNU General Public License for more details.
126 *
127 * EXPORT LAWS: THIS LICENSE ADDS NO RESTRICTIONS TO THE EXPORT LAWS OF
128 * YOUR JURISDICTION. It is licensee's responsibility to comply with
129 * any export regulations applicable in licensee's jurisdiction. Under
130 * CURRENT (2001) U.S. export regulations this software
131 * is eligible for export from the U.S. and can be downloaded by or
132 * otherwise exported or reexported worldwide EXCEPT to U.S. embargoed
133 * destinations which include Cuba, Iraq, Libya, North Korea, Iran,
134 * Syria, Sudan, Afghanistan and any other country to which the U.S.
135 * has embargoed goods and services.
136 *
137 * You should have received a copy of the GNU General Public License
138 * along with this file; if not, write to the Free Software Foundation,
139 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
140 *
141 * END_NSC_LIC_GPL */
142
143#define LINUX_ROM_SEGMENT 0x000F
144#define SEGMENT_LENGTH  0xFFFF
145#define PAGE_LENGTH     0x1000
146#define SYS_BOARD_NAME_LEN 24
147
148#define PLT_READ         0
149#define PLT_WRITE        1
150#define PLT_WRITE_BYTES  2
151#define PLT_READ_BYTES   3
152#define PLT_WRITE_WORDS  4
153#define PLT_READ_WORDS   5
154#define PLT_WRITE_DWORDS 6
155#define PLT_READ_DWORDS  7
156#define PLT_UNKNOWN	 ((SYS_BOARD) 0xFFFF)
157
158typedef struct
159{
160   char sys_board_name[SYS_BOARD_NAME_LEN];
161   SYS_BOARD sys_board;
162}
163SYS_BOARD_INFO;
164
165static SYS_BOARD_INFO Sys_info;
166
167/*
168 * The names in the sys_board_name string must exactly match the names in the
169 * BIOS header. These names are used by FindStringInSeg() to find the names
170 * in the BIOS header space. The BIOS does not use OTHER; it is a dummy value
171 * for program useonly.
172 *
173 */
174
175SYS_BOARD_INFO Sys_board_info_array[] = {
176   {"Marmot", MARMOT_PLATFORM},
177   {"Unicorn", UNICORN_PLATFORM},
178   {"Centaurus", CENTAURUS_PLATFORM},
179   {"Aries", ARIES_PLATFORM},
180   {"Carmel", CARMEL_PLATFORM},
181   {"Hyrda", HYDRA_PLATFORM},
182   {"Dorado", DORADO_PLATFORM},
183   {"Redcloud", REDCLOUD_PLATFORM},
184   {"Other", OTHER_PLATFORM}
185};
186
187#define NUM_SYS_BOARD_TYPES sizeof(Sys_board_info_array)/sizeof(SYS_BOARD_INFO)
188
189static int Num_sys_board_type = NUM_SYS_BOARD_TYPES;
190SYS_BOARD_INFO *Sys_board_array_base = Sys_board_info_array;
191int FindStringInSeg(unsigned int, char *);
192static unsigned char get_sys_board_type(SYS_BOARD_INFO *, SYS_BOARD_INFO *);
193
194#if defined(linux) && !defined(__KERNEL__)
195#if !defined(XFree86Server)
196static void platform_protected_mode_access(unsigned int, unsigned int,
197					   unsigned long, unsigned char *);
198static void setup_pma();
199static void close_pma();
200static int fd;
201#endif /* IN_MODULE */
202#endif /* __KERNEL__ */
203
204/* Detect the Platform */
205int
206Detect_Platform(void)
207{
208#if defined(linux) && !defined(__KERNEL__)
209#if !defined(XFree86Server)
210   setup_pma();
211#endif /* IN_MODULE */
212#endif /* __KERNEL__ */
213
214   /* See if we can find the board name using Xpressrom */
215   if (get_sys_board_type(&Sys_info, Sys_board_array_base) == TRUE) {
216#if 0
217      if (Sys_info.sys_board == CENTAURUS_PLATFORM) {
218	 printk("CENTAURUS Platform Found\n");
219      } else if (Sys_info.sys_board == DORADO_PLATFORM) {
220	 printk("DORADO Platform Found \n");
221      } else {
222	 printk("UNKNOWN Platform Found \n");
223      }
224#endif
225   }
226#if defined(linux) && !defined(__KERNEL__)
227#if !defined(XFree86Server)
228   close_pma();
229#endif /* IN_MODULE */
230#endif /* __KERNEL__ */
231
232   return (Sys_info.sys_board);
233}
234
235static int
236Strncmp(char *str1, char *str2, int len)
237{
238   int i;
239
240   if ((str1 == 0x0) || (str2 == 0x0) || (len == 0))
241      return (1);
242   for (i = 0; i < len; i++) {
243      if (*(str1 + i) > *(str2 + i)) {
244	 return 1;
245      } else if (*(str1 + i) < *(str2 + i)) {
246	 return -1;
247      }
248   }
249   return 0;
250}
251
252static char *
253Strcpy(char *dst, char *src)
254{
255   int i;
256
257   if ((dst == 0x0) || (src == 0x0))
258      return (0);
259   for (i = 0; src[i] != 0x0; i++) {
260      dst[i] = src[i];
261   }
262   dst[i] = 0x0;			/* NULL termination */
263   return dst;
264}
265
266static int
267Strlen(char *str)
268{
269   int i;
270
271   if (str == 0x0)
272      return 0;
273   for (i = 0; str[i] != 0x0; i++) ;
274   return i;
275}
276
277/***********************************************************************/
278
279/* Platform Detection Code */
280
281/***********************************************************************/
282
283/************************************************************************
284 * int FindStringInSeg( unsigned int segment_address, char *string_ptr )
285 * Returns the offset where the NULL terminated string pointed to by
286 * string_ptr is located in the segment passed in segment_address.
287 * Segment_address must be of the form 0xXXXX (i.e 0xf000 for segment f).
288 * Returns NULL if the string is not found.
289 ************************************************************************
290 */
291int
292FindStringInSeg(unsigned int segment_address, char *string_ptr)
293{
294   int string_length = Strlen(string_ptr);
295   char *psegment_buf;
296   unsigned long mem_ptr = (unsigned long)segment_address << 16;
297   char segment_buffer[SEGMENT_LENGTH + 1];
298   int i, cursor = 0;
299
300   /* silence compiler */
301   (void)cursor;
302   (void)mem_ptr;
303   (void)segment_buffer;
304
305#if defined(linux) && !defined(XFree86Server)
306#ifdef __KERNEL__
307   XpressROMPtr = (unsigned char *)ioremap(mem_ptr, SEGMENT_LENGTH + 1);
308   psegment_buf = (char *)XpressROMPtr;
309#else
310   /* Fill the segment_buffer with 16 page accesses */
311
312   for (cursor = 0; (cursor * PAGE_LENGTH) < SEGMENT_LENGTH; cursor++) {
313      platform_protected_mode_access(PLT_READ_BYTES, PAGE_LENGTH, mem_ptr +
314			    (cursor * PAGE_LENGTH),
315			    &(segment_buffer[(cursor * PAGE_LENGTH)]));
316   }
317   psegment_buf = segment_buffer;
318#endif /* __KERNEL__ */
319#elif defined (XFree86Server)
320   psegment_buf = (char *)XpressROMPtr;
321#elif defined(_WIN32)			/* Windows */
322   psegment_buf = XpressROMPtr;
323#endif
324
325   /* Now search for the first character of the string_ptr */
326   for (i = 0; i < SEGMENT_LENGTH + 1; i++) {
327      if (*(psegment_buf + i) == *string_ptr) {
328
329	 /* If we match the first character, do a
330	  * string compare.
331	  */
332
333	 if (!Strncmp(string_ptr, (psegment_buf + i), string_length)) {
334	    /* They match! */
335	    return (1);
336	 }
337      }
338   }
339   /* if we got this far we didn't find anything.  Return NULL. */
340   return (0);
341
342}					/* end FindStringInSeg() */
343
344/**********************************************************************
345
346 * TRUE_FALSE get_sys_board_type( SYS_BOARD_INFO *sys_info,
347 * SYS_BOARD_INFO *sys_board_array_base)  Checks the system
348 * BIOS area for Xpressrom information. If found, searches the  BIOS
349 * area for one of names in the array pointed to by sys_board_array_ptr.
350 * If a match is found, sets the SYS_INFO system_board_name string
351 * and the system_board variable to the board name and returns TRUE.
352 * If Xpressrom or a board is not found, sets the variables to
353 * their default values and returns FALSE.
354 * Uses the global string pointer *xpress_rom_string_ptr.
355 *
356 ***********************************************************************
357 */
358
359static unsigned char
360get_sys_board_type(SYS_BOARD_INFO * sys_info,
361		   SYS_BOARD_INFO * sys_board_array_base)
362{
363   int index;
364   char *xpress_rom_string_ptr = "XpressStart";
365   unsigned int segment = LINUX_ROM_SEGMENT;
366
367   /* See if XpressStart is present in the BIOS area.
368    * If it is, search for a board string.  If not, Xpressrom is
369    * not present, set system_board information to UNKNOWN and
370    * return FALSE.
371    */
372
373   if (!FindStringInSeg(segment, xpress_rom_string_ptr)) {
374      sys_info->sys_board = PLT_UNKNOWN;
375      Strcpy(sys_info->sys_board_name, "Unknown");
376      return (FALSE);
377   } else {
378
379      /* we have Xpressrom, so look for a board */
380      for (index = 0; index < Num_sys_board_type; index++) {
381	 if (!FindStringInSeg(segment, (sys_board_array_base +
382					index)->sys_board_name)) {
383	    continue;
384	 } else {
385
386	    /* a match!! */
387	    sys_info->sys_board = (sys_board_array_base + index)->sys_board;
388	    Strcpy(sys_info->sys_board_name,
389		   (sys_board_array_base + index)->sys_board_name);
390	    return (TRUE);
391	 }
392      }					/* end for() */
393   }					/* end else */
394
395   /* if we are here we have failed */
396   sys_info->sys_board = PLT_UNKNOWN;
397   Strcpy(sys_info->sys_board_name, "Unknown");
398   return (FALSE);
399}					/* end get_sys_board_type() */
400
401#if defined(linux) && !defined(__KERNEL__)
402#if !defined(XFree86Server)
403
404/******************************************************************
405 *
406 * platform_protected_mode_access( unsigned int mode, unsigned int width,
407 * unsigned long addr, unsigned char* pdata )
408 * This function provides access to physical memory
409 * at the requested address.
410 * mode is: PLT_READ or PLT_WRITE (accesses a single byte, word
411 * or double word depending on the value of "width".
412 * Only 1, 2 or 4 supported).
413 * PLT_READ_BYTES, PLT_WRITE_BYTES accesses "width" number
414 * of bytes (8 bits)
415 * PLT_READ_WORDS, PLT_WRITE_WORDS accesses "width" number
416 * of words (16 bits) PLT_READ_DWORDS, PLT_WRITE_DWORDS accesses
417 * "width" number of dwords (32 bits)
418 * width is: The size of the access.
419 * For PLT_READ or PLT_WRITE, only 1, 2 and 4 are
420 * supported.  For other modes, width is not limited but
421 * will cause paging if the block traverses page boundaries.
422 * addr is: The physical address being accessed
423 * pdata is: A pointer to the data to be read or written into.
424 * NOTE! WORD or DWORD accesses can only be made on
425 * WORD or DWORD boundaries!
426 *
427 ******************************************************************
428 */
429
430static void
431platform_protected_mode_access(unsigned int mode, unsigned int width,
432		      unsigned long addr, unsigned char *pdata)
433{
434
435#define PMTRASH 0x12345678L
436
437   unsigned long base;			/* The physical page address */
438   int length = 0x1000;			/* the page size is 4k */
439   unsigned int offset = 0;		/* The physical addr offset into page */
440   unsigned int index = 0;		/* Used to read/write from/to a block */
441   unsigned int chunk = 0;		/* The amount to read/wr from THIS block */
442   unsigned int size = 0;		/* Data size shift value (to avoid math) */
443   static void *ptr;			/* pointer to real memory location. */
444
445   static unsigned long lastbase = PMTRASH;
446
447   /* temp storage of previous base used. */
448   /* type specific buffer pointers */
449   unsigned char *byte_data = (unsigned char *)pdata;
450   unsigned int *word_data = (unsigned int *)pdata;
451   unsigned long *dword_data = (unsigned long *)pdata;
452
453   switch (mode) {
454
455   case PLT_READ_WORDS:
456   case PLT_WRITE_WORDS:
457
458      size = 1;
459      break;
460
461   case PLT_READ_DWORDS:
462   case PLT_WRITE_DWORDS:
463
464      size = 2;
465   }
466
467   /* Check if we're in the user accessable range */
468   if (addr < 0xFF000000L) {
469
470      /* We get physical memory in "pages", defined by the
471       * following "base" address and the "offset" into it.
472       * "base" will be used with mmap to get "ptr", which
473       * points to the memory mapped actual physical memory at
474       * the address pointed-to by "base".
475       * "width" and "chunk" are in units of whatever data
476       * type we're reading.
477       * "length" and "offset" are in units of bytes.
478       * "width" and "chunk" must be adjusted with "<<size"
479       * to use with "length" or "offset".  Similarly, the
480       * result must be adjusted with ">>size" to make into the
481       * proper type units when done.
482       */
483      base = addr & 0xFFFFF000L;
484      offset = addr & 0x00000FFFL;
485      do {
486	 if ((offset + (width << size)) > length) {
487
488	    /* Block being read extends beyond the
489	     * page boundary. Adjust things.
490	     */
491	    chunk = (length - offset) >> size;
492
493	    /* Figure the chunk size */
494	    width -= chunk;
495
496	    /* Reduce width by the current chunk */
497	 } else {
498
499	    /* Block being read is within the
500	     * page boundary.
501	     */
502	    chunk = width;
503	    width = 0;
504
505	    /* set to zero so we'll exit at the end */
506
507	 }
508	 /* We keep the page around in case we need to
509	  * access it again.
510	  * This saves us some time if we have consecutive
511	  * accesses.
512	  */
513
514	 if (base != lastbase) {
515
516	    /* we haven't mmap'd this address
517	     * Have to get a new page.  Free the
518	     * previous page, if it's valid  (ie, not
519	     * PMTRASH). If not, unmap it and get the
520	     * new page.
521	     */
522	    if (lastbase != PMTRASH)
523	       munmap(ptr, length);
524	    ptr = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd,
525		       base);
526	    if ((int)ptr == -1) {
527	       lastbase = PMTRASH;
528	       return;			/* error */
529	    }
530	 }
531
532	 /* Now we're ready to get the data.
533	  * It's pure memory access now, no funny
534	  * function calls, however we do cast things to get
535	  * the right size data.
536	  */
537
538	 /* Scale the offset for the data type size */
539	 index = offset >> size;
540
541	 /* Note that the above line and below lines,
542	  * which shift "offset", discard address information
543	  * if you happen to be trying to write, for example,
544	  * dwords on non-dword boundaries.
545	  */
546	 /* Note that cases PLT_READ and PLT_WRITE don't
547	  * use "index". They shift "offset"  on their own.
548	  * This is because in PLT_READ and PLT_WRITE modes,
549	  * the information on the size of the data
550	  * transaction is in the "width" variable not "size".
551	  * We also need separate cases to cast the values
552	  * right.
553	  */
554	 switch (mode) {
555
556	 case PLT_READ:{
557
558	       switch (chunk) {
559
560	       case FOUR_BYTES:
561
562		  *(dword_data) = (unsigned long)
563			(*(((unsigned long *)ptr) + (offset >> 2)));
564		  break;
565
566	       case TWO_BYTES:
567
568		  *(word_data) = (unsigned int)
569			(*(((unsigned int *)ptr) + (offset >> 1)));
570		  break;
571
572	       default:
573
574		  *(byte_data) = (unsigned char)
575			(*(((unsigned char *)ptr) + (offset)));
576		  break;
577
578	       }			/* end switch() */
579	       break;
580
581	    }				/* end case PLT_READ */
582
583	 case PLT_WRITE:{
584
585	       switch (chunk) {
586
587	       case FOUR_BYTES:
588
589		  *(((unsigned long *)ptr) + (offset >> 2)) = *dword_data;
590		  break;
591
592	       case TWO_BYTES:
593
594		  *(((unsigned int *)ptr) + (offset >> 1)) = *word_data;
595		  break;
596
597	       default:
598
599		  *(((unsigned char *)ptr) + (offset)) = *byte_data;
600		  break;
601	       }			/* end switch() */
602	       break;
603
604	    }				/* end case PLT_WRITE */
605
606	 case PLT_READ_BYTES:{
607
608	       for (; chunk > 0; chunk--) {
609
610		  *(byte_data++) = (unsigned char)(*(((unsigned char *)ptr) +
611						     (index++)));
612	       }
613	       break;
614	    }				/* end case PLT_READ_BYTES */
615
616	 case PLT_WRITE_BYTES:{
617
618	       for (; chunk > 0; chunk--) {
619		  *(((unsigned char *)ptr) + (index++)) = *(byte_data++);
620	       }
621	       break;
622
623	    }				/* end case PLT_WRITE_BYTES */
624
625	 case PLT_READ_WORDS:{
626
627	       for (; chunk > 0; chunk--) {
628
629		  *(word_data++) = (unsigned int)
630			(*(((unsigned int *)ptr) + (index++)));
631	       }
632	       break;
633
634	    }				/* end case PLT_READ_WORDS */
635
636	 case PLT_WRITE_WORDS:{
637
638	       for (; chunk > 0; chunk--) {
639
640		  *(((unsigned int *)ptr) + (index++)) = *(word_data++);
641	       }
642	       break;
643
644	    }				/* end case PLT_WRITE_WORDS */
645
646	 case PLT_READ_DWORDS:{
647
648	       for (; chunk > 0; chunk--) {
649
650		  *(dword_data++) = (*(((unsigned long *)ptr) + (index++)));
651	       }
652	       break;
653
654	    }				/* end case PLT_READ_DWORDS */
655
656	 case PLT_WRITE_DWORDS:{
657
658	       for (; chunk > 0; chunk--) {
659
660		  *(((unsigned long *)ptr) + (index++))
661			= *(dword_data++);
662	       }
663	       break;
664
665	    }				/* end case PLT_WRITE_DWORDS */
666
667	 }				/* end switch(mode) */
668
669	 lastbase = base;
670
671	 /* Save the page we've just processed. */
672
673	 if (width) {
674
675	    /* If there's still width left to get. */
676
677	    base += length;
678	    /* Increment to the next page. */
679
680	    offset = 0;
681	    /* Set the offset to zero. */
682	 }
683
684      } while (width);			/* While there's still data to get. */
685      return;
686
687   } /* end for if addr */
688   else {
689
690      printf("PMA error: Unable to read ROM address space\n");
691      exit(1);
692   }
693   return;
694}
695
696/************************************************************************
697 * setup_pma() loads the ROM memory access module and initializes
698 * memory access file descriptor (access is handled through a file-like
699 * interface).
700 ************************************************************************
701 */
702static void
703setup_pma()
704{
705   fd = open("/dev/mem", 2);		/*  O_RDWR */
706   if (fd == -1) {
707
708      printf("Error: Unable to open /dev/mem !\a\n");
709      exit(1);
710   }
711   return;
712}
713
714/**********************************************************************
715 * close_pma() cleans up the open memory access devices and file
716 * descriptors.
717 **********************************************************************
718 */
719static void
720close_pma()
721{
722   close(fd);
723   return;
724}
725#endif /* IN_MODULE */
726#endif /* linux && !__KERNEL__ */
727