ppc6lnx.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:14k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2. ppc6lnx.c (c) 2001 Micro Solutions Inc.
  3. Released under the terms of the GNU General Public license
  4. ppc6lnx.c  is a par of the protocol driver for the Micro Solutions
  5. "BACKPACK" parallel port IDE adapter
  6. (Works on Series 6 drives)
  7. */
  8. //***************************************************************************
  9. // PPC 6 Code in C sanitized for LINUX
  10. // Original x86 ASM by Ron, Converted to C by Clive
  11. //***************************************************************************
  12. #define port_stb 1
  13. #define port_afd 2
  14. #define cmd_stb port_afd
  15. #define port_init 4
  16. #define data_stb port_init
  17. #define port_sel 8
  18. #define port_int 16
  19. #define port_dir 0x20
  20. #define ECR_EPP 0x80
  21. #define ECR_BI 0x20
  22. //***************************************************************************
  23. //  60772 Commands
  24. #define ACCESS_REG 0x00
  25. #define ACCESS_PORT 0x40
  26. #define ACCESS_READ 0x00
  27. #define ACCESS_WRITE 0x20
  28. //  60772 Command Prefix
  29. #define CMD_PREFIX_SET 0xe0 // Special command that modifies the next command's operation
  30. #define CMD_PREFIX_RESET 0xc0 // Resets current cmd modifier reg bits
  31.  #define PREFIX_IO16 0x01 // perform 16-bit wide I/O
  32.  #define PREFIX_FASTWR 0x04 // enable PPC mode fast-write
  33.  #define PREFIX_BLK 0x08 // enable block transfer mode
  34. // 60772 Registers
  35. #define REG_STATUS 0x00 // status register
  36.  #define STATUS_IRQA 0x01 // Peripheral IRQA line
  37.  #define STATUS_EEPROM_DO 0x40 // Serial EEPROM data bit
  38. #define REG_VERSION 0x01 // PPC version register (read)
  39. #define REG_HWCFG 0x02 // Hardware Config register
  40. #define REG_RAMSIZE 0x03 // Size of RAM Buffer
  41.  #define RAMSIZE_128K 0x02
  42. #define REG_EEPROM 0x06 // EEPROM control register
  43.  #define EEPROM_SK 0x01 // eeprom SK bit
  44.  #define EEPROM_DI 0x02 // eeprom DI bit
  45.  #define EEPROM_CS 0x04 // eeprom CS bit
  46.  #define EEPROM_EN 0x08 // eeprom output enable
  47. #define REG_BLKSIZE 0x08 // Block transfer len (24 bit)
  48. //***************************************************************************
  49. typedef struct ppc_storage {
  50. u16 lpt_addr; // LPT base address
  51. u8 ppc_id;
  52. u8 mode; // operating mode
  53. // 0 = PPC Uni SW
  54. // 1 = PPC Uni FW
  55. // 2 = PPC Bi SW
  56. // 3 = PPC Bi FW
  57. // 4 = EPP Byte
  58. // 5 = EPP Word
  59. // 6 = EPP Dword
  60. u8 ppc_flags;
  61. u8 org_data; // original LPT data port contents
  62. u8 org_ctrl; // original LPT control port contents
  63. u8 cur_ctrl; // current control port contents
  64. } PPC;
  65. //***************************************************************************
  66. // ppc_flags
  67. #define fifo_wait 0x10
  68. //***************************************************************************
  69. // DONT CHANGE THESE LEST YOU BREAK EVERYTHING - BIT FIELD DEPENDENCIES
  70. #define PPCMODE_UNI_SW 0
  71. #define PPCMODE_UNI_FW 1
  72. #define PPCMODE_BI_SW 2
  73. #define PPCMODE_BI_FW 3
  74. #define PPCMODE_EPP_BYTE 4
  75. #define PPCMODE_EPP_WORD 5
  76. #define PPCMODE_EPP_DWORD 6
  77. //***************************************************************************
  78. static int ppc6_select(PPC *ppc);
  79. static void ppc6_deselect(PPC *ppc);
  80. static void ppc6_send_cmd(PPC *ppc, u8 cmd);
  81. static void ppc6_wr_data_byte(PPC *ppc, u8 data);
  82. static u8 ppc6_rd_data_byte(PPC *ppc);
  83. static u8 ppc6_rd_port(PPC *ppc, u8 port);
  84. static void ppc6_wr_port(PPC *ppc, u8 port, u8 data);
  85. static void ppc6_rd_data_blk(PPC *ppc, u8 *data, long count);
  86. static void ppc6_wait_for_fifo(PPC *ppc);
  87. static void ppc6_wr_data_blk(PPC *ppc, u8 *data, long count);
  88. static void ppc6_rd_port16_blk(PPC *ppc, u8 port, u8 *data, long length);
  89. static void ppc6_wr_port16_blk(PPC *ppc, u8 port, u8 *data, long length);
  90. static void ppc6_wr_extout(PPC *ppc, u8 regdata);
  91. static int ppc6_open(PPC *ppc);
  92. static void ppc6_close(PPC *ppc);
  93. //***************************************************************************
  94. static int ppc6_select(PPC *ppc)
  95. {
  96. u8 i, j, k;
  97. i = inb(ppc->lpt_addr + 1);
  98. if (i & 1)
  99. outb(i, ppc->lpt_addr + 1);
  100. ppc->org_data = inb(ppc->lpt_addr);
  101. ppc->org_ctrl = inb(ppc->lpt_addr + 2) & 0x5F; // readback ctrl
  102. ppc->cur_ctrl = ppc->org_ctrl;
  103. ppc->cur_ctrl |= port_sel;
  104. outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
  105. if (ppc->org_data == 'b')
  106. outb('x', ppc->lpt_addr);
  107. outb('b', ppc->lpt_addr);
  108. outb('p', ppc->lpt_addr);
  109. outb(ppc->ppc_id, ppc->lpt_addr);
  110. outb(~ppc->ppc_id,ppc->lpt_addr);
  111. ppc->cur_ctrl &= ~port_sel;
  112. outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
  113. ppc->cur_ctrl = (ppc->cur_ctrl & port_int) | port_init;
  114. outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
  115. i = ppc->mode & 0x0C;
  116. if (i == 0)
  117. i = (ppc->mode & 2) | 1;
  118. outb(i, ppc->lpt_addr);
  119. ppc->cur_ctrl |= port_sel;
  120. outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
  121. // DELAY
  122. ppc->cur_ctrl |= port_afd;
  123. outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
  124. j = ((i & 0x08) << 4) | ((i & 0x07) << 3);
  125. k = inb(ppc->lpt_addr + 1) & 0xB8;
  126. if (j == k)
  127. {
  128. ppc->cur_ctrl &= ~port_afd;
  129. outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
  130. k = (inb(ppc->lpt_addr + 1) & 0xB8) ^ 0xB8;
  131. if (j == k)
  132. {
  133. if (i & 4) // EPP
  134. ppc->cur_ctrl &= ~(port_sel | port_init);
  135. else // PPC/ECP
  136. ppc->cur_ctrl &= ~port_sel;
  137. outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
  138. return(1);
  139. }
  140. }
  141. outb(ppc->org_ctrl, ppc->lpt_addr + 2);
  142. outb(ppc->org_data, ppc->lpt_addr);
  143. return(0); // FAIL
  144. }
  145. //***************************************************************************
  146. static void ppc6_deselect(PPC *ppc)
  147. {
  148. if (ppc->mode & 4) // EPP
  149. ppc->cur_ctrl |= port_init;
  150. else // PPC/ECP
  151. ppc->cur_ctrl |= port_sel;
  152. outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
  153. outb(ppc->org_data, ppc->lpt_addr);
  154. outb((ppc->org_ctrl | port_sel), ppc->lpt_addr + 2);
  155. outb(ppc->org_ctrl, ppc->lpt_addr + 2);
  156. }
  157. //***************************************************************************
  158. static void ppc6_send_cmd(PPC *ppc, u8 cmd)
  159. {
  160. switch(ppc->mode)
  161. {
  162. case PPCMODE_UNI_SW :
  163. case PPCMODE_UNI_FW :
  164. case PPCMODE_BI_SW :
  165. case PPCMODE_BI_FW :
  166. {
  167. outb(cmd, ppc->lpt_addr);
  168. ppc->cur_ctrl ^= cmd_stb;
  169. outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
  170. break;
  171. }
  172. case PPCMODE_EPP_BYTE :
  173. case PPCMODE_EPP_WORD :
  174. case PPCMODE_EPP_DWORD :
  175. {
  176. outb(cmd, ppc->lpt_addr + 3);
  177. break;
  178. }
  179. }
  180. }
  181. //***************************************************************************
  182. static void ppc6_wr_data_byte(PPC *ppc, u8 data)
  183. {
  184. switch(ppc->mode)
  185. {
  186. case PPCMODE_UNI_SW :
  187. case PPCMODE_UNI_FW :
  188. case PPCMODE_BI_SW :
  189. case PPCMODE_BI_FW :
  190. {
  191. outb(data, ppc->lpt_addr);
  192. ppc->cur_ctrl ^= data_stb;
  193. outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
  194. break;
  195. }
  196. case PPCMODE_EPP_BYTE :
  197. case PPCMODE_EPP_WORD :
  198. case PPCMODE_EPP_DWORD :
  199. {
  200. outb(data, ppc->lpt_addr + 4);
  201. break;
  202. }
  203. }
  204. }
  205. //***************************************************************************
  206. static u8 ppc6_rd_data_byte(PPC *ppc)
  207. {
  208. u8 data = 0;
  209. switch(ppc->mode)
  210. {
  211. case PPCMODE_UNI_SW :
  212. case PPCMODE_UNI_FW :
  213. {
  214. ppc->cur_ctrl = (ppc->cur_ctrl & ~port_stb) ^ data_stb;
  215. outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
  216. // DELAY
  217. data = inb(ppc->lpt_addr + 1);
  218. data = ((data & 0x80) >> 1) | ((data & 0x38) >> 3);
  219. ppc->cur_ctrl |= port_stb;
  220. outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
  221. // DELAY
  222. data |= inb(ppc->lpt_addr + 1) & 0xB8;
  223. break;
  224. }
  225. case PPCMODE_BI_SW :
  226. case PPCMODE_BI_FW :
  227. {
  228. ppc->cur_ctrl |= port_dir;
  229. outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
  230. ppc->cur_ctrl = (ppc->cur_ctrl | port_stb) ^ data_stb;
  231. outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
  232. data = inb(ppc->lpt_addr);
  233. ppc->cur_ctrl &= ~port_stb;
  234. outb(ppc->cur_ctrl,ppc->lpt_addr + 2);
  235. ppc->cur_ctrl &= ~port_dir;
  236. outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
  237. break;
  238. }
  239. case PPCMODE_EPP_BYTE :
  240. case PPCMODE_EPP_WORD :
  241. case PPCMODE_EPP_DWORD :
  242. {
  243. outb((ppc->cur_ctrl | port_dir),ppc->lpt_addr + 2);
  244. data = inb(ppc->lpt_addr + 4);
  245. outb(ppc->cur_ctrl,ppc->lpt_addr + 2);
  246. break;
  247. }
  248. }
  249. return(data);
  250. }
  251. //***************************************************************************
  252. static u8 ppc6_rd_port(PPC *ppc, u8 port)
  253. {
  254. ppc6_send_cmd(ppc,(u8)(port | ACCESS_PORT | ACCESS_READ));
  255. return(ppc6_rd_data_byte(ppc));
  256. }
  257. //***************************************************************************
  258. static void ppc6_wr_port(PPC *ppc, u8 port, u8 data)
  259. {
  260. ppc6_send_cmd(ppc,(u8)(port | ACCESS_PORT | ACCESS_WRITE));
  261. ppc6_wr_data_byte(ppc, data);
  262. }
  263. //***************************************************************************
  264. static void ppc6_rd_data_blk(PPC *ppc, u8 *data, long count)
  265. {
  266. switch(ppc->mode)
  267. {
  268. case PPCMODE_UNI_SW :
  269. case PPCMODE_UNI_FW :
  270. {
  271. while(count)
  272. {
  273. u8 d;
  274. ppc->cur_ctrl = (ppc->cur_ctrl & ~port_stb) ^ data_stb;
  275. outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
  276. // DELAY
  277. d = inb(ppc->lpt_addr + 1);
  278. d = ((d & 0x80) >> 1) | ((d & 0x38) >> 3);
  279. ppc->cur_ctrl |= port_stb;
  280. outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
  281. // DELAY
  282. d |= inb(ppc->lpt_addr + 1) & 0xB8;
  283. *data++ = d;
  284. count--;
  285. }
  286. break;
  287. }
  288. case PPCMODE_BI_SW :
  289. case PPCMODE_BI_FW :
  290. {
  291. ppc->cur_ctrl |= port_dir;
  292. outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
  293. ppc->cur_ctrl |= port_stb;
  294. while(count)
  295. {
  296. ppc->cur_ctrl ^= data_stb;
  297. outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
  298. *data++ = inb(ppc->lpt_addr);
  299. count--;
  300. }
  301. ppc->cur_ctrl &= ~port_stb;
  302. outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
  303. ppc->cur_ctrl &= ~port_dir;
  304. outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
  305. break;
  306. }
  307. case PPCMODE_EPP_BYTE :
  308. {
  309. outb((ppc->cur_ctrl | port_dir), ppc->lpt_addr + 2);
  310. // DELAY
  311. while(count)
  312. {
  313. *data++ = inb(ppc->lpt_addr + 4);
  314. count--;
  315. }
  316. outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
  317. break;
  318. }
  319. case PPCMODE_EPP_WORD :
  320. {
  321. outb((ppc->cur_ctrl | port_dir), ppc->lpt_addr + 2);
  322. // DELAY
  323. while(count > 1)
  324. {
  325. *((u16 *)data) = inw(ppc->lpt_addr + 4);
  326. data  += 2;
  327. count -= 2;
  328. }
  329. while(count)
  330. {
  331. *data++ = inb(ppc->lpt_addr + 4);
  332. count--;
  333. }
  334. outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
  335. break;
  336. }
  337. case PPCMODE_EPP_DWORD :
  338. {
  339. outb((ppc->cur_ctrl | port_dir),ppc->lpt_addr + 2);
  340. // DELAY
  341. while(count > 3)
  342. {
  343. *((u32 *)data) = inl(ppc->lpt_addr + 4);
  344. data  += 4;
  345. count -= 4;
  346. }
  347. while(count)
  348. {
  349. *data++ = inb(ppc->lpt_addr + 4);
  350. count--;
  351. }
  352. outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
  353. break;
  354. }
  355. }
  356. }
  357. //***************************************************************************
  358. static void ppc6_wait_for_fifo(PPC *ppc)
  359. {
  360. int i;
  361. if (ppc->ppc_flags & fifo_wait)
  362. {
  363. for(i=0; i<20; i++)
  364. inb(ppc->lpt_addr + 1);
  365. }
  366. }
  367. //***************************************************************************
  368. static void ppc6_wr_data_blk(PPC *ppc, u8 *data, long count)
  369. {
  370. switch(ppc->mode)
  371. {
  372. case PPCMODE_UNI_SW :
  373. case PPCMODE_BI_SW :
  374. {
  375. while(count--)
  376. {
  377. outb(*data++, ppc->lpt_addr);
  378. ppc->cur_ctrl ^= data_stb;
  379. outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
  380. }
  381. break;
  382. }
  383. case PPCMODE_UNI_FW :
  384. case PPCMODE_BI_FW :
  385. {
  386. u8 this, last;
  387. ppc6_send_cmd(ppc,(CMD_PREFIX_SET | PREFIX_FASTWR));
  388. ppc->cur_ctrl |= port_stb;
  389. outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
  390. last = *data;
  391. outb(last, ppc->lpt_addr);
  392. while(count)
  393. {
  394. this = *data++;
  395. count--;
  396. if (this == last)
  397. {
  398. ppc->cur_ctrl ^= data_stb;
  399. outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
  400. }
  401. else
  402. {
  403. outb(this, ppc->lpt_addr);
  404. last = this;
  405. }
  406. }
  407. ppc->cur_ctrl &= ~port_stb;
  408. outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
  409. ppc6_send_cmd(ppc,(CMD_PREFIX_RESET | PREFIX_FASTWR));
  410. break;
  411. }
  412. case PPCMODE_EPP_BYTE :
  413. {
  414. while(count)
  415. {
  416. outb(*data++,ppc->lpt_addr + 4);
  417. count--;
  418. }
  419. ppc6_wait_for_fifo(ppc);
  420. break;
  421. }
  422. case PPCMODE_EPP_WORD :
  423. {
  424. while(count > 1)
  425. {
  426. outw(*((u16 *)data),ppc->lpt_addr + 4);
  427. data  += 2;
  428. count -= 2;
  429. }
  430. while(count)
  431. {
  432. outb(*data++,ppc->lpt_addr + 4);
  433. count--;
  434. }
  435. ppc6_wait_for_fifo(ppc);
  436. break;
  437. }
  438. case PPCMODE_EPP_DWORD :
  439. {
  440. while(count > 3)
  441. {
  442. outl(*((u32 *)data),ppc->lpt_addr + 4);
  443. data  += 4;
  444. count -= 4;
  445. }
  446. while(count)
  447. {
  448. outb(*data++,ppc->lpt_addr + 4);
  449. count--;
  450. }
  451. ppc6_wait_for_fifo(ppc);
  452. break;
  453. }
  454. }
  455. }
  456. //***************************************************************************
  457. static void ppc6_rd_port16_blk(PPC *ppc, u8 port, u8 *data, long length)
  458. {
  459. length = length << 1;
  460. ppc6_send_cmd(ppc, (REG_BLKSIZE | ACCESS_REG | ACCESS_WRITE));
  461. ppc6_wr_data_byte(ppc,(u8)length);
  462. ppc6_wr_data_byte(ppc,(u8)(length >> 8));
  463. ppc6_wr_data_byte(ppc,0);
  464. ppc6_send_cmd(ppc, (CMD_PREFIX_SET | PREFIX_IO16 | PREFIX_BLK));
  465. ppc6_send_cmd(ppc, (u8)(port | ACCESS_PORT | ACCESS_READ));
  466. ppc6_rd_data_blk(ppc, data, length);
  467. ppc6_send_cmd(ppc, (CMD_PREFIX_RESET | PREFIX_IO16 | PREFIX_BLK));
  468. }
  469. //***************************************************************************
  470. static void ppc6_wr_port16_blk(PPC *ppc, u8 port, u8 *data, long length)
  471. {
  472. length = length << 1;
  473. ppc6_send_cmd(ppc, (REG_BLKSIZE | ACCESS_REG | ACCESS_WRITE));
  474. ppc6_wr_data_byte(ppc,(u8)length);
  475. ppc6_wr_data_byte(ppc,(u8)(length >> 8));
  476. ppc6_wr_data_byte(ppc,0);
  477. ppc6_send_cmd(ppc, (CMD_PREFIX_SET | PREFIX_IO16 | PREFIX_BLK));
  478. ppc6_send_cmd(ppc, (u8)(port | ACCESS_PORT | ACCESS_WRITE));
  479. ppc6_wr_data_blk(ppc, data, length);
  480. ppc6_send_cmd(ppc, (CMD_PREFIX_RESET | PREFIX_IO16 | PREFIX_BLK));
  481. }
  482. //***************************************************************************
  483. static void ppc6_wr_extout(PPC *ppc, u8 regdata)
  484. {
  485. ppc6_send_cmd(ppc,(REG_VERSION | ACCESS_REG | ACCESS_WRITE));
  486. ppc6_wr_data_byte(ppc, (u8)((regdata & 0x03) << 6));
  487. }
  488. //***************************************************************************
  489. static int ppc6_open(PPC *ppc)
  490. {
  491. int ret;
  492. ret = ppc6_select(ppc);
  493. if (ret == 0)
  494. return(ret);
  495. ppc->ppc_flags &= ~fifo_wait;
  496. ppc6_send_cmd(ppc, (ACCESS_REG | ACCESS_WRITE | REG_RAMSIZE));
  497. ppc6_wr_data_byte(ppc, RAMSIZE_128K);
  498. ppc6_send_cmd(ppc, (ACCESS_REG | ACCESS_READ | REG_VERSION));
  499. if ((ppc6_rd_data_byte(ppc) & 0x3F) == 0x0C)
  500. ppc->ppc_flags |= fifo_wait;
  501. return(ret);
  502. }
  503. //***************************************************************************
  504. static void ppc6_close(PPC *ppc)
  505. {
  506. ppc6_deselect(ppc);
  507. }
  508. //***************************************************************************
  509. MODULE_LICENSE("GPL");