1 /* 2 * p1275.c: Sun IEEE 1275 PROM low level interface routines 3 * 4 * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) 5 */ 6 7 #include <linux/kernel.h> 8 #include <linux/init.h> 9 #include <linux/sched.h> 10 #include <linux/smp.h> 11 #include <linux/string.h> 12 #include <linux/spinlock.h> 13 14 #include <asm/openprom.h> 15 #include <asm/oplib.h> 16 #include <asm/system.h> 17 #include <asm/spitfire.h> 18 #include <asm/pstate.h> 19 #include <asm/ldc.h> 20 21 struct { 22 long prom_callback; /* 0x00 */ 23 void (*prom_cif_handler)(long *); /* 0x08 */ 24 unsigned long prom_cif_stack; /* 0x10 */ 25 unsigned long prom_args [23]; /* 0x18 */ 26 char prom_buffer [3000]; 27 } p1275buf; 28 29 extern void prom_world(int); 30 31 extern void prom_cif_interface(void); 32 extern void prom_cif_callback(void); 33 34 /* 35 * This provides SMP safety on the p1275buf. prom_callback() drops this lock 36 * to allow recursuve acquisition. 37 */ 38 DEFINE_SPINLOCK(prom_entry_lock); 39 40 long p1275_cmd(const char *service, long fmt, ...) 41 { 42 char *p, *q; 43 unsigned long flags; 44 int nargs, nrets, i; 45 va_list list; 46 long attrs, x; 47 48 p = p1275buf.prom_buffer; 49 50 spin_lock_irqsave(&prom_entry_lock, flags); 51 52 p1275buf.prom_args[0] = (unsigned long)p; /* service */ 53 strcpy (p, service); 54 p = (char *)(((long)(strchr (p, 0) + 8)) & ~7); 55 p1275buf.prom_args[1] = nargs = (fmt & 0x0f); /* nargs */ 56 p1275buf.prom_args[2] = nrets = ((fmt & 0xf0) >> 4); /* nrets */ 57 attrs = fmt >> 8; 58 va_start(list, fmt); 59 for (i = 0; i < nargs; i++, attrs >>= 3) { 60 switch (attrs & 0x7) { 61 case P1275_ARG_NUMBER: 62 p1275buf.prom_args[i + 3] = 63 (unsigned)va_arg(list, long); 64 break; 65 case P1275_ARG_IN_64B: 66 p1275buf.prom_args[i + 3] = 67 va_arg(list, unsigned long); 68 break; 69 case P1275_ARG_IN_STRING: 70 strcpy (p, va_arg(list, char *)); 71 p1275buf.prom_args[i + 3] = (unsigned long)p; 72 p = (char *)(((long)(strchr (p, 0) + 8)) & ~7); 73 break; 74 case P1275_ARG_OUT_BUF: 75 (void) va_arg(list, char *); 76 p1275buf.prom_args[i + 3] = (unsigned long)p; 77 x = va_arg(list, long); 78 i++; attrs >>= 3; 79 p = (char *)(((long)(p + (int)x + 7)) & ~7); 80 p1275buf.prom_args[i + 3] = x; 81 break; 82 case P1275_ARG_IN_BUF: 83 q = va_arg(list, char *); 84 p1275buf.prom_args[i + 3] = (unsigned long)p; 85 x = va_arg(list, long); 86 i++; attrs >>= 3; 87 memcpy (p, q, (int)x); 88 p = (char *)(((long)(p + (int)x + 7)) & ~7); 89 p1275buf.prom_args[i + 3] = x; 90 break; 91 case P1275_ARG_OUT_32B: 92 (void) va_arg(list, char *); 93 p1275buf.prom_args[i + 3] = (unsigned long)p; 94 p += 32; 95 break; 96 case P1275_ARG_IN_FUNCTION: 97 p1275buf.prom_args[i + 3] = 98 (unsigned long)prom_cif_callback; 99 p1275buf.prom_callback = va_arg(list, long); 100 break; 101 } 102 } 103 va_end(list); 104 105 prom_world(1); 106 prom_cif_interface(); 107 prom_world(0); 108 109 attrs = fmt >> 8; 110 va_start(list, fmt); 111 for (i = 0; i < nargs; i++, attrs >>= 3) { 112 switch (attrs & 0x7) { 113 case P1275_ARG_NUMBER: 114 (void) va_arg(list, long); 115 break; 116 case P1275_ARG_IN_STRING: 117 (void) va_arg(list, char *); 118 break; 119 case P1275_ARG_IN_FUNCTION: 120 (void) va_arg(list, long); 121 break; 122 case P1275_ARG_IN_BUF: 123 (void) va_arg(list, char *); 124 (void) va_arg(list, long); 125 i++; attrs >>= 3; 126 break; 127 case P1275_ARG_OUT_BUF: 128 p = va_arg(list, char *); 129 x = va_arg(list, long); 130 memcpy (p, (char *)(p1275buf.prom_args[i + 3]), (int)x); 131 i++; attrs >>= 3; 132 break; 133 case P1275_ARG_OUT_32B: 134 p = va_arg(list, char *); 135 memcpy (p, (char *)(p1275buf.prom_args[i + 3]), 32); 136 break; 137 } 138 } 139 va_end(list); 140 x = p1275buf.prom_args [nargs + 3]; 141 142 spin_unlock_irqrestore(&prom_entry_lock, flags); 143 144 return x; 145 } 146 147 void prom_cif_init(void *cif_handler, void *cif_stack) 148 { 149 p1275buf.prom_cif_handler = (void (*)(long *))cif_handler; 150 p1275buf.prom_cif_stack = (unsigned long)cif_stack; 151 } 152