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

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * $Id$
  3.  *
  4.  * Device driver for the PCMCIA controller module of the
  5.  * Hitachi HD64465 handheld companion chip.
  6.  *
  7.  * Note that the HD64465 provides a very thin PCMCIA host bridge
  8.  * layer, requiring a lot of the work of supporting cards to be
  9.  * performed by the processor.  For example: mapping of card
  10.  * interrupts to processor IRQs is done by IRQ demuxing software;
  11.  * IO and memory mappings are fixed; setting voltages according
  12.  * to card Voltage Select pins etc is done in software.
  13.  *
  14.  * Note also that this driver uses only the simple, fixed,
  15.  * 16MB, 16-bit wide mappings to PCMCIA spaces defined by the
  16.  * HD64465.  Larger mappings, smaller mappings, or mappings of
  17.  * different width to the same socket, are all possible only by
  18.  * involving the SH7750's MMU, which is considered unnecessary here.
  19.  * The downside is that it may be possible for some drivers to
  20.  * break because they need or expect 8-bit mappings.
  21.  *
  22.  * This driver currently supports only the following configuration:
  23.  * SH7750 CPU, HD64465, TPS2206 voltage control chip.
  24.  *
  25.  * by Greg Banks <gbanks@pocketpenguins.com>
  26.  * (c) 2000 PocketPenguins Inc
  27.  *
  28.  */
  29. #include <linux/types.h>
  30. #include <linux/module.h>
  31. #include <linux/init.h>
  32. #include <linux/string.h>
  33. #include <linux/kernel.h>
  34. #include <linux/ioport.h>
  35. #include <linux/mm.h>
  36. #include <linux/vmalloc.h>
  37. #include <asm/errno.h>
  38. #include <linux/irq.h>
  39. #include <asm/io.h>
  40. #include <asm/hd64465.h>
  41. #include <pcmcia/version.h>
  42. #include <pcmcia/cs_types.h>
  43. #include <pcmcia/cs.h>
  44. #include <pcmcia/ss.h>
  45. #include <pcmcia/bulkmem.h>
  46. #include <pcmcia/cistpl.h>
  47. #include "cs_internal.h"
  48. #define MODNAME "hd64465_ss"
  49. /* #define HD64465_DEBUG 1 */
  50. #ifndef HD64465_DEBUG
  51. #define HD64465_DEBUG 0
  52. #endif
  53. #if HD64465_DEBUG
  54. #define DPRINTK(args...) printk(MODNAME ": " args)
  55. #else
  56. #define DPRINTK(args...)
  57. #endif
  58. extern int hd64465_io_debug;
  59. /*============================================================*/
  60. #define HS_IO_MAP_SIZE  (64*1024)
  61. typedef struct hs_socket_t
  62. {
  63.     u_int         irq;
  64.     u_long        mem_base;
  65.     u_long        mem_length;
  66.     void      (*handler)(void *info, u_int events);
  67.     void          *handler_info;
  68.     u_int         pending_events;
  69.     u_int         ctrl_base;
  70.     socket_state_t   state;
  71.     pccard_io_map      io_maps[MAX_IO_WIN];
  72.     pccard_mem_map   mem_maps[MAX_WIN];
  73.     struct vm_struct *io_vma;    /* allocated kernel vm for mapping IO space */
  74. } hs_socket_t;
  75. #define HS_MAX_SOCKETS 2
  76. static hs_socket_t hs_sockets[HS_MAX_SOCKETS];
  77. static spinlock_t hs_pending_event_lock = SPIN_LOCK_UNLOCKED;
  78. /* Calculate socket number from ptr into hs_sockets[] */
  79. #define hs_sockno(sp)  (sp - hs_sockets)
  80. static socket_cap_t hs_socket_cap =
  81. {
  82.     SS_CAP_PCCARD        /* support 16 bit cards */
  83.     |SS_CAP_STATIC_MAP      /* mappings are fixed in host memory */
  84.     ,
  85.     0xffde/*0xffff*/,      /* IRQs mapped in s/w so can do any, really */
  86.     HD64465_PCC_WINDOW,     /* 16MB fixed window size */
  87.     0,               /* no PCI support */
  88.     0,               /* no CardBus support */
  89.     0               /* no bus operations needed */
  90. };
  91. #define hs_in(sp, r)     inb((sp)->ctrl_base + (r))
  92. #define hs_out(sp, v, r)    outb(v, (sp)->ctrl_base + (r))
  93. /* translate a boolean value to a bit in a register */
  94. #define bool_to_regbit(sp, r, bi, bo)     
  95.     do {                        
  96.      unsigned short v = hs_in(sp, r);    
  97. if (bo)                    
  98.     v |= (bi);               
  99. else                    
  100.     v &= ~(bi);               
  101. hs_out(sp, v, r);             
  102.     } while(0)
  103.     
  104. /* register offsets from HD64465_REG_PCC[01]ISR */
  105. #define ISR  0x0
  106. #define GCR  0x2
  107. #define CSCR  0x4
  108. #define CSCIER  0x6
  109. #define SCR  0x8
  110. /* Mask and values for CSCIER register */
  111. #define IER_MASK    0x80
  112. #define IER_ON     0x3f     /* interrupts on */
  113. #define IER_OFF     0x00     /* interrupts off */
  114. /*============================================================*/
  115. #if HD64465_DEBUG > 10
  116. static void cis_hex_dump(const unsigned char *x, int len)
  117. {
  118.      int i;
  119.      for (i=0 ; i<len ; i++)
  120. {
  121.     if (!(i & 0xf))
  122.      printk("n%08x", (unsigned)(x + i));
  123.     printk(" %02x", *(volatile unsigned short*)x);
  124.     x += 2;
  125. }
  126. printk("n");
  127. }
  128. #endif
  129. /*============================================================*/
  130. /*
  131.  * This code helps create the illusion that the IREQ line from
  132.  * the PC card is mapped to one of the CPU's IRQ lines by the
  133.  * host bridge hardware (which is how every host bridge *except*
  134.  * the HD64465 works).  In particular, it supports enabling
  135.  * and disabling the IREQ line by code which knows nothing
  136.  * about the host bridge (e.g. device drivers, IDE code) using
  137.  * the request_irq(), free_irq(), probe_irq_on() and probe_irq_off()
  138.  * functions.  Also, it supports sharing the mapped IRQ with
  139.  * real hardware IRQs from the -IRL0-3 lines.
  140.  */
  141. #define HS_NUM_MAPPED_IRQS  16 /* Limitation of the PCMCIA code */
  142. static struct
  143. {
  144.     /* index is mapped irq number */
  145.     hs_socket_t *sock;
  146.     hw_irq_controller *old_handler;
  147. } hs_mapped_irq[HS_NUM_MAPPED_IRQS];
  148. static void hs_socket_enable_ireq(hs_socket_t *sp)
  149. {
  150.      unsigned short cscier;
  151.      DPRINTK("hs_socket_enable_ireq(sock=%d)n", hs_sockno(sp));
  152.      cscier = hs_in(sp, CSCIER);
  153. cscier &= ~HD64465_PCCCSCIER_PIREQE_MASK;
  154.      cscier |= HD64465_PCCCSCIER_PIREQE_LEVEL;
  155. hs_out(sp, cscier, CSCIER);
  156. }
  157. static void hs_socket_disable_ireq(hs_socket_t *sp)
  158. {
  159.      unsigned short cscier;
  160.      DPRINTK("hs_socket_disable_ireq(sock=%d)n", hs_sockno(sp));
  161.      cscier = hs_in(sp, CSCIER);
  162. cscier &= ~HD64465_PCCCSCIER_PIREQE_MASK;
  163. hs_out(sp, cscier, CSCIER);
  164. }
  165. static unsigned int hs_startup_irq(unsigned int irq)
  166. {
  167. hs_socket_enable_ireq(hs_mapped_irq[irq].sock);
  168. hs_mapped_irq[irq].old_handler->startup(irq);
  169. return 0;
  170. }
  171. static void hs_shutdown_irq(unsigned int irq)
  172. {
  173. hs_socket_disable_ireq(hs_mapped_irq[irq].sock);
  174. hs_mapped_irq[irq].old_handler->shutdown(irq);
  175. }
  176. static void hs_enable_irq(unsigned int irq)
  177. {
  178. hs_socket_enable_ireq(hs_mapped_irq[irq].sock);
  179. hs_mapped_irq[irq].old_handler->enable(irq);
  180. }
  181. static void hs_disable_irq(unsigned int irq)
  182. {
  183. hs_socket_disable_ireq(hs_mapped_irq[irq].sock);
  184. hs_mapped_irq[irq].old_handler->disable(irq);
  185. }
  186. extern struct hw_interrupt_type no_irq_type;
  187. static void hs_mask_and_ack_irq(unsigned int irq)
  188. {
  189. hs_socket_disable_ireq(hs_mapped_irq[irq].sock);
  190. /* ack_none() spuriously complains about an unexpected IRQ */
  191. if (hs_mapped_irq[irq].old_handler != &no_irq_type)
  192.     hs_mapped_irq[irq].old_handler->ack(irq);
  193. }
  194. static void hs_end_irq(unsigned int irq)
  195. {
  196. hs_socket_enable_ireq(hs_mapped_irq[irq].sock);
  197. hs_mapped_irq[irq].old_handler->end(irq);
  198. }
  199. static struct hw_interrupt_type hd64465_ss_irq_type = {
  200. typename: "PCMCIA-IRQ",
  201. startup: hs_startup_irq,
  202. shutdown: hs_shutdown_irq,
  203. enable: hs_enable_irq,
  204. disable: hs_disable_irq,
  205. ack: hs_mask_and_ack_irq,
  206. end: hs_end_irq
  207. };
  208. /* 
  209.  * This function should only ever be called with interrupts disabled.
  210.  */
  211. static void hs_map_irq(hs_socket_t *sp, unsigned int irq)
  212. {
  213.      DPRINTK("hs_map_irq(sock=%d irq=%d)n", hs_sockno(sp), irq);
  214. if (irq >= HS_NUM_MAPPED_IRQS)
  215.     return;
  216.      hs_mapped_irq[irq].sock = sp;
  217. /* insert ourselves as the irq controller */
  218. hs_mapped_irq[irq].old_handler = irq_desc[irq].handler;
  219. irq_desc[irq].handler = &hd64465_ss_irq_type;
  220. }
  221. /* 
  222.  * This function should only ever be called with interrupts disabled.
  223.  */
  224. static void hs_unmap_irq(hs_socket_t *sp, unsigned int irq)
  225. {
  226.      DPRINTK("hs_unmap_irq(sock=%d irq=%d)n", hs_sockno(sp), irq);
  227. if (irq >= HS_NUM_MAPPED_IRQS)
  228.     return;
  229. /* restore the original irq controller */
  230. irq_desc[irq].handler = hs_mapped_irq[irq].old_handler;
  231. }
  232. /*============================================================*/
  233. /*
  234.  * Set Vpp and Vcc (in tenths of a Volt).  Does not
  235.  * support the hi-Z state.
  236.  *
  237.  * Note, this assumes the board uses a TPS2206 chip to control
  238.  * the Vcc and Vpp voltages to the hs_sockets.  If your board
  239.  * uses the MIC2563 (also supported by the HD64465) then you
  240.  * will have to modify this function.
  241.  */
  242.                              /* 0V   3.3V  5.5V */
  243. static const u_char hs_tps2206_avcc[3] = { 0x00, 0x04, 0x08 };
  244. static const u_char hs_tps2206_bvcc[3] = { 0x00, 0x80, 0x40 };
  245. static int hs_set_voltages(hs_socket_t *sp, int Vcc, int Vpp)
  246. {
  247.      u_int psr;
  248. u_int vcci = 0;
  249. u_int sock = hs_sockno(sp);
  250.      DPRINTK("hs_set_voltage(%d, %d, %d)n", sock, Vcc, Vpp);
  251.      switch (Vcc)
  252. {
  253. case 0:  vcci = 0; break;
  254. case 33: vcci = 1; break;
  255. case 50: vcci = 2; break;
  256. default: return 0;
  257. }
  258.      /* Note: Vpp = 120 not supported -- Greg Banks */
  259. if (Vpp != 0 && Vpp != Vcc)
  260.     return 0;
  261. /* The PSR register holds 8 of the 9 bits which control
  262.  * the TPS2206 via its serial interface.
  263.  */
  264. psr = inw(HD64465_REG_PCCPSR);
  265. switch (sock)
  266. {
  267. case 0:
  268.     psr &= 0x0f;
  269.     psr |= hs_tps2206_avcc[vcci];
  270.     psr |= (Vpp == 0 ? 0x00 : 0x02);
  271.     break;
  272. case 1:
  273.     psr &= 0xf0;
  274.     psr |= hs_tps2206_bvcc[vcci];
  275.     psr |= (Vpp == 0 ? 0x00 : 0x20);
  276.     break;
  277. };
  278. outw(psr, HD64465_REG_PCCPSR);
  279. return 1;
  280. }
  281. /*============================================================*/
  282. /*
  283.  * Drive the RESET line to the card.
  284.  */
  285. static void hs_reset_socket(hs_socket_t *sp, int on)
  286. {
  287.      unsigned short v;
  288. v = hs_in(sp, GCR);
  289. if (on)
  290.     v |= HD64465_PCCGCR_PCCR;
  291. else
  292.     v &= ~HD64465_PCCGCR_PCCR;
  293. hs_out(sp, v, GCR);
  294. }
  295. /*============================================================*/
  296. static int hs_init(unsigned int sock)
  297. {
  298.      hs_socket_t *sp = &hs_sockets[sock];
  299.      DPRINTK("hs_init(%d)n", sock);
  300. sp->pending_events = 0;
  301. sp->state.Vcc = 0;
  302. sp->state.Vpp = 0;
  303. hs_set_voltages(sp, 0, 0);
  304. return 0;
  305. }
  306. /*============================================================*/
  307. static int hs_suspend(unsigned int sock)
  308. {
  309.      DPRINTK("hs_suspend(%d)n", sock);
  310.      /* TODO */
  311. return 0;
  312. }
  313. /*============================================================*/
  314. static int hs_register_callback(unsigned int sock,
  315.          void (*handler)(void *, unsigned int), void * info)
  316. {
  317.      hs_socket_t *sp = &hs_sockets[sock];
  318.      DPRINTK("hs_register_callback(%d)n", sock);
  319. sp->handler = handler;
  320. sp->handler_info = info;
  321. if (handler == 0) {
  322.     MOD_DEC_USE_COUNT;
  323. } else {
  324.     MOD_INC_USE_COUNT;
  325. }
  326. return 0;
  327. }
  328. /*============================================================*/
  329. static int hs_inquire_socket(unsigned int sock, socket_cap_t *cap)
  330. {
  331.      DPRINTK("hs_inquire_socket(%d)n", sock);
  332. *cap = hs_socket_cap;
  333. return 0;
  334. }
  335. /*============================================================*/
  336. static int hs_get_status(unsigned int sock, u_int *value)
  337. {
  338.      hs_socket_t *sp = &hs_sockets[sock];
  339.      unsigned int isr;
  340. u_int status = 0;
  341. isr = hs_in(sp, ISR);
  342.      /* Card is seated and powered when *both* CD pins are low */
  343. if ((isr & HD64465_PCCISR_PCD_MASK) == 0)
  344.      {
  345.     status |= SS_DETECT;    /* card present */
  346.     switch (isr & HD64465_PCCISR_PBVD_MASK)
  347.     {
  348.     case HD64465_PCCISR_PBVD_BATGOOD:   
  349. break;
  350.     case HD64465_PCCISR_PBVD_BATWARN:
  351. status |= SS_BATWARN;
  352. break;
  353.     default:
  354. status |= SS_BATDEAD;
  355. break;
  356.     }
  357.     if (isr & HD64465_PCCISR_PREADY)
  358. status |= SS_READY;
  359.     if (isr & HD64465_PCCISR_PMWP)
  360. status |= SS_WRPROT;
  361.     /* Voltage Select pins interpreted as per Table 4-5 of the std.
  362.      * Assuming we have the TPS2206, the socket is a "Low Voltage
  363.      * key, 3.3V and 5V available, no X.XV available".
  364.      */
  365.     switch (isr & (HD64465_PCCISR_PVS2|HD64465_PCCISR_PVS1))
  366.     {
  367.     case HD64465_PCCISR_PVS1:
  368.      printk(KERN_NOTICE MODNAME ": cannot handle X.XV card, ignoredn");
  369. status = 0;
  370.      break;
  371.     case 0:
  372.     case HD64465_PCCISR_PVS2:
  373.           /* 3.3V */
  374.           status |= SS_3VCARD;
  375.      break;
  376.     case HD64465_PCCISR_PVS2|HD64465_PCCISR_PVS1:
  377.      /* 5V */
  378.      break;
  379.     }
  380.     /* TODO: SS_POWERON */
  381.     /* TODO: SS_STSCHG */
  382.      }
  383.      DPRINTK("hs_get_status(%d) = %xn", sock, status);
  384. *value = status;
  385. return 0;
  386. }
  387. /*============================================================*/
  388. static int hs_get_socket(unsigned int sock, socket_state_t *state)
  389. {
  390.      hs_socket_t *sp = &hs_sockets[sock];
  391.      DPRINTK("hs_get_socket(%d)n", sock);
  392. *state = sp->state;
  393. return 0;
  394. }
  395. /*============================================================*/
  396. static int hs_set_socket(unsigned int sock, socket_state_t *state)
  397. {
  398.      hs_socket_t *sp = &hs_sockets[sock];
  399.      u_long flags;
  400. u_int changed;
  401. unsigned short cscier;
  402.      DPRINTK("hs_set_socket(sock=%d, flags=%x, csc_mask=%x, Vcc=%d, Vpp=%d, io_irq=%d)n",
  403.     sock, state->flags, state->csc_mask, state->Vcc, state->Vpp, state->io_irq);
  404. save_and_cli(flags); /* Don't want interrupts happening here */
  405. if (state->Vpp != sp->state.Vpp ||
  406.     state->Vcc != sp->state.Vcc) {
  407.     if (!hs_set_voltages(sp, state->Vcc, state->Vpp)) {
  408.      restore_flags(flags);
  409.      return -EINVAL;
  410.     }
  411. }
  412. /*     hd64465_io_debug = 1; */
  413.      /*
  414.  * Handle changes in the Card Status Change mask,
  415.  * by propagating to the CSCR register
  416.  */
  417. changed = sp->state.csc_mask ^ state->csc_mask;
  418. cscier = hs_in(sp, CSCIER);
  419.     
  420. if (changed & SS_DETECT) {
  421.     if (state->csc_mask & SS_DETECT)
  422. cscier |= HD64465_PCCCSCIER_PCDE;
  423.     else
  424. cscier &= ~HD64465_PCCCSCIER_PCDE;
  425. }
  426. if (changed & SS_READY) {
  427.     if (state->csc_mask & SS_READY)
  428. cscier |= HD64465_PCCCSCIER_PRE;
  429.     else
  430. cscier &= ~HD64465_PCCCSCIER_PRE;
  431. }
  432. if (changed & SS_BATDEAD) {
  433.     if (state->csc_mask & SS_BATDEAD)
  434. cscier |= HD64465_PCCCSCIER_PBDE;
  435.     else
  436. cscier &= ~HD64465_PCCCSCIER_PBDE;
  437. }
  438. if (changed & SS_BATWARN) {
  439.     if (state->csc_mask & SS_BATWARN)
  440. cscier |= HD64465_PCCCSCIER_PBWE;
  441.     else
  442. cscier &= ~HD64465_PCCCSCIER_PBWE;
  443. }
  444. if (changed & SS_STSCHG) {
  445.     if (state->csc_mask & SS_STSCHG)
  446. cscier |= HD64465_PCCCSCIER_PSCE;
  447.     else
  448. cscier &= ~HD64465_PCCCSCIER_PSCE;
  449. }
  450.      hs_out(sp, cscier, CSCIER);
  451. if (sp->state.io_irq && !state->io_irq)
  452.     hs_unmap_irq(sp, sp->state.io_irq);
  453. else if (!sp->state.io_irq && state->io_irq)
  454.     hs_map_irq(sp, state->io_irq);
  455.      /*
  456.  * Handle changes in the flags field,
  457.  * by propagating to config registers.
  458.  */
  459. changed = sp->state.flags ^ state->flags;
  460. if (changed & SS_IOCARD) {
  461.     DPRINTK("card type: %sn",
  462.     (state->flags & SS_IOCARD ? "i/o" : "memory" ));
  463.     bool_to_regbit(sp, GCR, HD64465_PCCGCR_PCCT,
  464. state->flags & SS_IOCARD);
  465. }
  466. if (changed & SS_RESET) {
  467.     DPRINTK("%s reset cardn",
  468. (state->flags & SS_RESET ? "start" : "stop"));
  469.     bool_to_regbit(sp, GCR, HD64465_PCCGCR_PCCR,
  470. state->flags & SS_RESET);
  471. }
  472. if (changed & SS_OUTPUT_ENA) {
  473.     DPRINTK("%sabling card outputn",
  474. (state->flags & SS_OUTPUT_ENA ? "en" : "dis"));
  475.     bool_to_regbit(sp, GCR, HD64465_PCCGCR_PDRV,
  476. state->flags & SS_OUTPUT_ENA);
  477. }
  478.      /* TODO: SS_SPKR_ENA */
  479.     
  480. /*     hd64465_io_debug = 0; */
  481. sp->state = *state;
  482.     
  483. restore_flags(flags);
  484. #if HD64465_DEBUG > 10
  485. if (state->flags & SS_OUTPUT_ENA)   
  486.     cis_hex_dump((const unsigned char*)sp->mem_base, 0x100);
  487. #endif
  488. return 0;
  489. }
  490. /*============================================================*/
  491. static int hs_get_io_map(unsigned int sock, struct pccard_io_map *io)
  492. {
  493.      hs_socket_t *sp = &hs_sockets[sock];
  494. int map = io->map;
  495.      DPRINTK("hs_get_io_map(%d, %d)n", sock, map);
  496. if (map >= MAX_IO_WIN)
  497.     return -EINVAL;
  498. *io = sp->io_maps[map];
  499. return 0;
  500. }
  501. /*============================================================*/
  502. static int hs_set_io_map(unsigned int sock, struct pccard_io_map *io)
  503. {
  504.      hs_socket_t *sp = &hs_sockets[sock];
  505. int map = io->map;
  506. struct pccard_io_map *sio;
  507. pgprot_t prot;
  508.      DPRINTK("hs_set_io_map(sock=%d, map=%d, flags=0x%x, speed=%dns, start=0x%04x, stop=0x%04x)n",
  509.     sock, map, io->flags, io->speed, io->start, io->stop);
  510. if (map >= MAX_IO_WIN)
  511.     return -EINVAL;
  512. sio = &sp->io_maps[map];
  513.      /* check for null changes */
  514.      if (io->flags == sio->flags &&
  515.     io->start == sio->start &&
  516.     io->stop == sio->stop)
  517.     return 0;
  518. if (io->flags & MAP_AUTOSZ)
  519.     prot = PAGE_KERNEL_PCC(sock, _PAGE_PCC_IODYN);
  520. else if (io->flags & MAP_16BIT)
  521.     prot = PAGE_KERNEL_PCC(sock, _PAGE_PCC_IO16);
  522. else
  523.     prot = PAGE_KERNEL_PCC(sock, _PAGE_PCC_IO8);
  524. /* TODO: handle MAP_USE_WAIT */
  525. if (io->flags & MAP_USE_WAIT)
  526.     printk(KERN_INFO MODNAME ": MAP_USE_WAIT unimplementedn");
  527. /* TODO: handle MAP_PREFETCH */
  528. if (io->flags & MAP_PREFETCH)
  529.     printk(KERN_INFO MODNAME ": MAP_PREFETCH unimplementedn");
  530. /* TODO: handle MAP_WRPROT */
  531. if (io->flags & MAP_WRPROT)
  532.     printk(KERN_INFO MODNAME ": MAP_WRPROT unimplementedn");
  533. /* TODO: handle MAP_0WS */
  534. if (io->flags & MAP_0WS)
  535.     printk(KERN_INFO MODNAME ": MAP_0WS unimplementedn");
  536. if (io->flags & MAP_ACTIVE) {
  537.     unsigned long pstart, psize, paddrbase, vaddrbase;
  538.     
  539.     paddrbase = virt_to_phys((void*)(sp->mem_base + 2 * HD64465_PCC_WINDOW));
  540.     vaddrbase = (unsigned long)sp->io_vma->addr;
  541.     pstart = io->start & PAGE_MASK;
  542.     psize = ((io->stop + PAGE_SIZE) & PAGE_MASK) - pstart;
  543.          /*
  544.      * Change PTEs in only that portion of the mapping requested
  545.      * by the caller.  This means that most of the time, most of
  546.      * the PTEs in the io_vma will be unmapped and only the bottom
  547.      * page will be mapped.  But the code allows for weird cards
  548.      * that might want IO ports > 4K.
  549.      */
  550.     DPRINTK("remap_page_range(vaddr=0x%08lx, paddr=0x%08lx, size=0x%08lxx)n",
  551.      vaddrbase + pstart, paddrbase + pstart, psize);
  552.     remap_page_range(vaddrbase + pstart, paddrbase + pstart, psize, prot);
  553.     
  554.     /*
  555.      * Change the mapping used by inb() outb() etc
  556.      */
  557.     hd64465_port_map(
  558.      io->start,
  559. io->stop - io->start + 1,
  560.      vaddrbase + io->start,0);
  561. } else {
  562.     hd64465_port_unmap(
  563.      sio->start,
  564. sio->stop - sio->start + 1);
  565.     /* TODO: remap_page_range() to mark pages not present ? */
  566. }
  567. *sio = *io;
  568. return 0;
  569. }
  570. /*============================================================*/
  571. static int hs_get_mem_map(unsigned int sock, struct pccard_mem_map *mem)
  572. {
  573.      hs_socket_t *sp = &hs_sockets[sock];
  574. int map = mem->map;
  575.      DPRINTK("hs_get_mem_map(%d, %d)n", sock, map);
  576. if (map >= MAX_WIN)
  577.     return -EINVAL;
  578. *mem = sp->mem_maps[map];
  579. return 0;
  580. }
  581. /*============================================================*/
  582. static int hs_set_mem_map(unsigned int sock, struct pccard_mem_map *mem)
  583. {
  584.      hs_socket_t *sp = &hs_sockets[sock];
  585. struct pccard_mem_map *smem;
  586. int map = mem->map;
  587. unsigned long paddr, size;
  588. #if 0
  589.      DPRINTK("hs_set_mem_map(sock=%d, map=%d, flags=0x%x, sys_start=0x%08lx, sys_end=0x%08lx, card_start=0x%08x)n",
  590.     sock, map, mem->flags, mem->sys_start, mem->sys_stop, mem->card_start);
  591. #endif
  592. if (map >= MAX_WIN)
  593.     return -EINVAL;
  594. smem = &sp->mem_maps[map];
  595. size = mem->sys_stop - mem->sys_start + 1;
  596. paddr = sp->mem_base;          /* base of Attribute mapping */
  597. if (!(mem->flags & MAP_ATTRIB))
  598.     paddr += HD64465_PCC_WINDOW;    /* base of Common mapping */
  599. paddr += mem->card_start;
  600.      /* Because we specified SS_CAP_STATIC_MAP, we are obliged
  601.  * at this time to report the system address corresponding
  602.  * to the card address requested.  This is how Socket Services
  603.  * queries our fixed mapping.  I wish this fact had been
  604.  * documented - Greg Banks.
  605.  */
  606.      mem->sys_start = paddr;
  607. mem->sys_stop = paddr + size - 1;
  608. *smem = *mem;
  609.      return 0;
  610. }
  611. /* TODO: do we need to use the MMU to access Common memory ??? */
  612. /*============================================================*/
  613. static void hs_proc_setup(unsigned int sock, struct proc_dir_entry *base)
  614. {
  615.      DPRINTK("hs_proc_setup(%d)n", sock);
  616. }
  617. /*============================================================*/
  618. /*
  619.  * This function is registered with the HD64465 glue code to do a
  620.  * secondary demux step on the PCMCIA interrupts.  It handles 
  621.  * mapping the IREQ request from the card to a standard Linux
  622.  * IRQ, as requested by SocketServices.
  623.  */
  624. static int hs_irq_demux(int irq, void *dev)
  625. {
  626.      hs_socket_t *sp = (hs_socket_t *)dev;
  627. u_int cscr;
  628.     
  629.      DPRINTK("hs_irq_demux(irq=%d)n", irq);
  630.      if (sp->state.io_irq &&
  631.     (cscr = hs_in(sp, CSCR)) & HD64465_PCCCSCR_PIREQ) {
  632.     cscr &= ~HD64465_PCCCSCR_PIREQ;
  633.     hs_out(sp, cscr, CSCR);
  634.     return sp->state.io_irq;
  635. }
  636.     
  637. return irq;
  638. }
  639. /*============================================================*/
  640. /*
  641.  * Interrupt handling routine.
  642.  *
  643.  * This uses the schedule_task() technique to cause reportable events
  644.  * such as card insertion and removal to be handled in keventd's
  645.  * process context.
  646.  */
  647.  
  648. static void hs_events_bh(void *dummy)
  649. {
  650. hs_socket_t *sp;
  651. u_int events;
  652. int i;
  653. for (i=0; i<HS_MAX_SOCKETS; i++) {
  654.     sp = &hs_sockets[i];
  655.     spin_lock_irq(&hs_pending_event_lock);
  656.     events = sp->pending_events;
  657.     sp->pending_events = 0;
  658.     spin_unlock_irq(&hs_pending_event_lock);
  659.     
  660.     if (sp->handler)
  661. sp->handler(sp->handler_info, events);
  662. }
  663. }
  664. static struct tq_struct hs_events_task = {
  665. routine: hs_events_bh
  666. };
  667. static void hs_interrupt(int irq, void *dev, struct pt_regs *regs)
  668. {
  669.      hs_socket_t *sp = (hs_socket_t *)dev;
  670. u_int events = 0;
  671. u_int cscr;
  672. cscr = hs_in(sp, CSCR);
  673. DPRINTK("hs_interrupt, cscr=%04xn", cscr);
  674. /* check for bus-related changes to be reported to Socket Services */
  675. if (cscr & HD64465_PCCCSCR_PCDC) {
  676.     /* double-check for a 16-bit card, as we don't support CardBus */
  677.     if ((hs_in(sp, ISR) & HD64465_PCCISR_PCD_MASK) != 0) {
  678.      printk(KERN_NOTICE MODNAME
  679.     ": socket %d, card not a supported card type or not inserted correctlyn",
  680.     hs_sockno(sp));
  681. /* Don't do the rest unless a card is present */
  682. cscr &= ~(HD64465_PCCCSCR_PCDC|
  683.        HD64465_PCCCSCR_PRC|
  684.   HD64465_PCCCSCR_PBW|
  685.        HD64465_PCCCSCR_PBD|
  686.   HD64465_PCCCSCR_PSC);
  687.     } else {
  688.      cscr &= ~HD64465_PCCCSCR_PCDC;
  689. events |= SS_DETECT;     /* card insertion or removal */
  690.          }
  691. }
  692. if (cscr & HD64465_PCCCSCR_PRC) {
  693.     cscr &= ~HD64465_PCCCSCR_PRC;
  694.     events |= SS_READY;      /* ready signal changed */
  695. }
  696. if (cscr & HD64465_PCCCSCR_PBW) {
  697.     cscr &= ~HD64465_PCCCSCR_PSC;
  698.     events |= SS_BATWARN;      /* battery warning */
  699. }
  700. if (cscr & HD64465_PCCCSCR_PBD) {
  701.     cscr &= ~HD64465_PCCCSCR_PSC;
  702.     events |= SS_BATDEAD;      /* battery dead */
  703. }
  704. if (cscr & HD64465_PCCCSCR_PSC) {
  705.     cscr &= ~HD64465_PCCCSCR_PSC;
  706.     events |= SS_STSCHG;      /* STSCHG (status changed) signal */
  707. }
  708. if (cscr & HD64465_PCCCSCR_PIREQ) {
  709.     cscr &= ~HD64465_PCCCSCR_PIREQ;
  710.          /* This should have been dealt with during irq demux */     
  711.     printk(KERN_NOTICE MODNAME ": unexpected IREQ from cardn");
  712. }
  713. hs_out(sp, cscr, CSCR);
  714. if (events) {
  715.     /*
  716.           * Arrange for events to be reported to the registered
  717.      * event handler function (from CardServices) in a process
  718.      * context (keventd) "soon".
  719.      */
  720.     spin_lock(&hs_pending_event_lock);
  721.     sp->pending_events |= events;
  722.     spin_unlock(&hs_pending_event_lock);
  723.     
  724.     schedule_task(&hs_events_task);
  725. }
  726. }
  727. /*============================================================*/
  728. static struct pccard_operations hs_operations = {
  729. hs_init,
  730. hs_suspend,
  731. hs_register_callback,
  732. hs_inquire_socket,
  733. hs_get_status,
  734. hs_get_socket,
  735. hs_set_socket,
  736. hs_get_io_map,
  737. hs_set_io_map,
  738. hs_get_mem_map,
  739. hs_set_mem_map,
  740. hs_proc_setup
  741. };
  742. static int hs_init_socket(hs_socket_t *sp, int irq, unsigned long mem_base,
  743.          unsigned int ctrl_base)
  744. {
  745.      unsigned short v;
  746.      int i, err;
  747.      memset(sp, 0, sizeof(*sp));
  748. sp->irq = irq;
  749. sp->mem_base = mem_base;
  750. sp->mem_length = 4*HD64465_PCC_WINDOW; /* 16MB */
  751. sp->ctrl_base = ctrl_base;
  752. for (i=0 ; i<MAX_IO_WIN ; i++)
  753.     sp->io_maps[i].map = i;
  754. for (i=0 ; i<MAX_WIN ; i++)
  755.     sp->mem_maps[i].map = i;
  756. if ((sp->io_vma = get_vm_area(HS_IO_MAP_SIZE, VM_IOREMAP)) == 0)
  757.     return -ENOMEM;
  758. hd64465_register_irq_demux(sp->irq, hs_irq_demux, sp);
  759.      if ((err = request_irq(sp->irq, hs_interrupt, SA_INTERRUPT, MODNAME, sp)) < 0)
  760.     return err;
  761.      if (request_mem_region(sp->mem_base, sp->mem_length, MODNAME) == 0) {
  762.          sp->mem_base = 0;
  763.     return -ENOMEM;
  764. }
  765. /* According to section 3.2 of the PCMCIA standard, low-voltage
  766.  * capable cards must implement cold insertion, i.e. Vpp and
  767.  * Vcc set to 0 before card is inserted.
  768.  */
  769. /*hs_set_voltages(sp, 0, 0);*/
  770. /* hi-Z the outputs to the card and set 16MB map mode */
  771. v = hs_in(sp, GCR);
  772. v &= ~HD64465_PCCGCR_PCCT;   /* memory-only card */
  773. hs_out(sp, v, GCR);
  774. v = hs_in(sp, GCR);
  775. v |= HD64465_PCCGCR_PDRV;    /* enable outputs to card */
  776. hs_out(sp, v, GCR);
  777. v = hs_in(sp, GCR);
  778. v |= HD64465_PCCGCR_PMMOD;  /* 16MB mapping mode */
  779. hs_out(sp, v, GCR);
  780. v = hs_in(sp, GCR);
  781. /* lowest 16MB of Common */
  782. v &= ~(HD64465_PCCGCR_PPA25|HD64465_PCCGCR_PPA24); 
  783. hs_out(sp, v, GCR);
  784. hs_reset_socket(sp, 1);
  785.      return 0;
  786. }
  787. static void hs_exit_socket(hs_socket_t *sp)
  788. {
  789.      unsigned short cscier, gcr;
  790. /* turn off interrupts in hardware */
  791.      cscier = hs_in(sp, CSCIER);
  792. cscier = (cscier & IER_MASK) | IER_OFF;
  793.      hs_out(sp, cscier, CSCIER);
  794. /* hi-Z the outputs to the card */
  795.      gcr = hs_in(sp, GCR);
  796. gcr &= HD64465_PCCGCR_PDRV;
  797. hs_out(sp, gcr, GCR);
  798.      /* power the card down */
  799. hs_set_voltages(sp, 0, 0);
  800.      if (sp->mem_base != 0)
  801.     release_mem_region(sp->mem_base, sp->mem_length);
  802. if (sp->irq != 0) {
  803.     free_irq(sp->irq, hs_interrupt);
  804.          hd64465_unregister_irq_demux(sp->irq);
  805. }
  806. if (sp->io_vma != 0)
  807.     vfree(sp->io_vma->addr);
  808. }
  809. static int __init init_hs(void)
  810. {
  811. servinfo_t serv;
  812. int i;
  813. unsigned short v;
  814.      /*
  815.  * Check API version
  816.  */
  817. pcmcia_get_card_services_info(&serv);
  818. if (serv.Revision != CS_RELEASE_CODE) {
  819.     printk(KERN_NOTICE MODNAME ": Card Services release does not match!n");
  820.     return -ENODEV;
  821. }
  822. /* hd64465_io_debug = 1; */
  823. /* Wake both sockets out of STANDBY mode */
  824. /* TODO: wait 15ms */
  825. v = inw(HD64465_REG_SMSCR);
  826. v &= ~(HD64465_SMSCR_PC0ST|HD64465_SMSCR_PC1ST);
  827. outw(v, HD64465_REG_SMSCR);
  828. /* keep power controller out of shutdown mode */
  829. v = inb(HD64465_REG_PCC0SCR);
  830. v |= HD64465_PCCSCR_SHDN;
  831. outb(v, HD64465_REG_PCC0SCR);
  832.      /* use serial (TPS2206) power controller */
  833. v = inb(HD64465_REG_PCC0CSCR);
  834. v |= HD64465_PCCCSCR_PSWSEL;
  835. outb(v, HD64465_REG_PCC0CSCR);
  836.      hs_set_voltages(&hs_sockets[0], 0, 0);
  837.      hs_set_voltages(&hs_sockets[1], 0, 0);
  838. /*
  839.  * Setup hs_sockets[] structures and request system resources.
  840.  * TODO: on memory allocation failure, power down the socket
  841.  *       before quitting.
  842.  */
  843. i = hs_init_socket(&hs_sockets[0],
  844.     HD64465_IRQ_PCMCIA0,
  845.     HD64465_PCC0_BASE,
  846.     HD64465_REG_PCC0ISR);
  847. if (i < 0)
  848.     return i;
  849. i = hs_init_socket(&hs_sockets[1],
  850.     HD64465_IRQ_PCMCIA1,
  851.     HD64465_PCC1_BASE,
  852.     HD64465_REG_PCC1ISR);
  853. if (i < 0)
  854.     return i;
  855. /* hd64465_io_debug = 0; */
  856.     
  857. if (register_ss_entry(HS_MAX_SOCKETS, &hs_operations) != 0) {
  858.     for (i=0 ; i<HS_MAX_SOCKETS ; i++)
  859. hs_exit_socket(&hs_sockets[i]);
  860.          return -ENODEV;
  861. }
  862. printk(KERN_INFO "HD64465 PCMCIA bridge:n");
  863. for (i=0 ; i<HS_MAX_SOCKETS ; i++) {
  864.     hs_socket_t *sp = &hs_sockets[i];
  865.     
  866.     printk(KERN_INFO "  socket %d at 0x%08lx irq %d io window %ldK@0x%08lxn",
  867.      i, sp->mem_base, sp->irq,
  868. sp->io_vma->size>>10, (unsigned long)sp->io_vma->addr);
  869. }
  870.      return 0;
  871. }
  872. static void __exit exit_hs(void)
  873. {
  874.      u_long flags;
  875. int i;
  876. save_and_cli(flags);
  877.      /*
  878.  * Release kernel resources
  879.  */
  880. for (i=0 ; i<HS_MAX_SOCKETS ; i++)
  881.     hs_exit_socket(&hs_sockets[i]);
  882. unregister_ss_entry(&hs_operations);
  883. restore_flags(flags);
  884. }
  885. module_init(init_hs);
  886. module_exit(exit_hs);
  887. /*============================================================*/
  888. /*END*/