eisa_enumerator.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:11k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * eisa_enumerator.c - provide support for EISA adapters in PA-RISC machines
  3.  *
  4.  * This program is free software; you can redistribute it and/or
  5.  * modify it under the terms of the GNU General Public License
  6.  * as published by the Free Software Foundation; either version
  7.  * 2 of the License, or (at your option) any later version.
  8.  *
  9.  * Copyright (c) 2002 Daniel Engstrom <5116@telia.com>
  10.  *
  11.  */
  12. #include <linux/ioport.h>
  13. #include <linux/init.h>
  14. #include <linux/kernel.h>
  15. #include <linux/slab.h>
  16. #include <asm/gsc.h>
  17. #include <asm/uaccess.h>
  18. #include <asm/byteorder.h>
  19. #include <asm/eisa_bus.h>
  20. #include <asm/eisa_eeprom.h>
  21. /*
  22.  * Todo:
  23.  * 
  24.  * PORT init with MASK attr and other size than byte
  25.  * MEMORY with other decode than 20 bit
  26.  * CRC stuff
  27.  * FREEFORM stuff
  28.  */
  29. #define EPI 0xc80
  30. #define NUM_SLOT 16
  31. #define SLOT2PORT(x) (x<<12)
  32. /* macros to handle unaligned accesses and 
  33.  * byte swapping. The data in the EEPROM is
  34.  * little-endian on the big-endian PAROSC */
  35. #define get_8(x) (*(u_int8_t*)(x))
  36. static inline u_int16_t get_16(const unsigned char *x)
  37. return (x[1] << 8) | x[0];
  38. }
  39. static inline u_int32_t get_32(const unsigned char *x)
  40. {
  41. return (x[3] << 24) | (x[2] << 16) | (x[1] << 8) | x[0];
  42. }
  43. static inline u_int32_t get_24(const unsigned char *x)
  44. {
  45. return (x[2] << 24) | (x[1] << 16) | (x[0] << 8);
  46. }
  47. static void print_eisa_id(char *s, u_int32_t id)
  48. {
  49. char vendor[4];
  50. int rev;
  51. int device;
  52. rev = id & 0xff;
  53. id >>= 8;
  54. device = id & 0xff;
  55. id >>= 8;
  56. vendor[3] = '';
  57. vendor[2] = '@' + (id & 0x1f);
  58. id >>= 5;
  59. vendor[1] = '@' + (id & 0x1f);
  60. id >>= 5;
  61. vendor[0] = '@' + (id & 0x1f);
  62. id >>= 5;
  63. sprintf(s, "%s%02X%02X", vendor, device, rev);
  64. }
  65.        
  66. static int configure_memory(const unsigned char *buf, 
  67.        struct resource *mem_parent,
  68.        char *name)
  69. {
  70. int len;
  71. u_int8_t c;
  72. int i;
  73. struct resource *res;
  74. len=0;
  75. for (i=0;i<HPEE_MEMORY_MAX_ENT;i++) {
  76. c = get_8(buf+len);
  77. if (NULL != (res = kmalloc(sizeof(struct resource), GFP_KERNEL))) {
  78. int result;
  79. res->name = name;
  80. res->start = mem_parent->start + get_24(buf+len+2);
  81. res->end = res->start + get_16(buf+len+5)*1024;
  82. res->flags = IORESOURCE_MEM;
  83. printk("memory %lx-%lx ", res->start, res->end);
  84. result = request_resource(mem_parent, res);
  85. if (result < 0) {
  86. printk("n" KERN_ERR "EISA Enumerator: failed to claim EISA Bus address space!n");
  87. return result;
  88. }
  89. }
  90.  
  91. len+=7;      
  92. if (!(c & HPEE_MEMORY_MORE)) {
  93. break;
  94. }
  95. }
  96. return len;
  97. }
  98. static int configure_irq(const unsigned char *buf)
  99. {
  100. int len;
  101. u_int8_t c;
  102. int i;
  103. len=0;
  104. for (i=0;i<HPEE_IRQ_MAX_ENT;i++) {
  105. c = get_8(buf+len);
  106. printk("IRQ %d ", c & HPEE_IRQ_CHANNEL_MASK);
  107. if (c & HPEE_IRQ_TRIG_LEVEL) {
  108. eisa_make_irq_level(c & HPEE_IRQ_CHANNEL_MASK);
  109. } else {
  110. eisa_make_irq_edge(c & HPEE_IRQ_CHANNEL_MASK);
  111. }
  112. len+=2; 
  113. /* hpux seems to allow for
  114.  * two bytes of irq data but only defines one of
  115.  * them, I think */
  116. if  (!(c & HPEE_IRQ_MORE)) {
  117. break;
  118. }
  119. }
  120. return len;
  121. }
  122. static int configure_dma(const unsigned char *buf)
  123. {
  124. int len;
  125. u_int8_t c;
  126. int i;
  127. len=0;
  128. for (i=0;i<HPEE_DMA_MAX_ENT;i++) {
  129. c = get_8(buf+len);
  130. printk("DMA %d ", c&HPEE_DMA_CHANNEL_MASK);
  131. /* fixme: maybe initialize the dma channel withthe timing ? */
  132. len+=2;      
  133. if (!(c & HPEE_DMA_MORE)) {
  134. break;
  135. }
  136. }
  137. return len;
  138. }
  139. static int configure_port(const unsigned char *buf, struct resource *io_parent,
  140.      char *board)
  141. {
  142. int len;
  143. u_int8_t c;
  144. int i;
  145. struct resource *res;
  146. int result;
  147. len=0;
  148. for (i=0;i<HPEE_PORT_MAX_ENT;i++) {
  149. c = get_8(buf+len);
  150. if (NULL != (res = kmalloc(sizeof(struct resource), GFP_KERNEL))) {
  151. res->name = board;
  152. res->start = get_16(buf+len+1);
  153. res->end = get_16(buf+len+1)+(c&HPEE_PORT_SIZE_MASK)+1;
  154. res->flags = IORESOURCE_IO;
  155. printk("ioports %lx-%lx ", res->start, res->end);
  156. result = request_resource(io_parent, res);
  157. if (result < 0) {
  158. printk("n" KERN_ERR "EISA Enumerator: failed to claim EISA Bus address space!n");
  159. return result;
  160. }
  161. }
  162. len+=3;      
  163. if (!(c & HPEE_PORT_MORE)) {
  164. break;
  165. }
  166. }
  167. return len;
  168. }
  169. /* byte 1 and 2 is the port number to write
  170.  * and at byte 3 the value to write starts.
  171.  * I assume that there are and- and or- masks
  172.  * here when HPEE_PORT_INIT_MASK is set but I have 
  173.  * not yet encountered this. */
  174. static int configure_port_init(const unsigned char *buf)
  175. {
  176. int len=0;
  177. u_int8_t c;
  178. while (len<HPEE_PORT_INIT_MAX_LEN) {
  179. int s=0;
  180. c = get_8(buf+len);
  181. switch (c & HPEE_PORT_INIT_WIDTH_MASK)  {
  182.  case HPEE_PORT_INIT_WIDTH_BYTE:
  183. s=1;
  184. if (c & HPEE_PORT_INIT_MASK) {
  185. printk("n" KERN_WARNING "port_init: unverified mask attributen");
  186. outb((inb(get_16(buf+len+1) & 
  187.   get_8(buf+len+3)) | 
  188.       get_8(buf+len+4)), get_16(buf+len+1));
  189.       
  190. } else {
  191. outb(get_8(buf+len+3), get_16(buf+len+1));
  192.       
  193. }
  194. break;
  195.  case HPEE_PORT_INIT_WIDTH_WORD:
  196. s=2;
  197. if (c & HPEE_PORT_INIT_MASK) {
  198.   printk(KERN_WARNING "port_init: unverified mask attributen");
  199.        outw((inw(get_16(buf+len+1)) &
  200.      get_16(buf+len+3)) |
  201.     get_16(buf+len+5), 
  202.     get_16(buf+len+1));
  203. } else {
  204. outw(cpu_to_le16(get_16(buf+len+3)), get_16(buf+len+1));
  205. }
  206. break;
  207.  case HPEE_PORT_INIT_WIDTH_DWORD:
  208. s=4;
  209. if (c & HPEE_PORT_INIT_MASK) {
  210.   printk("n" KERN_WARNING "port_init: unverified mask attributen");
  211. outl((inl(get_16(buf+len+1) &
  212.   get_32(buf+len+3)) |
  213.       get_32(buf+len+7)), get_16(buf+len+1));
  214. } else {
  215. outl(cpu_to_le32(get_32(buf+len+3)), get_16(buf+len+1));
  216. }
  217. break;
  218.  default:
  219. printk("n" KERN_ERR "Invalid port init word %02xn", c);
  220. return 0;
  221. }
  222. if (c & HPEE_PORT_INIT_MASK) {   
  223. s*=2;
  224. }
  225. len+=s+3;
  226. if (!(c & HPEE_PORT_INIT_MORE)) {
  227. break;
  228. }
  229. }
  230. return len;
  231. }
  232. static int configure_choise(const unsigned char *buf, u_int8_t *info)
  233. {
  234. int len;
  235. /* theis record contain the value of the functions
  236.  * configuration choises and an info byte which 
  237.  * describes which other records to expect in this 
  238.  * function */
  239. len = get_8(buf);
  240. *info=get_8(buf+len+1);
  241.  
  242. return len+2;
  243. }
  244. static int configure_type_string(const unsigned char *buf) 
  245. {
  246. int len;
  247. /* just skip past the type field */
  248. len = get_8(buf);
  249. if (len > 80) {
  250. printk("n" KERN_ERR "eisa_enumerator: type info field too long (%d, max is 80)n", len);
  251. }
  252. return 1+len;
  253. }
  254. static int configure_function(const unsigned char *buf, int *more) 
  255. {
  256. /* the init field seems to be a two-byte field
  257.  * which is non-zero if there are an other function following
  258.  * I think it is the length of the function def 
  259.  */
  260. *more = get_16(buf);
  261. return 2;
  262. }
  263. static int parse_slot_config(int slot,
  264.      const unsigned char *buf,
  265.      struct eeprom_eisa_slot_info *es, 
  266.      struct resource *io_parent,
  267.      struct resource *mem_parent)
  268. {
  269. int res=0;
  270. int function_len;
  271. unsigned int pos=0;
  272. unsigned int maxlen;
  273. int num_func=0;
  274. u_int8_t flags;
  275. int p0;
  276. char *board;
  277. int id_string_used=0;
  278. if (NULL == (board = kmalloc(8, GFP_KERNEL))) {
  279. return -1;
  280. }
  281. print_eisa_id(board, es->eisa_slot_id);
  282. printk(KERN_INFO "EISA slot %d: %s %s ", 
  283.        slot, board, es->flags&HPEE_FLAG_BOARD_IS_ISA ? "ISA" : "EISA");
  284. maxlen = es->config_data_length < HPEE_MAX_LENGTH ?
  285.  es->config_data_length : HPEE_MAX_LENGTH;
  286. while ((pos < maxlen) && (num_func <= es->num_functions)) {
  287. pos+=configure_function(buf+pos, &function_len); 
  288. if (!function_len) {
  289. break;
  290. }
  291. num_func++;
  292. p0 = pos;
  293. pos += configure_choise(buf+pos, &flags);
  294. if (flags & HPEE_FUNCTION_INFO_F_DISABLED) {
  295. /* function disabled, skip silently */
  296. pos = p0 + function_len;
  297. continue;
  298. }
  299. if (flags & HPEE_FUNCTION_INFO_CFG_FREE_FORM) {
  300. /* I have no idea how to handle this */
  301. printk("function %d have free-form confgiuration, skipping ",
  302. num_func);
  303. pos = p0 + function_len;
  304. continue;
  305. }
  306. /* the ordering of the sections need
  307.  * more investigation.
  308.  * Currently I think that memory comaed before IRQ
  309.  * I assume the order is LSB to MSB in the 
  310.  * info flags 
  311.  * eg type, memory, irq, dma, port, HPEE_PORT_init 
  312.  */
  313. if (flags & HPEE_FUNCTION_INFO_HAVE_TYPE) {
  314. pos += configure_type_string(buf+pos);
  315. }
  316. if (flags & HPEE_FUNCTION_INFO_HAVE_MEMORY) {
  317. id_string_used=1;
  318. pos += configure_memory(buf+pos, mem_parent, board);
  319. if (flags & HPEE_FUNCTION_INFO_HAVE_IRQ) {
  320. pos += configure_irq(buf+pos);
  321. if (flags & HPEE_FUNCTION_INFO_HAVE_DMA) {
  322. pos += configure_dma(buf+pos);
  323. if (flags & HPEE_FUNCTION_INFO_HAVE_PORT) {
  324. id_string_used=1;
  325. pos += configure_port(buf+pos, io_parent, board);
  326. if (flags &  HPEE_FUNCTION_INFO_HAVE_PORT_INIT) {
  327. pos += configure_port_init(buf+pos);
  328. }
  329. if (p0 + function_len < pos) {
  330. printk("n" KERN_ERR "eisa_enumerator: function %d length mis-match "
  331.        "got %d, expected %dn",
  332.        num_func, pos-p0, function_len);
  333. res=-1;
  334. break;
  335. }
  336. pos = p0 + function_len;
  337. }
  338. printk("n");
  339. if (!id_string_used) {
  340. kfree(board);
  341. }
  342. if (pos != es->config_data_length) {
  343. printk(KERN_ERR "eisa_enumerator: config data length mis-match got %d, expected %dn",
  344. pos, es->config_data_length);
  345. res=-1;
  346. }
  347. if (num_func != es->num_functions) {
  348. printk(KERN_ERR "eisa_enumerator: number of functions mis-match got %d, expected %dn",
  349. num_func, es->num_functions);
  350. res=-2;
  351. }
  352. return res;
  353. }
  354. static int init_slot(int slot, struct eeprom_eisa_slot_info *es)
  355. {
  356. unsigned int id;
  357. char id_string[8];
  358. if (!(es->slot_info&HPEE_SLOT_INFO_NO_READID)) {
  359. /* try to read the id of the board in the slot */
  360. id = le32_to_cpu(inl(SLOT2PORT(slot)+EPI));
  361. if (0xffffffff == id) {
  362. /* this board is not here or it does not 
  363.  * support readid 
  364.  */
  365. printk(KERN_ERR "EISA slot %d a configured board was not detected (", 
  366.        slot);
  367. print_eisa_id(id_string, es->eisa_slot_id);
  368. printk(" expected %s)n", id_string);
  369. return -1;
  370. }
  371. if (es->eisa_slot_id != id) {
  372. print_eisa_id(id_string, id);
  373. printk(KERN_ERR "EISA slot %d id mis-match: got %s", 
  374.        slot, id_string);
  375. print_eisa_id(id_string, es->eisa_slot_id);
  376. printk(" expected %s n", id_string);
  377. return -1;
  378. }
  379. }
  380. /* now: we need to enable the board if 
  381.  * it supports enabling and run through
  382.  * the port init sction if present
  383.  * and finally record any interrupt polarity
  384.  */
  385. if (es->slot_features & HPEE_SLOT_FEATURES_ENABLE) {
  386. /* enable board */
  387. outb(0x01| inb(SLOT2PORT(slot)+EPI+4),
  388.      SLOT2PORT(slot)+EPI+4);
  389. }
  390. return 0;
  391. }
  392. int eisa_enumerator(unsigned long eeprom_addr,
  393.     struct resource *io_parent, struct resource *mem_parent) 
  394. {
  395. int i;
  396. struct eeprom_header *eh;
  397. static char eeprom_buf[HPEE_MAX_LENGTH];
  398. for (i=0; i < HPEE_MAX_LENGTH; i++) {
  399. eeprom_buf[i] = gsc_readb(eeprom_addr+i);
  400. }
  401. printk(KERN_INFO "Enumerating EISA busn");
  402.     
  403. eh = (struct eeprom_header*)(eeprom_buf);
  404. for (i=0;i<eh->num_slots;i++) {
  405. struct eeprom_eisa_slot_info *es;
  406. es = (struct eeprom_eisa_slot_info*)
  407. (&eeprom_buf[HPEE_SLOT_INFO(i)]);
  408.         
  409. if (-1==init_slot(i+1, es)) {
  410. return -1;
  411. }
  412. if (es->config_data_offset < HPEE_MAX_LENGTH) {
  413. if (parse_slot_config(i+1, &eeprom_buf[es->config_data_offset],
  414.       es, io_parent, mem_parent)) {
  415. return -1;
  416. }
  417. } else {
  418. printk (KERN_WARNING "EISA EEPROM offset 0x%x out of rangen",es->config_data_offset);
  419. return -1;
  420. }
  421. }
  422. return 0;
  423. }