Beispiel #1
0
/* sa1100_pcmcia_update_mecr()
 * ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 * When sa1100_pcmcia_notifier() decides that a MECR adjustment (due
 * to a core clock frequency change) is needed, this routine establishes
 * new BS_xx values consistent with the clock speed `clock'.
 */
static void sa1100_pcmcia_update_mecr(unsigned int clock){
  unsigned int sock;
  unsigned long mecr = MECR;

  for(sock = 0; sock < SA1100_PCMCIA_MAX_SOCK; ++sock){

    MECR_BSIO_SET(mecr, sock,
		  sa1100_pcmcia_mecr_bs(sa1100_pcmcia_socket[sock].speed_io,
					clock));
    MECR_BSA_SET(mecr, sock,
		 sa1100_pcmcia_mecr_bs(sa1100_pcmcia_socket[sock].speed_attr,
				       clock));
    MECR_BSM_SET(mecr, sock,
		 sa1100_pcmcia_mecr_bs(sa1100_pcmcia_socket[sock].speed_mem,
				       clock));
  }

  MECR = mecr;

}
/* sa1100_pcmcia_set_mem_map()
 * ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 * Implements the set_mem_map() operation for the in-kernel PCMCIA
 * service (formerly SS_SetMemMap in Card Services). We configure
 * the map speed as requested, but override the address ranges
 * supplied by Card Services.
 *
 * Returns: 0 on success, -1 on error
 */
static int
sa1100_pcmcia_set_mem_map(unsigned int sock, struct pccard_mem_map *map)
{
  struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
  unsigned long start;

  DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock);

  DEBUG(3, "\tmap %u speed %u sys_start %08lx sys_stop %08lx card_start %08x\n",
	map->map, map->speed, map->sys_start, map->sys_stop, map->card_start);
  DEBUG(3, "\tflags: %s%s%s%s%s%s%s%s\n",
	(map->flags==0)?"<NONE>":"",
	(map->flags&MAP_ACTIVE)?"ACTIVE ":"",
	(map->flags&MAP_16BIT)?"16BIT ":"",
	(map->flags&MAP_AUTOSZ)?"AUTOSZ ":"",
	(map->flags&MAP_0WS)?"0WS ":"",
	(map->flags&MAP_WRPROT)?"WRPROT ":"",
	(map->flags&MAP_ATTRIB)?"ATTRIB ":"",
	(map->flags&MAP_USE_WAIT)?"USE_WAIT ":"");

  if (map->map >= MAX_WIN){
    printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__,
	   map->map);
    return -1;
  }

  if (map->flags & MAP_ACTIVE) {
    unsigned int clock, speed = map->speed;
    unsigned long mecr;

    /*
     * When clients issue RequestMap, the access speed is not always
     * properly configured.  Choose some sensible defaults.
     */
    if (speed == 0) {
      if (skt->cs_state.Vcc == 33)
	speed = SA1100_PCMCIA_3V_MEM_ACCESS;
      else
	speed = SA1100_PCMCIA_5V_MEM_ACCESS;
    }

    clock = cpufreq_get(0);

    /* Fixme: MECR is not pre-empt safe. */
    mecr = MECR;

    if (map->flags & MAP_ATTRIB) {
      MECR_BSA_SET(mecr, sock, sa1100_pcmcia_mecr_bs(speed, clock));
      skt->speed_attr = speed;
    } else {
      MECR_BSM_SET(mecr, sock, sa1100_pcmcia_mecr_bs(speed, clock));
      skt->speed_mem = speed;
    }

    DEBUG(4, "%s(): FAST%u %lx  BSM%u %lx  BSA%u %lx  BSIO%u %lx\n",
	  __FUNCTION__, sock, MECR_FAST_GET(mecr, sock), sock,
	  MECR_BSM_GET(mecr, sock), sock, MECR_BSA_GET(mecr, sock), 
	  sock, MECR_BSIO_GET(mecr, sock));

    MECR = mecr;
  }

  start = (map->flags & MAP_ATTRIB) ? skt->phys_attr : skt->phys_mem;

  if (map->sys_stop == 0)
    map->sys_stop = PAGE_SIZE-1;

  map->sys_stop -= map->sys_start;
  map->sys_stop += start;
  map->sys_start = start;

  skt->mem_map[map->map] = *map;

  return 0;
}  /* sa1100_pcmcia_set_mem_map() */
/* sa1100_pcmcia_driver_init()
 * ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 *
 * This routine performs a basic sanity check to ensure that this
 * kernel has been built with the appropriate board-specific low-level
 * PCMCIA support, performs low-level PCMCIA initialization, registers
 * this socket driver with Card Services, and then spawns the daemon
 * thread which is the real workhorse of the socket driver.
 *
 * Returns: 0 on success, -1 on error
 */
static int __init sa1100_pcmcia_driver_init(void)
{
  servinfo_t info;
  struct pcmcia_init pcmcia_init;
  struct pcmcia_state state[SA1100_PCMCIA_MAX_SOCK];
  struct pcmcia_state_array state_array;
  unsigned int i, clock;
  unsigned long mecr;
  int ret;

  printk(KERN_INFO "SA-1100 PCMCIA (CS release %s)\n", CS_RELEASE);

  CardServices(GetCardServicesInfo, &info);

  if (info.Revision != CS_RELEASE_CODE) {
    printk(KERN_ERR "Card Services release codes do not match\n");
    return -EINVAL;
  }

  ret = sa1100_pcmcia_machine_init();
  if (ret)
    return ret;

  pcmcia_init.handler = sa1100_pcmcia_interrupt;

  ret = pcmcia_low_level->init(&pcmcia_init);
  if (ret < 0) {
    printk(KERN_ERR "Unable to initialize kernel PCMCIA service (%d).\n", ret);
    return ret == -1 ? -EIO : ret;
  }

  sa1100_pcmcia_socket_count = ret;
  state_array.size  = sa1100_pcmcia_socket_count;
  state_array.state = state;

  memset(state, 0, sizeof(state));

  if (pcmcia_low_level->socket_state(&state_array) < 0) {
    pcmcia_low_level->shutdown();
    printk(KERN_ERR "Unable to get PCMCIA status from kernel.\n");
    return -EIO;
  }

  /*
   * We initialize the MECR to default values here, because we are
   * not guaranteed to see a SetIOMap operation at runtime.
   */
  mecr = MECR;

  clock = cpufreq_get(0);

  for (i = 0; i < sa1100_pcmcia_socket_count; i++) {
    struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(i);
    struct pcmcia_irq_info irq_info;

    if (!request_mem_region(_PCMCIA(i), PCMCIASp, "PCMCIA")) {
      ret = -EBUSY;
      goto out_err;
    }

    irq_info.sock = i;
    irq_info.irq  = -1;
    ret = pcmcia_low_level->get_irq_info(&irq_info);
    if (ret < 0)
      printk(KERN_ERR "Unable to get IRQ for socket %u (%d)\n", i, ret);

    skt->irq        = irq_info.irq;
    skt->k_state    = state[i];
    skt->speed_io   = SA1100_PCMCIA_IO_ACCESS;
    skt->speed_attr = SA1100_PCMCIA_5V_MEM_ACCESS;
    skt->speed_mem  = SA1100_PCMCIA_5V_MEM_ACCESS;
    skt->phys_attr  = _PCMCIAAttr(i);
    skt->phys_mem   = _PCMCIAMem(i);
    skt->virt_io    = ioremap(_PCMCIAIO(i), 0x10000);

    if (skt->virt_io == NULL) {
      ret = -ENOMEM;
      goto out_err;
    }

    MECR_FAST_SET(mecr, i, 0);
    MECR_BSIO_SET(mecr, i, sa1100_pcmcia_mecr_bs(skt->speed_io, clock));
    MECR_BSA_SET(mecr, i, sa1100_pcmcia_mecr_bs(skt->speed_attr, clock));
    MECR_BSM_SET(mecr, i, sa1100_pcmcia_mecr_bs(skt->speed_mem, clock));
  }

  MECR = mecr;

#ifdef CONFIG_CPU_FREQ
  ret = cpufreq_register_notifier(&sa1100_pcmcia_notifier_block);
  if (ret < 0) {
    printk(KERN_ERR "Unable to register CPU frequency change notifier (%d)\n", ret);
    goto out_err;
  }
#endif

  /* Only advertise as many sockets as we can detect */
  ret = register_ss_entry(sa1100_pcmcia_socket_count,
			  &sa1100_pcmcia_operations);
  if (ret < 0) {
    printk(KERN_ERR "Unable to register sockets\n");
    goto out_err;
  }

  /*
   * Start the event poll timer.  It will reschedule by itself afterwards.
   */
  sa1100_pcmcia_poll_event(0);

  return 0;

 out_err:
  for (i = 0; i < sa1100_pcmcia_socket_count; i++) {
    iounmap(sa1100_pcmcia_socket[i].virt_io);
    release_mem_region(_PCMCIA(i), PCMCIASp);
  }

  pcmcia_low_level->shutdown();

  return ret;
}  /* sa1100_pcmcia_driver_init() */
Beispiel #4
0
/* sa1100_pcmcia_set_mem_map()
 * ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 * Implements the set_mem_map() operation for the in-kernel PCMCIA
 * service (formerly SS_SetMemMap in Card Services). We configure
 * the map speed as requested, but override the address ranges
 * supplied by Card Services.
 *
 * Returns: 0 on success, -1 on error
 */
static int sa1100_pcmcia_set_mem_map(unsigned int sock,
				     struct pccard_mem_map *map){
  unsigned int clock, speed;
  unsigned long mecr, start;

  DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock);

  DEBUG(4, "\tmap %u  speed %u\n\tsys_start  %#lx\n"
	"\tsys_stop   %#lx\n\tcard_start %#x\n"
	"\tflags: %s%s%s%s%s%s%s%s\n",
	map->map, map->speed, map->sys_start, map->sys_stop,
	map->card_start, (map->flags==0)?"<NONE>":"",
	(map->flags&MAP_ACTIVE)?"ACTIVE ":"",
	(map->flags&MAP_16BIT)?"16BIT ":"",
	(map->flags&MAP_AUTOSZ)?"AUTOSZ ":"",
	(map->flags&MAP_0WS)?"0WS ":"",
	(map->flags&MAP_WRPROT)?"WRPROT ":"",
	(map->flags&MAP_ATTRIB)?"ATTRIB ":"",
	(map->flags&MAP_USE_WAIT)?"USE_WAIT ":"");

  if(map->map>=MAX_WIN){
    printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__,
	   map->map);
    return -1;
  }

  if(map->flags&MAP_ACTIVE){

    /* When clients issue RequestMap, the access speed is not always
     * properly configured:
     */
    if(map->speed > 0)
      speed = map->speed;
    else
      switch(sa1100_pcmcia_socket[sock].cs_state.Vcc){
      case 33:
	speed = SA1100_PCMCIA_3V_MEM_ACCESS;
	break;
      default:
	speed = SA1100_PCMCIA_5V_MEM_ACCESS;
      }

    clock = cpufreq_get(0);
    
    mecr=MECR;
    
    if(map->flags&MAP_ATTRIB){

      MECR_BSA_SET(mecr, sock, sa1100_pcmcia_mecr_bs(speed, clock));
      sa1100_pcmcia_socket[sock].speed_attr=speed;

    } else {

      MECR_BSM_SET(mecr, sock, sa1100_pcmcia_mecr_bs(speed, clock));
      sa1100_pcmcia_socket[sock].speed_mem=speed;

    }
    
    DEBUG(4, "%s(): FAST%u %lx  BSM%u %lx  BSA%u %lx  BSIO%u %lx\n",
	  __FUNCTION__, sock, MECR_FAST_GET(mecr, sock), sock,
	  MECR_BSM_GET(mecr, sock), sock, MECR_BSA_GET(mecr, sock), 
	  sock, MECR_BSIO_GET(mecr, sock));
    
    MECR=mecr;

  }

  start=map->sys_start;

  if(map->sys_stop==0)
    map->sys_stop=PAGE_SIZE-1;

  map->sys_start=(map->flags & MAP_ATTRIB)?\
    sa1100_pcmcia_socket[sock].phys_attr:\
    sa1100_pcmcia_socket[sock].phys_mem;

  map->sys_stop=map->sys_start+(map->sys_stop-start);

  sa1100_pcmcia_socket[sock].mem_map[map->map]=*map;

  return 0;

}  /* sa1100_pcmcia_set_mem_map() */
Beispiel #5
0
/* sa1100_pcmcia_driver_init()
 * ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 *
 * This routine performs a basic sanity check to ensure that this
 * kernel has been built with the appropriate board-specific low-level
 * PCMCIA support, performs low-level PCMCIA initialization, registers
 * this socket driver with Card Services, and then spawns the daemon
 * thread which is the real workhorse of the socket driver.
 *
 * Please see linux/Documentation/arm/SA1100/PCMCIA for more information
 * on the low-level kernel interface.
 *
 * Returns: 0 on success, -1 on error
 */
static int __init sa1100_pcmcia_driver_init(void){
  servinfo_t info;
  struct pcmcia_init pcmcia_init;
  struct pcmcia_state state[SA1100_PCMCIA_MAX_SOCK];
  struct pcmcia_state_array state_array;
  unsigned int i, clock;
  unsigned long mecr;

  printk(KERN_INFO "SA-1100 PCMCIA (CS release %s)\n", CS_RELEASE);

  CardServices(GetCardServicesInfo, &info);

  if(info.Revision!=CS_RELEASE_CODE){
    printk(KERN_ERR "Card Services release codes do not match\n");
    return -1;
  }

  if(machine_is_assabet()){
#ifdef CONFIG_SA1100_ASSABET
    if(machine_has_neponset()){
#ifdef CONFIG_ASSABET_NEPONSET
      pcmcia_low_level=&neponset_pcmcia_ops;
#else
      printk(KERN_ERR "Card Services disabled: missing Neponset support\n");
      return -1;
#endif
    }else{
      pcmcia_low_level=&assabet_pcmcia_ops;
    }
#endif
  } else if (machine_is_freebird()) {
#ifdef CONFIG_SA1100_FREEBIRD
    pcmcia_low_level = &freebird_pcmcia_ops;
#endif
  } else if (machine_is_h3xxx()) {
#ifdef CONFIG_SA1100_H3XXX
    pcmcia_low_level = &h3600_pcmcia_ops;
#endif    
  } else if (machine_is_cerf()) {
#ifdef CONFIG_SA1100_CERF
    pcmcia_low_level = &cerf_pcmcia_ops;
#endif
  } else if (machine_is_graphicsclient()) {
#ifdef CONFIG_SA1100_GRAPHICSCLIENT
    pcmcia_low_level = &gcplus_pcmcia_ops;
#endif
  } else if (machine_is_xp860()) {
#ifdef CONFIG_SA1100_XP860
    pcmcia_low_level = &xp860_pcmcia_ops;
#endif
  } else if (machine_is_yopy()) {
#ifdef CONFIG_SA1100_YOPY
    pcmcia_low_level = &yopy_pcmcia_ops;
#endif
  } else if (machine_is_shannon()) {
#ifdef CONFIG_SA1100_SHANNON
    pcmcia_low_level = &shannon_pcmcia_ops;
#endif
  } else if (machine_is_pangolin()) {
#ifdef CONFIG_SA1100_PANGOLIN
    pcmcia_low_level = &pangolin_pcmcia_ops;
#endif
  } else if (machine_is_jornada720()) {
#ifdef CONFIG_SA1100_JORNADA720
    pcmcia_low_level = &jornada720_pcmcia_ops;
#endif
  } else if(machine_is_pfs168()){
#ifdef CONFIG_SA1100_PFS168
    pcmcia_low_level=&pfs168_pcmcia_ops;
#endif
  } else if(machine_is_flexanet()){
#ifdef CONFIG_SA1100_FLEXANET
    pcmcia_low_level=&flexanet_pcmcia_ops;
#endif
 } else if(machine_is_simpad()){
#ifdef CONFIG_SA1100_SIMPAD
    pcmcia_low_level=&simpad_pcmcia_ops;
#endif
  } else if(machine_is_graphicsmaster()) {
#ifdef CONFIG_SA1100_GRAPHICSMASTER
    pcmcia_low_level=&graphicsmaster_pcmcia_ops;
#endif
  } else if(machine_is_adsbitsy()) {
#ifdef CONFIG_SA1100_ADSBITSY
    pcmcia_low_level=&adsbitsy_pcmcia_ops;
#endif
  } else if(machine_is_stork()) {
#ifdef CONFIG_SA1100_STORK
    pcmcia_low_level=&stork_pcmcia_ops;
#endif
  }

  if (!pcmcia_low_level) {
    printk(KERN_ERR "This hardware is not supported by the SA1100 Card Service driver\n");
    return -ENODEV;
  }

  pcmcia_init.handler=sa1100_pcmcia_interrupt;

  if((sa1100_pcmcia_socket_count=pcmcia_low_level->init(&pcmcia_init))<0){
    printk(KERN_ERR "Unable to initialize kernel PCMCIA service.\n");
    return -EIO;
  }

  state_array.size=sa1100_pcmcia_socket_count;
  state_array.state=state;

  if(pcmcia_low_level->socket_state(&state_array)<0){
    printk(KERN_ERR "Unable to get PCMCIA status from kernel.\n");
    return -EIO;
  }

  /* We initialize the MECR to default values here, because we are
   * not guaranteed to see a SetIOMap operation at runtime.
   */
  mecr=0;

  clock = cpufreq_get(0);

  for(i=0; i<sa1100_pcmcia_socket_count; ++i){
    sa1100_pcmcia_socket[i].k_state=state[i];

    /* This is an interim fix. Apparently, SetSocket is no longer
     * called to initialize each socket (prior to the first detect
     * event). For now, we'll just manually set up the mask.
     */
    sa1100_pcmcia_socket[i].cs_state.csc_mask=SS_DETECT;

    sa1100_pcmcia_socket[i].virt_io=(i==0)?PCMCIA_IO_0_BASE:PCMCIA_IO_1_BASE;
    sa1100_pcmcia_socket[i].phys_attr=_PCMCIAAttr(i);
    sa1100_pcmcia_socket[i].phys_mem=_PCMCIAMem(i);

    MECR_FAST_SET(mecr, i, 0);
    MECR_BSIO_SET(mecr, i,
		  sa1100_pcmcia_mecr_bs(SA1100_PCMCIA_IO_ACCESS, clock));
    MECR_BSA_SET(mecr, i,
		 sa1100_pcmcia_mecr_bs(SA1100_PCMCIA_5V_MEM_ACCESS, clock));
    MECR_BSM_SET(mecr, i,
		 sa1100_pcmcia_mecr_bs(SA1100_PCMCIA_5V_MEM_ACCESS, clock));

    sa1100_pcmcia_socket[i].speed_io=SA1100_PCMCIA_IO_ACCESS;
    sa1100_pcmcia_socket[i].speed_attr=SA1100_PCMCIA_5V_MEM_ACCESS;
    sa1100_pcmcia_socket[i].speed_mem=SA1100_PCMCIA_5V_MEM_ACCESS;
  }

  MECR=mecr;

#ifdef CONFIG_CPU_FREQ
  if(cpufreq_register_notifier(&sa1100_pcmcia_notifier_block) < 0){
    printk(KERN_ERR "Unable to register CPU frequency change notifier\n");
    return -ENXIO;
  }
#endif

  /* Only advertise as many sockets as we can detect: */
  if(register_ss_entry(sa1100_pcmcia_socket_count, 
		       &sa1100_pcmcia_operations)<0){
    printk(KERN_ERR "Unable to register socket service routine\n");
    return -ENXIO;
  }

  /* Start the event poll timer.  It will reschedule by itself afterwards. */
  sa1100_pcmcia_poll_event(0);

  DEBUG(1, "sa1100: initialization complete\n");

  return 0;

}  /* sa1100_pcmcia_driver_init() */