patch-2.4.19 linux-2.4.19/drivers/pcmcia/sa1100_generic.c
Next file: linux-2.4.19/drivers/pcmcia/sa1100_generic.h
Previous file: linux-2.4.19/drivers/pcmcia/sa1100_freebird.c
Back to the patch index
Back to the overall index
- Lines: 1643
- Date:
Fri Aug 2 17:39:44 2002
- Orig file:
linux-2.4.18/drivers/pcmcia/sa1100_generic.c
- Orig date:
Thu Oct 25 13:53:48 2001
diff -urN linux-2.4.18/drivers/pcmcia/sa1100_generic.c linux-2.4.19/drivers/pcmcia/sa1100_generic.c
@@ -29,6 +29,10 @@
file under either the MPL or the GPL.
======================================================================*/
+/*
+ * Please see linux/Documentation/arm/SA1100/PCMCIA for more information
+ * on the low-level kernel interface.
+ */
#include <linux/module.h>
#include <linux/init.h>
@@ -43,6 +47,7 @@
#include <linux/notifier.h>
#include <linux/proc_fs.h>
#include <linux/version.h>
+#include <linux/cpufreq.h>
#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
@@ -62,338 +67,94 @@
static int pc_debug;
#endif
-MODULE_AUTHOR("John Dorsey <john+@cs.cmu.edu>");
-MODULE_DESCRIPTION("Linux PCMCIA Card Services: SA-1100 Socket Controller");
-
/* This structure maintains housekeeping state for each socket, such
* as the last known values of the card detect pins, or the Card Services
* callback value associated with the socket:
*/
-static struct sa1100_pcmcia_socket
-sa1100_pcmcia_socket[SA1100_PCMCIA_MAX_SOCK];
-
static int sa1100_pcmcia_socket_count;
+static struct sa1100_pcmcia_socket sa1100_pcmcia_socket[SA1100_PCMCIA_MAX_SOCK];
+#define PCMCIA_SOCKET(x) (sa1100_pcmcia_socket + (x))
/* Returned by the low-level PCMCIA interface: */
static struct pcmcia_low_level *pcmcia_low_level;
-/* Event poll timer structure */
static struct timer_list poll_timer;
-
-
-/* Prototypes for routines which are used internally: */
-
-static int sa1100_pcmcia_driver_init(void);
-static void sa1100_pcmcia_driver_shutdown(void);
-static void sa1100_pcmcia_task_handler(void *data);
-static void sa1100_pcmcia_poll_event(unsigned long data);
-static void sa1100_pcmcia_interrupt(int irq, void *dev,
- struct pt_regs *regs);
static struct tq_struct sa1100_pcmcia_task;
-#ifdef CONFIG_PROC_FS
-static int sa1100_pcmcia_proc_status(char *buf, char **start, off_t pos,
- int count, int *eof, void *data);
-#endif
-
-
-/* Prototypes for operations which are exported to the
- * new-and-impr^H^H^H^H^H^H^H^H^H^H in-kernel PCMCIA core:
- */
-
-static int sa1100_pcmcia_init(unsigned int sock);
-static int sa1100_pcmcia_suspend(unsigned int sock);
-static int sa1100_pcmcia_register_callback(unsigned int sock,
- void (*handler)(void *,
- unsigned int),
- void *info);
-static int sa1100_pcmcia_inquire_socket(unsigned int sock,
- socket_cap_t *cap);
-static int sa1100_pcmcia_get_status(unsigned int sock, u_int *value);
-static int sa1100_pcmcia_get_socket(unsigned int sock,
- socket_state_t *state);
-static int sa1100_pcmcia_set_socket(unsigned int sock,
- socket_state_t *state);
-static int sa1100_pcmcia_get_io_map(unsigned int sock,
- struct pccard_io_map *io);
-static int sa1100_pcmcia_set_io_map(unsigned int sock,
- struct pccard_io_map *io);
-static int sa1100_pcmcia_get_mem_map(unsigned int sock,
- struct pccard_mem_map *mem);
-static int sa1100_pcmcia_set_mem_map(unsigned int sock,
- struct pccard_mem_map *mem);
-#ifdef CONFIG_PROC_FS
-static void sa1100_pcmcia_proc_setup(unsigned int sock,
- struct proc_dir_entry *base);
-#endif
-
-static struct pccard_operations sa1100_pcmcia_operations = {
- sa1100_pcmcia_init,
- sa1100_pcmcia_suspend,
- sa1100_pcmcia_register_callback,
- sa1100_pcmcia_inquire_socket,
- sa1100_pcmcia_get_status,
- sa1100_pcmcia_get_socket,
- sa1100_pcmcia_set_socket,
- sa1100_pcmcia_get_io_map,
- sa1100_pcmcia_set_io_map,
- sa1100_pcmcia_get_mem_map,
- sa1100_pcmcia_set_mem_map,
-#ifdef CONFIG_PROC_FS
- sa1100_pcmcia_proc_setup
-#endif
-};
-
-#ifdef CONFIG_CPU_FREQ
-/* forward declaration */
-static struct notifier_block sa1100_pcmcia_notifier_block;
-#endif
-
-
-/* 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.
+/*
+ * sa1100_pcmcia_state_to_config
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
*
- * 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_h3600()) {
-#ifdef CONFIG_SA1100_H3600
- 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_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 = get_cclk_frequency() * 100;
-
- 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() */
-
-module_init(sa1100_pcmcia_driver_init);
-
-
-/* sa1100_pcmcia_driver_shutdown()
- * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- * Invokes the low-level kernel service to free IRQs associated with this
- * socket controller and reset GPIO edge detection.
+ * Convert PCMCIA socket state to our socket configure structure.
*/
-static void __exit sa1100_pcmcia_driver_shutdown(void){
+static struct pcmcia_configure
+sa1100_pcmcia_state_to_config(unsigned int sock, socket_state_t *state)
+{
+ struct pcmcia_configure conf;
- del_timer_sync(&poll_timer);
- unregister_ss_entry(&sa1100_pcmcia_operations);
-#ifdef CONFIG_CPU_FREQ
- cpufreq_unregister_notifier(&sa1100_pcmcia_notifier_block);
-#endif
- pcmcia_low_level->shutdown();
- flush_scheduled_tasks();
+ conf.sock = sock;
+ conf.vcc = state->Vcc;
+ conf.vpp = state->Vpp;
+ conf.output = state->flags & SS_OUTPUT_ENA ? 1 : 0;
+ conf.speaker = state->flags & SS_SPKR_ENA ? 1 : 0;
+ conf.reset = state->flags & SS_RESET ? 1 : 0;
+ conf.irq = state->io_irq != 0;
- DEBUG(1, "sa1100: shutdown complete\n");
+ return conf;
}
-module_exit(sa1100_pcmcia_driver_shutdown);
-
-
/* sa1100_pcmcia_init()
* ^^^^^^^^^^^^^^^^^^^^
- * We perform all of the interesting initialization tasks in
- * sa1100_pcmcia_driver_init().
+ *
+ * (Re-)Initialise the socket, turning on status interrupts
+ * and PCMCIA bus. This must wait for power to stabilise
+ * so that the card status signals report correctly.
*
* Returns: 0
*/
-static int sa1100_pcmcia_init(unsigned int sock){
-
+static int sa1100_pcmcia_init(unsigned int sock)
+{
+ struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
+ struct pcmcia_configure conf;
+
DEBUG(2, "%s(): initializing socket %u\n", __FUNCTION__, sock);
- return 0;
+ skt->cs_state = dead_socket;
+
+ conf = sa1100_pcmcia_state_to_config(sock, &dead_socket);
+
+ pcmcia_low_level->configure_socket(&conf);
+
+ return pcmcia_low_level->socket_init(sock);
}
-/* sa1100_pcmcia_suspend()
+/*
+ * sa1100_pcmcia_suspend()
* ^^^^^^^^^^^^^^^^^^^^^^^
- * We don't currently perform any actions on a suspend.
+ *
+ * Remove power on the socket, disable IRQs from the card.
+ * Turn off status interrupts, and disable the PCMCIA bus.
*
* Returns: 0
*/
static int sa1100_pcmcia_suspend(unsigned int sock)
{
+ struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
struct pcmcia_configure conf;
int ret;
DEBUG(2, "%s(): suspending socket %u\n", __FUNCTION__, sock);
- conf.sock = sock;
- conf.vcc = 0;
- conf.vpp = 0;
- conf.output = 0;
- conf.speaker = 0;
- conf.reset = 1;
+ conf = sa1100_pcmcia_state_to_config(sock, &dead_socket);
ret = pcmcia_low_level->configure_socket(&conf);
- if (ret == 0)
- sa1100_pcmcia_socket[sock].cs_state = dead_socket;
+ if (ret == 0) {
+ skt->cs_state = dead_socket;
+ ret = pcmcia_low_level->socket_suspend(sock);
+ }
return ret;
}
@@ -407,52 +168,50 @@
*
* Returns: an event mask for the given socket state.
*/
-static inline unsigned sa1100_pcmcia_events(struct pcmcia_state *state,
- struct pcmcia_state *prev_state,
- unsigned int mask,
- unsigned int flags){
- unsigned int events=0;
-
- if(state->detect!=prev_state->detect){
+static inline unsigned int
+sa1100_pcmcia_events(struct pcmcia_state *state,
+ struct pcmcia_state *prev_state,
+ unsigned int mask, unsigned int flags)
+{
+ unsigned int events = 0;
- DEBUG(2, "%s(): card detect value %u\n", __FUNCTION__, state->detect);
+ if (state->detect != prev_state->detect) {
+ DEBUG(3, "%s(): card detect value %u\n", __FUNCTION__, state->detect);
- events|=mask&SS_DETECT;
+ events |= SS_DETECT;
}
- if(state->ready!=prev_state->ready){
+ if (state->ready != prev_state->ready) {
+ DEBUG(3, "%s(): card ready value %u\n", __FUNCTION__, state->ready);
- DEBUG(2, "%s(): card ready value %u\n", __FUNCTION__, state->ready);
-
- events|=mask&((flags&SS_IOCARD)?0:SS_READY);
+ events |= flags & SS_IOCARD ? 0 : SS_READY;
}
- if(state->bvd1!=prev_state->bvd1){
-
- DEBUG(2, "%s(): card BVD1 value %u\n", __FUNCTION__, state->bvd1);
+ if (state->bvd1 != prev_state->bvd1) {
+ DEBUG(3, "%s(): card BVD1 value %u\n", __FUNCTION__, state->bvd1);
- events|=mask&(flags&SS_IOCARD)?SS_STSCHG:SS_BATDEAD;
+ events |= flags & SS_IOCARD ? SS_STSCHG : SS_BATDEAD;
}
- if(state->bvd2!=prev_state->bvd2){
+ if (state->bvd2 != prev_state->bvd2) {
+ DEBUG(3, "%s(): card BVD2 value %u\n", __FUNCTION__, state->bvd2);
- DEBUG(2, "%s(): card BVD2 value %u\n", __FUNCTION__, state->bvd2);
-
- events|=mask&(flags&SS_IOCARD)?0:SS_BATWARN;
+ events |= flags & SS_IOCARD ? 0 : SS_BATWARN;
}
- DEBUG(2, "events: %s%s%s%s%s%s\n",
- (events==0)?"<NONE>":"",
- (events&SS_DETECT)?"DETECT ":"",
- (events&SS_READY)?"READY ":"",
- (events&SS_BATDEAD)?"BATDEAD ":"",
- (events&SS_BATWARN)?"BATWARN ":"",
- (events&SS_STSCHG)?"STSCHG ":"");
+ *prev_state = *state;
- *prev_state=*state;
+ events &= mask;
- return events;
+ DEBUG(2, "events: %s%s%s%s%s%s\n",
+ events == 0 ? "<NONE>" : "",
+ events & SS_DETECT ? "DETECT " : "",
+ events & SS_READY ? "READY " : "",
+ events & SS_BATDEAD ? "BATDEAD " : "",
+ events & SS_BATWARN ? "BATWARN " : "",
+ events & SS_STSCHG ? "STSCHG " : "");
+ return events;
} /* sa1100_pcmcia_events() */
@@ -464,38 +223,43 @@
* callback) occurs in this thread rather than in the actual interrupt
* handler due to the use of scheduling operations in the PCMCIA core.
*/
-static void sa1100_pcmcia_task_handler(void *data) {
+static void sa1100_pcmcia_task_handler(void *data)
+{
struct pcmcia_state state[SA1100_PCMCIA_MAX_SOCK];
struct pcmcia_state_array state_array;
- int i, events, all_events, irq_status;
+ unsigned int all_events;
- DEBUG(2, "%s(): entering PCMCIA monitoring thread\n", __FUNCTION__);
+ DEBUG(4, "%s(): entering PCMCIA monitoring thread\n", __FUNCTION__);
- state_array.size=sa1100_pcmcia_socket_count;
- state_array.state=state;
+ state_array.size = sa1100_pcmcia_socket_count;
+ state_array.state = state;
do {
+ unsigned int events;
+ int ret, i;
- DEBUG(3, "%s(): interrogating low-level PCMCIA service\n", __FUNCTION__);
+ memset(state, 0, sizeof(state));
- if((irq_status=pcmcia_low_level->socket_state(&state_array))<0)
- printk(KERN_ERR "Error in kernel low-level PCMCIA service.\n");
+ DEBUG(4, "%s(): interrogating low-level PCMCIA service\n", __FUNCTION__);
- all_events=0;
+ ret = pcmcia_low_level->socket_state(&state_array);
+ if (ret < 0) {
+ printk(KERN_ERR "sa1100_pcmcia: unable to read socket status\n");
+ break;
+ }
- if(irq_status>0){
+ all_events = 0;
- for(i=0; i<state_array.size; ++i, all_events|=events)
- if((events=
- sa1100_pcmcia_events(&state[i],
- &sa1100_pcmcia_socket[i].k_state,
- sa1100_pcmcia_socket[i].cs_state.csc_mask,
- sa1100_pcmcia_socket[i].cs_state.flags)))
- if(sa1100_pcmcia_socket[i].handler!=NULL)
- sa1100_pcmcia_socket[i].handler(sa1100_pcmcia_socket[i].handler_info,
- events);
- }
+ for (i = 0; i < state_array.size; i++, all_events |= events) {
+ struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(i);
+ events = sa1100_pcmcia_events(&state[i], &skt->k_state,
+ skt->cs_state.csc_mask,
+ skt->cs_state.flags);
+
+ if (events && sa1100_pcmcia_socket[i].handler != NULL)
+ skt->handler(skt->handler_info, events);
+ }
} while(all_events);
} /* sa1100_pcmcia_task_handler() */
@@ -510,7 +274,7 @@
*/
static void sa1100_pcmcia_poll_event(unsigned long dummy)
{
- DEBUG(3, "%s(): polling for events\n", __FUNCTION__);
+ DEBUG(4, "%s(): polling for events\n", __FUNCTION__);
poll_timer.function = sa1100_pcmcia_poll_event;
poll_timer.expires = jiffies + SA1100_PCMCIA_POLL_PERIOD;
add_timer(&poll_timer);
@@ -527,7 +291,8 @@
* handling code performs scheduling operations which cannot be
* executed from within an interrupt context.
*/
-static void sa1100_pcmcia_interrupt(int irq, void *dev, struct pt_regs *regs){
+static void sa1100_pcmcia_interrupt(int irq, void *dev, struct pt_regs *regs)
+{
DEBUG(3, "%s(): servicing IRQ %d\n", __FUNCTION__, irq);
schedule_task(&sa1100_pcmcia_task);
}
@@ -546,17 +311,20 @@
*
* Returns: 0
*/
-static int sa1100_pcmcia_register_callback(unsigned int sock,
- void (*handler)(void *,
- unsigned int),
- void *info){
- if(handler==NULL){
- sa1100_pcmcia_socket[sock].handler=NULL;
+static int
+sa1100_pcmcia_register_callback(unsigned int sock,
+ void (*handler)(void *, unsigned int),
+ void *info)
+{
+ struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
+
+ if (handler == NULL) {
+ skt->handler = NULL;
MOD_DEC_USE_COUNT;
} else {
MOD_INC_USE_COUNT;
- sa1100_pcmcia_socket[sock].handler=handler;
- sa1100_pcmcia_socket[sock].handler_info=info;
+ skt->handler_info = info;
+ skt->handler = handler;
}
return 0;
@@ -580,51 +348,41 @@
* an offset which is applied to client-requested base I/O addresses
* in alloc_io_space().
*
- * Returns: 0 on success, -1 if no pin has been configured for `sock'
+ * SS_CAP_PAGE_REGS: used by setup_cis_mem() in cistpl.c to set the
+ * force_low argument to validate_mem() in rsrc_mgr.c -- since in
+ * general, the mapped * addresses of the PCMCIA memory regions
+ * will not be within 0xffff, setting force_low would be
+ * undesirable.
+ *
+ * SS_CAP_STATIC_MAP: don't bother with the (user-configured) memory
+ * resource database; we instead pass up physical address ranges
+ * and allow other parts of Card Services to deal with remapping.
+ *
+ * SS_CAP_PCCARD: we can deal with 16-bit PCMCIA & CF cards, but
+ * not 32-bit CardBus devices.
+ *
+ * Return value is irrelevant; the pcmcia subsystem ignores it.
*/
-static int sa1100_pcmcia_inquire_socket(unsigned int sock,
- socket_cap_t *cap){
- struct pcmcia_irq_info irq_info;
-
- DEBUG(3, "%s() for sock %u\n", __FUNCTION__, sock);
-
- if(sock>=sa1100_pcmcia_socket_count){
- printk(KERN_ERR "sa1100: socket %u not configured\n", sock);
- return -1;
- }
+static int
+sa1100_pcmcia_inquire_socket(unsigned int sock, socket_cap_t *cap)
+{
+ struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
+ int ret = -1;
- /* SS_CAP_PAGE_REGS: used by setup_cis_mem() in cistpl.c to set the
- * force_low argument to validate_mem() in rsrc_mgr.c -- since in
- * general, the mapped * addresses of the PCMCIA memory regions
- * will not be within 0xffff, setting force_low would be
- * undesirable.
- *
- * SS_CAP_STATIC_MAP: don't bother with the (user-configured) memory
- * resource database; we instead pass up physical address ranges
- * and allow other parts of Card Services to deal with remapping.
- *
- * SS_CAP_PCCARD: we can deal with 16-bit PCMCIA & CF cards, but
- * not 32-bit CardBus devices.
- */
- cap->features=(SS_CAP_PAGE_REGS | SS_CAP_STATIC_MAP | SS_CAP_PCCARD);
+ DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock);
- irq_info.sock=sock;
- irq_info.irq=-1;
+ if (sock < sa1100_pcmcia_socket_count) {
+ cap->features = SS_CAP_PAGE_REGS | SS_CAP_STATIC_MAP | SS_CAP_PCCARD;
+ cap->irq_mask = 0;
+ cap->map_size = PAGE_SIZE;
+ cap->pci_irq = skt->irq;
+ cap->io_offset = (unsigned long)skt->virt_io;
- if(pcmcia_low_level->get_irq_info(&irq_info)<0){
- printk(KERN_ERR "Error obtaining IRQ info from kernel for socket %u\n",
- sock);
- return -1;
+ ret = 0;
}
- cap->irq_mask=0;
- cap->map_size=PAGE_SIZE;
- cap->pci_irq=irq_info.irq;
- cap->io_offset=sa1100_pcmcia_socket[sock].virt_io;
-
- return 0;
-
-} /* sa1100_pcmcia_inquire_socket() */
+ return ret;
+}
/* sa1100_pcmcia_get_status()
@@ -643,58 +401,61 @@
*
* Returns: 0
*/
-static int sa1100_pcmcia_get_status(unsigned int sock,
- unsigned int *status){
+static int
+sa1100_pcmcia_get_status(unsigned int sock, unsigned int *status)
+{
+ struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
struct pcmcia_state state[SA1100_PCMCIA_MAX_SOCK];
struct pcmcia_state_array state_array;
+ unsigned int stat;
- DEBUG(3, "%s() for sock %u\n", __FUNCTION__, sock);
+ DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock);
- state_array.size=sa1100_pcmcia_socket_count;
- state_array.state=state;
+ 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");
+ memset(state, 0, sizeof(state));
+
+ if ((pcmcia_low_level->socket_state(&state_array)) < 0) {
+ printk(KERN_ERR "sa1100_pcmcia: unable to get socket status\n");
return -1;
}
- sa1100_pcmcia_socket[sock].k_state=state[sock];
-
- *status=state[sock].detect?SS_DETECT:0;
+ skt->k_state = state[sock];
- *status|=state[sock].ready?SS_READY:0;
+ stat = state[sock].detect ? SS_DETECT : 0;
+ stat |= state[sock].ready ? SS_READY : 0;
+ stat |= state[sock].vs_3v ? SS_3VCARD : 0;
+ stat |= state[sock].vs_Xv ? SS_XVCARD : 0;
/* The power status of individual sockets is not available
* explicitly from the hardware, so we just remember the state
* and regurgitate it upon request:
*/
- *status|=sa1100_pcmcia_socket[sock].cs_state.Vcc?SS_POWERON:0;
+ stat |= skt->cs_state.Vcc ? SS_POWERON : 0;
- if(sa1100_pcmcia_socket[sock].cs_state.flags&SS_IOCARD)
- *status|=state[sock].bvd1?SS_STSCHG:0;
+ if (skt->cs_state.flags & SS_IOCARD)
+ stat |= state[sock].bvd1 ? SS_STSCHG : 0;
else {
- if(state[sock].bvd1==0)
- *status|=SS_BATDEAD;
- else if(state[sock].bvd2==0)
- *status|=SS_BATWARN;
+ if (state[sock].bvd1 == 0)
+ stat |= SS_BATDEAD;
+ else if (state[sock].bvd2 == 0)
+ stat |= SS_BATWARN;
}
- *status|=state[sock].vs_3v?SS_3VCARD:0;
-
- *status|=state[sock].vs_Xv?SS_XVCARD:0;
-
DEBUG(3, "\tstatus: %s%s%s%s%s%s%s%s\n",
- (*status&SS_DETECT)?"DETECT ":"",
- (*status&SS_READY)?"READY ":"",
- (*status&SS_BATDEAD)?"BATDEAD ":"",
- (*status&SS_BATWARN)?"BATWARN ":"",
- (*status&SS_POWERON)?"POWERON ":"",
- (*status&SS_STSCHG)?"STSCHG ":"",
- (*status&SS_3VCARD)?"3VCARD ":"",
- (*status&SS_XVCARD)?"XVCARD ":"");
+ stat & SS_DETECT ? "DETECT " : "",
+ stat & SS_READY ? "READY " : "",
+ stat & SS_BATDEAD ? "BATDEAD " : "",
+ stat & SS_BATWARN ? "BATWARN " : "",
+ stat & SS_POWERON ? "POWERON " : "",
+ stat & SS_STSCHG ? "STSCHG " : "",
+ stat & SS_3VCARD ? "3VCARD " : "",
+ stat & SS_XVCARD ? "XVCARD " : "");
- return 0;
+ *status = stat;
+ return 0;
} /* sa1100_pcmcia_get_status() */
@@ -706,20 +467,18 @@
*
* Returns: 0
*/
-static int sa1100_pcmcia_get_socket(unsigned int sock,
- socket_state_t *state){
+static int
+sa1100_pcmcia_get_socket(unsigned int sock, socket_state_t *state)
+{
+ struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
- DEBUG(3, "%s() for sock %u\n", __FUNCTION__, sock);
+ DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock);
- /* This information was given to us in an earlier call to set_socket(),
- * so we're just regurgitating it here:
- */
- *state=sa1100_pcmcia_socket[sock].cs_state;
+ *state = skt->cs_state;
return 0;
}
-
/* sa1100_pcmcia_set_socket()
* ^^^^^^^^^^^^^^^^^^^^^^^^^^
* Implements the set_socket() operation for the in-kernel PCMCIA
@@ -730,14 +489,15 @@
*
* Returns: 0
*/
-static int sa1100_pcmcia_set_socket(unsigned int sock,
- socket_state_t *state){
- struct pcmcia_configure configure;
+static int
+sa1100_pcmcia_set_socket(unsigned int sock, socket_state_t *state)
+{
+ struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
+ struct pcmcia_configure conf;
- DEBUG(3, "%s() for sock %u\n", __FUNCTION__, sock);
+ DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock);
- DEBUG(3, "\tmask: %s%s%s%s%s%s\n\tflags: %s%s%s%s%s%s\n"
- "\tVcc %d Vpp %d irq %d\n",
+ DEBUG(3, "\tmask: %s%s%s%s%s%s\n\tflags: %s%s%s%s%s%s\n",
(state->csc_mask==0)?"<NONE>":"",
(state->csc_mask&SS_DETECT)?"DETECT ":"",
(state->csc_mask&SS_READY)?"READY ":"",
@@ -749,25 +509,20 @@
(state->flags&SS_IOCARD)?"IOCARD ":"",
(state->flags&SS_RESET)?"RESET ":"",
(state->flags&SS_SPKR_ENA)?"SPKR_ENA ":"",
- (state->flags&SS_OUTPUT_ENA)?"OUTPUT_ENA ":"",
+ (state->flags&SS_OUTPUT_ENA)?"OUTPUT_ENA ":"");
+ DEBUG(3, "\tVcc %d Vpp %d irq %d\n",
state->Vcc, state->Vpp, state->io_irq);
- configure.sock=sock;
- configure.vcc=state->Vcc;
- configure.vpp=state->Vpp;
- configure.output=(state->flags&SS_OUTPUT_ENA)?1:0;
- configure.speaker=(state->flags&SS_SPKR_ENA)?1:0;
- configure.reset=(state->flags&SS_RESET)?1:0;
+ conf = sa1100_pcmcia_state_to_config(sock, state);
- if(pcmcia_low_level->configure_socket(&configure)<0){
- printk(KERN_ERR "Unable to configure socket %u\n", sock);
+ if (pcmcia_low_level->configure_socket(&conf) < 0) {
+ printk(KERN_ERR "sa1100_pcmcia: unable to configure socket %d\n", sock);
return -1;
}
- sa1100_pcmcia_socket[sock].cs_state=*state;
+ skt->cs_state = *state;
return 0;
-
} /* sa1100_pcmcia_set_socket() */
@@ -779,20 +534,20 @@
*
* Returns: 0 on success, -1 if the map index was out of range
*/
-static int sa1100_pcmcia_get_io_map(unsigned int sock,
- struct pccard_io_map *map){
+static int
+sa1100_pcmcia_get_io_map(unsigned int sock, struct pccard_io_map *map)
+{
+ struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
+ int ret = -1;
- DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock);
+ DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock);
- if(map->map>=MAX_IO_WIN){
- printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__,
- map->map);
- return -1;
+ if (map->map < MAX_IO_WIN) {
+ *map = skt->io_map[map->map];
+ ret = 0;
}
- *map=sa1100_pcmcia_socket[sock].io_map[map->map];
-
- return 0;
+ return ret;
}
@@ -805,16 +560,16 @@
*
* Returns: 0 on success, -1 on error
*/
-static int sa1100_pcmcia_set_io_map(unsigned int sock,
- struct pccard_io_map *map){
- unsigned int clock, speed;
- unsigned long mecr, start;
+static int
+sa1100_pcmcia_set_io_map(unsigned int sock, struct pccard_io_map *map)
+{
+ struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
- DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock);
+ DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock);
- DEBUG(4, "\tmap %u speed %u\n\tstart 0x%08lx stop 0x%08lx\n"
- "\tflags: %s%s%s%s%s%s%s%s\n",
- map->map, map->speed, map->start, map->stop,
+ DEBUG(3, "\tmap %u speed %u\n\tstart 0x%08x stop 0x%08x\n",
+ map->map, map->speed, map->start, map->stop);
+ 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 ":"",
@@ -824,45 +579,45 @@
(map->flags&MAP_USE_WAIT)?"USE_WAIT ":"",
(map->flags&MAP_PREFETCH)?"PREFETCH ":"");
- if(map->map>=MAX_IO_WIN){
+ if (map->map >= MAX_IO_WIN) {
printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__,
map->map);
return -1;
}
- if(map->flags&MAP_ACTIVE){
+ if (map->flags & MAP_ACTIVE) {
+ unsigned int clock, speed = map->speed;
+ unsigned long mecr;
- speed=(map->speed>0)?map->speed:SA1100_PCMCIA_IO_ACCESS;
+ if (speed == 0)
+ speed = SA1100_PCMCIA_IO_ACCESS;
- clock = get_cclk_frequency() * 100;
+ clock = cpufreq_get(0);
- mecr=MECR;
+ mecr = MECR;
MECR_BSIO_SET(mecr, sock, sa1100_pcmcia_mecr_bs(speed, clock));
- sa1100_pcmcia_socket[sock].speed_io=speed;
+ skt->speed_io = 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;
-
+ MECR = mecr;
}
- start=map->start;
+ if (map->stop == 1)
+ map->stop = PAGE_SIZE-1;
- if(map->stop==1)
- map->stop=PAGE_SIZE-1;
+ map->stop -= map->start;
+ map->stop += (unsigned long)skt->virt_io;
+ map->start = (unsigned long)skt->virt_io;
- map->start=sa1100_pcmcia_socket[sock].virt_io;
- map->stop=map->start+(map->stop-start);
-
- sa1100_pcmcia_socket[sock].io_map[map->map]=*map;
+ skt->io_map[map->map] = *map;
return 0;
-
} /* sa1100_pcmcia_set_io_map() */
@@ -875,20 +630,20 @@
*
* Returns: 0 on success, -1 if the map index was out of range
*/
-static int sa1100_pcmcia_get_mem_map(unsigned int sock,
- struct pccard_mem_map *map){
+static int
+sa1100_pcmcia_get_mem_map(unsigned int sock, struct pccard_mem_map *map)
+{
+ struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
+ int ret = -1;
- DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock);
+ DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock);
- if(map->map>=MAX_WIN){
- printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__,
- map->map);
- return -1;
+ if (map->map < MAX_WIN) {
+ *map = skt->mem_map[map->map];
+ ret = 0;
}
- *map=sa1100_pcmcia_socket[sock].mem_map[map->map];
-
- return 0;
+ return ret;
}
@@ -901,18 +656,18 @@
*
* 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;
+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(4, "%s() for sock %u\n", __FUNCTION__, sock);
+ DEBUG(2, "%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>":"",
+ 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 ":"",
@@ -921,177 +676,175 @@
(map->flags&MAP_ATTRIB)?"ATTRIB ":"",
(map->flags&MAP_USE_WAIT)?"USE_WAIT ":"");
- if(map->map>=MAX_WIN){
+ 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->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(map->speed > 0)
- speed = map->speed;
- else
- switch(sa1100_pcmcia_socket[sock].cs_state.Vcc){
- case 33:
+ if (speed == 0) {
+ if (skt->cs_state.Vcc == 33)
speed = SA1100_PCMCIA_3V_MEM_ACCESS;
- break;
- default:
+ else
speed = SA1100_PCMCIA_5V_MEM_ACCESS;
- }
+ }
- clock = get_cclk_frequency() * 100;
-
- mecr=MECR;
-
- if(map->flags&MAP_ATTRIB){
+ clock = cpufreq_get(0);
- MECR_BSA_SET(mecr, sock, sa1100_pcmcia_mecr_bs(speed, clock));
- sa1100_pcmcia_socket[sock].speed_attr=speed;
+ /* 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));
- sa1100_pcmcia_socket[sock].speed_mem=speed;
-
+ 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;
+ MECR = mecr;
}
- start=map->sys_start;
-
- if(map->sys_stop==0)
- map->sys_stop=PAGE_SIZE-1;
+ start = (map->flags & MAP_ATTRIB) ? skt->phys_attr : skt->phys_mem;
- map->sys_start=(map->flags & MAP_ATTRIB)?\
- sa1100_pcmcia_socket[sock].phys_attr:\
- sa1100_pcmcia_socket[sock].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_stop -= map->sys_start;
+ map->sys_stop += start;
+ map->sys_start = start;
- sa1100_pcmcia_socket[sock].mem_map[map->map]=*map;
+ skt->mem_map[map->map] = *map;
return 0;
-
} /* sa1100_pcmcia_set_mem_map() */
#if defined(CONFIG_PROC_FS)
-/* sa1100_pcmcia_proc_setup()
- * ^^^^^^^^^^^^^^^^^^^^^^^^^^
- * Implements the proc_setup() operation for the in-kernel PCMCIA
- * service (formerly SS_ProcSetup in Card Services).
- *
- * Returns: 0 on success, -1 on error
- */
-static void sa1100_pcmcia_proc_setup(unsigned int sock,
- struct proc_dir_entry *base){
- struct proc_dir_entry *entry;
-
- DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock);
-
- if((entry=create_proc_entry("status", 0, base))==NULL){
- printk(KERN_ERR "Unable to install \"status\" procfs entry\n");
- return;
- }
-
- entry->read_proc=sa1100_pcmcia_proc_status;
- entry->data=(void *)sock;
-}
-
-
/* sa1100_pcmcia_proc_status()
* ^^^^^^^^^^^^^^^^^^^^^^^^^^^
* Implements the /proc/bus/pccard/??/status file.
*
* Returns: the number of characters added to the buffer
*/
-static int sa1100_pcmcia_proc_status(char *buf, char **start, off_t pos,
- int count, int *eof, void *data){
- char *p=buf;
- unsigned int sock=(unsigned int)data;
- unsigned int clock = get_cclk_frequency() * 100;
+static int
+sa1100_pcmcia_proc_status(char *buf, char **start, off_t pos,
+ int count, int *eof, void *data)
+{
+ unsigned int sock = (unsigned int)data;
+ unsigned int clock = cpufreq_get(0);
+ struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
unsigned long mecr = MECR;
+ char *p = buf;
- p+=sprintf(p, "k_flags : %s%s%s%s%s%s%s\n",
- sa1100_pcmcia_socket[sock].k_state.detect?"detect ":"",
- sa1100_pcmcia_socket[sock].k_state.ready?"ready ":"",
- sa1100_pcmcia_socket[sock].k_state.bvd1?"bvd1 ":"",
- sa1100_pcmcia_socket[sock].k_state.bvd2?"bvd2 ":"",
- sa1100_pcmcia_socket[sock].k_state.wrprot?"wrprot ":"",
- sa1100_pcmcia_socket[sock].k_state.vs_3v?"vs_3v ":"",
- sa1100_pcmcia_socket[sock].k_state.vs_Xv?"vs_Xv ":"");
+ p+=sprintf(p, "k_state : %s%s%s%s%s%s%s\n",
+ skt->k_state.detect ? "detect " : "",
+ skt->k_state.ready ? "ready " : "",
+ skt->k_state.bvd1 ? "bvd1 " : "",
+ skt->k_state.bvd2 ? "bvd2 " : "",
+ skt->k_state.wrprot ? "wrprot " : "",
+ skt->k_state.vs_3v ? "vs_3v " : "",
+ skt->k_state.vs_Xv ? "vs_Xv " : "");
p+=sprintf(p, "status : %s%s%s%s%s%s%s%s%s\n",
- sa1100_pcmcia_socket[sock].k_state.detect?"SS_DETECT ":"",
- sa1100_pcmcia_socket[sock].k_state.ready?"SS_READY ":"",
- sa1100_pcmcia_socket[sock].cs_state.Vcc?"SS_POWERON ":"",
- sa1100_pcmcia_socket[sock].cs_state.flags&SS_IOCARD?\
- "SS_IOCARD ":"",
- (sa1100_pcmcia_socket[sock].cs_state.flags&SS_IOCARD &&
- sa1100_pcmcia_socket[sock].k_state.bvd1)?"SS_STSCHG ":"",
- ((sa1100_pcmcia_socket[sock].cs_state.flags&SS_IOCARD)==0 &&
- (sa1100_pcmcia_socket[sock].k_state.bvd1==0))?"SS_BATDEAD ":"",
- ((sa1100_pcmcia_socket[sock].cs_state.flags&SS_IOCARD)==0 &&
- (sa1100_pcmcia_socket[sock].k_state.bvd2==0))?"SS_BATWARN ":"",
- sa1100_pcmcia_socket[sock].k_state.vs_3v?"SS_3VCARD ":"",
- sa1100_pcmcia_socket[sock].k_state.vs_Xv?"SS_XVCARD ":"");
+ skt->k_state.detect ? "SS_DETECT " : "",
+ skt->k_state.ready ? "SS_READY " : "",
+ skt->cs_state.Vcc ? "SS_POWERON " : "",
+ skt->cs_state.flags & SS_IOCARD ? "SS_IOCARD " : "",
+ (skt->cs_state.flags & SS_IOCARD &&
+ skt->k_state.bvd1) ? "SS_STSCHG " : "",
+ ((skt->cs_state.flags & SS_IOCARD)==0 &&
+ (skt->k_state.bvd1==0)) ? "SS_BATDEAD " : "",
+ ((skt->cs_state.flags & SS_IOCARD)==0 &&
+ (skt->k_state.bvd2==0)) ? "SS_BATWARN " : "",
+ skt->k_state.vs_3v ? "SS_3VCARD " : "",
+ skt->k_state.vs_Xv ? "SS_XVCARD " : "");
p+=sprintf(p, "mask : %s%s%s%s%s\n",
- sa1100_pcmcia_socket[sock].cs_state.csc_mask&SS_DETECT?\
- "SS_DETECT ":"",
- sa1100_pcmcia_socket[sock].cs_state.csc_mask&SS_READY?\
- "SS_READY ":"",
- sa1100_pcmcia_socket[sock].cs_state.csc_mask&SS_BATDEAD?\
- "SS_BATDEAD ":"",
- sa1100_pcmcia_socket[sock].cs_state.csc_mask&SS_BATWARN?\
- "SS_BATWARN ":"",
- sa1100_pcmcia_socket[sock].cs_state.csc_mask&SS_STSCHG?\
- "SS_STSCHG ":"");
+ skt->cs_state.csc_mask & SS_DETECT ? "SS_DETECT " : "",
+ skt->cs_state.csc_mask & SS_READY ? "SS_READY " : "",
+ skt->cs_state.csc_mask & SS_BATDEAD ? "SS_BATDEAD " : "",
+ skt->cs_state.csc_mask & SS_BATWARN ? "SS_BATWARN " : "",
+ skt->cs_state.csc_mask & SS_STSCHG ? "SS_STSCHG " : "");
p+=sprintf(p, "cs_flags : %s%s%s%s%s\n",
- sa1100_pcmcia_socket[sock].cs_state.flags&SS_PWR_AUTO?\
- "SS_PWR_AUTO ":"",
- sa1100_pcmcia_socket[sock].cs_state.flags&SS_IOCARD?\
- "SS_IOCARD ":"",
- sa1100_pcmcia_socket[sock].cs_state.flags&SS_RESET?\
- "SS_RESET ":"",
- sa1100_pcmcia_socket[sock].cs_state.flags&SS_SPKR_ENA?\
- "SS_SPKR_ENA ":"",
- sa1100_pcmcia_socket[sock].cs_state.flags&SS_OUTPUT_ENA?\
- "SS_OUTPUT_ENA ":"");
-
- p+=sprintf(p, "Vcc : %d\n", sa1100_pcmcia_socket[sock].cs_state.Vcc);
-
- p+=sprintf(p, "Vpp : %d\n", sa1100_pcmcia_socket[sock].cs_state.Vpp);
-
- p+=sprintf(p, "irq : %d\n", sa1100_pcmcia_socket[sock].cs_state.io_irq);
+ skt->cs_state.flags & SS_PWR_AUTO ? "SS_PWR_AUTO " : "",
+ skt->cs_state.flags & SS_IOCARD ? "SS_IOCARD " : "",
+ skt->cs_state.flags & SS_RESET ? "SS_RESET " : "",
+ skt->cs_state.flags & SS_SPKR_ENA ? "SS_SPKR_ENA " : "",
+ skt->cs_state.flags & SS_OUTPUT_ENA ? "SS_OUTPUT_ENA " : "");
+
+ p+=sprintf(p, "Vcc : %d\n", skt->cs_state.Vcc);
+ p+=sprintf(p, "Vpp : %d\n", skt->cs_state.Vpp);
+ p+=sprintf(p, "IRQ : %d\n", skt->cs_state.io_irq);
- p+=sprintf(p, "I/O : %u (%u)\n", sa1100_pcmcia_socket[sock].speed_io,
+ p+=sprintf(p, "I/O : %u (%u)\n", skt->speed_io,
sa1100_pcmcia_cmd_time(clock, MECR_BSIO_GET(mecr, sock)));
- p+=sprintf(p, "attribute: %u (%u)\n", sa1100_pcmcia_socket[sock].speed_attr,
+ p+=sprintf(p, "attribute: %u (%u)\n", skt->speed_attr,
sa1100_pcmcia_cmd_time(clock, MECR_BSA_GET(mecr, sock)));
- p+=sprintf(p, "common : %u (%u)\n", sa1100_pcmcia_socket[sock].speed_mem,
+ p+=sprintf(p, "common : %u (%u)\n", skt->speed_mem,
sa1100_pcmcia_cmd_time(clock, MECR_BSM_GET(mecr, sock)));
return p-buf;
}
+/* sa1100_pcmcia_proc_setup()
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ * Implements the proc_setup() operation for the in-kernel PCMCIA
+ * service (formerly SS_ProcSetup in Card Services).
+ *
+ * Returns: 0 on success, -1 on error
+ */
+static void
+sa1100_pcmcia_proc_setup(unsigned int sock, struct proc_dir_entry *base)
+{
+ struct proc_dir_entry *entry;
+
+ DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock);
+
+ if ((entry = create_proc_entry("status", 0, base)) == NULL){
+ printk(KERN_ERR "unable to install \"status\" procfs entry\n");
+ return;
+ }
+
+ entry->read_proc = sa1100_pcmcia_proc_status;
+ entry->data = (void *)sock;
+}
+
#endif /* defined(CONFIG_PROC_FS) */
+static struct pccard_operations sa1100_pcmcia_operations = {
+ init: sa1100_pcmcia_init,
+ suspend: sa1100_pcmcia_suspend,
+ register_callback: sa1100_pcmcia_register_callback,
+ inquire_socket: sa1100_pcmcia_inquire_socket,
+ get_status: sa1100_pcmcia_get_status,
+ get_socket: sa1100_pcmcia_get_socket,
+ set_socket: sa1100_pcmcia_set_socket,
+ get_io_map: sa1100_pcmcia_get_io_map,
+ set_io_map: sa1100_pcmcia_set_io_map,
+ get_mem_map: sa1100_pcmcia_get_mem_map,
+ set_mem_map: sa1100_pcmcia_set_mem_map,
+#ifdef CONFIG_PROC_FS
+ proc_setup: sa1100_pcmcia_proc_setup
+#endif
+};
#ifdef CONFIG_CPU_FREQ
@@ -1101,7 +854,8 @@
* 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){
+static void sa1100_pcmcia_update_mecr(unsigned int clock)
+{
unsigned int sock;
unsigned long mecr = MECR;
@@ -1132,53 +886,293 @@
*
* Returns: 0 on success, -1 on error
*/
-static int sa1100_pcmcia_notifier(struct notifier_block *nb,
- unsigned long val, void *data){
+static int
+sa1100_pcmcia_notifier(struct notifier_block *nb, unsigned long val,
+ void *data)
+{
struct cpufreq_info *ci = data;
- switch(val){
- case CPUFREQ_MINMAX:
-
- break;
-
+ switch (val) {
case CPUFREQ_PRECHANGE:
-
- if(ci->new_freq > ci->old_freq){
+ if (ci->new_freq > ci->old_freq) {
DEBUG(2, "%s(): new frequency %u.%uMHz > %u.%uMHz, pre-updating\n",
__FUNCTION__,
ci->new_freq / 1000, (ci->new_freq / 100) % 10,
ci->old_freq / 1000, (ci->old_freq / 100) % 10);
sa1100_pcmcia_update_mecr(ci->new_freq);
}
-
break;
case CPUFREQ_POSTCHANGE:
-
- if(ci->new_freq < ci->old_freq){
+ if (ci->new_freq < ci->old_freq) {
DEBUG(2, "%s(): new frequency %u.%uMHz < %u.%uMHz, post-updating\n",
__FUNCTION__,
ci->new_freq / 1000, (ci->new_freq / 100) % 10,
ci->old_freq / 1000, (ci->old_freq / 100) % 10);
sa1100_pcmcia_update_mecr(ci->new_freq);
}
-
break;
-
- default:
- printk(KERN_ERR "%s(): unknown CPU frequency event %lx\n", __FUNCTION__,
- val);
- return -1;
-
}
return 0;
-
}
static struct notifier_block sa1100_pcmcia_notifier_block = {
notifier_call: sa1100_pcmcia_notifier
};
+#endif
+static int __init sa1100_pcmcia_machine_init(void)
+{
+#ifdef CONFIG_SA1100_ASSABET
+ if(machine_is_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
+#ifdef CONFIG_SA1100_BADGE4
+ if (machine_is_badge4())
+ pcmcia_low_level = &badge4_pcmcia_ops;
+#endif
+#ifdef CONFIG_SA1100_FREEBIRD
+ if (machine_is_freebird())
+ pcmcia_low_level = &freebird_pcmcia_ops;
+#endif
+#ifdef CONFIG_SA1100_H3600
+ if (machine_is_h3600())
+ pcmcia_low_level = &h3600_pcmcia_ops;
+#endif
+#ifdef CONFIG_SA1100_CERF
+ if (machine_is_cerf())
+ pcmcia_low_level = &cerf_pcmcia_ops;
+#endif
+#ifdef CONFIG_SA1100_GRAPHICSCLIENT
+ if (machine_is_graphicsclient())
+ pcmcia_low_level = &gcplus_pcmcia_ops;
+#endif
+#ifdef CONFIG_SA1100_XP860
+ if (machine_is_xp860())
+ pcmcia_low_level = &xp860_pcmcia_ops;
+#endif
+#ifdef CONFIG_SA1100_YOPY
+ if (machine_is_yopy())
+ pcmcia_low_level = &yopy_pcmcia_ops;
+#endif
+#ifdef CONFIG_SA1100_SHANNON
+ if (machine_is_shannon())
+ pcmcia_low_level = &shannon_pcmcia_ops;
+#endif
+#ifdef CONFIG_SA1100_PANGOLIN
+ if (machine_is_pangolin())
+ pcmcia_low_level = &pangolin_pcmcia_ops;
+#endif
+#ifdef CONFIG_SA1100_JORNADA720
+ if (machine_is_jornada720())
+ pcmcia_low_level = &jornada720_pcmcia_ops;
+#endif
+#ifdef CONFIG_SA1100_PFS168
+ if(machine_is_pfs168())
+ pcmcia_low_level = &pfs168_pcmcia_ops;
#endif
+#ifdef CONFIG_SA1100_FLEXANET
+ if(machine_is_flexanet())
+ pcmcia_low_level = &flexanet_pcmcia_ops;
+#endif
+#ifdef CONFIG_SA1100_SIMPAD
+ if(machine_is_simpad())
+ pcmcia_low_level = &simpad_pcmcia_ops;
+#endif
+#ifdef CONFIG_SA1100_GRAPHICSMASTER
+ if(machine_is_graphicsmaster())
+ pcmcia_low_level = &graphicsmaster_pcmcia_ops;
+#endif
+#ifdef CONFIG_SA1100_ADSBITSY
+ if(machine_is_adsbitsy())
+ pcmcia_low_level = &adsbitsy_pcmcia_ops;
+#endif
+#ifdef CONFIG_SA1100_STORK
+ if(machine_is_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;
+ }
+
+ return 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.
+ *
+ * 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 = 0;
+
+ 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() */
+
+/* sa1100_pcmcia_driver_shutdown()
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ * Invokes the low-level kernel service to free IRQs associated with this
+ * socket controller and reset GPIO edge detection.
+ */
+static void __exit sa1100_pcmcia_driver_shutdown(void)
+{
+ int i;
+
+ del_timer_sync(&poll_timer);
+
+ unregister_ss_entry(&sa1100_pcmcia_operations);
+
+#ifdef CONFIG_CPU_FREQ
+ cpufreq_unregister_notifier(&sa1100_pcmcia_notifier_block);
+#endif
+
+ 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();
+
+ flush_scheduled_tasks();
+}
+
+MODULE_AUTHOR("John Dorsey <john+@cs.cmu.edu>");
+MODULE_DESCRIPTION("Linux PCMCIA Card Services: SA-1100 Socket Controller");
+MODULE_LICENSE("Dual MPL/GPL");
+
+module_init(sa1100_pcmcia_driver_init);
+module_exit(sa1100_pcmcia_driver_shutdown);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)