www.pudn.com > efs.rar > fs_hotplug.c
/***********************************************************************
* fs_hotplug.c
*
* EFS2 hotplug manager.
* Copyright (C) 2005-2006 QUALCOMM, Inc.
*
* Auto mount/umount hot-insertable devices in EFS2.
*
***********************************************************************/
/*===========================================================================
EDIT HISTORY FOR MODULE
This section contains comments describing changes made to the module.
Notice that changes are listed in reverse chronological order.
$Header: //depot/asic/MSMSHARED/services/efs/MSM_EFS.01.02/fs_hotplug.c#39 $ $DateTime: 2006/11/13 14:44:34 $ $Author: davidb $
when who what, where, why
---------- --- ---------------------------------------------------------
2006-11-09 sch Added implementation of hotplug_dev_write_udata
2006-11-09 sh Removed remote hotplug altogether.
2006-10-17 sh Always poll from hotplug task, and on media change
2006-10-17 sh Count hotplug read/write operations for benchmarking.
2006-10-16 sh Change lock/unlock functions to return int status.
2006-10-03 sh Fixed some ZPRINT line endings.
2006-09-20 sh Renamed TYPE_ values to have HOTPLUG prefix.
2006-09-10 sh Removed prohibited %s from MSG calls.
2006-09-06 sh Lint cleanup
2006-08-27 sh Allow HFAT or SFAT calls for formatting.
2006-06-28 sh Hold FS_GLOBAL lock only for SD's is_present()
2006-06-25 sh Initialize was_present instead of sd_present
2006-06-12 sh Fix the return status for fat_format.
2006-06-06 sh Added NULL device
2006-06-05 sh Added more feature flag safeguards
2006-06-02 sh Added reset handler
2006-05-25 sh Removed redundant nodev mount from fat_mount
2006-05-25 sh Simplified HOTPLUG vs COLDPLUG switches
2006-05-23 sch Removed device open from hotplug_unlock_dev
2006-05-23 sh Added FTL to hotplug.
2006-05-16 sh Added hotplug_dev_is_mounted()
2006-05-13 sh Fixed error in debugging print
2006-05-11 sh Renamed efs_hotplug_... to hotplug_...
2006-05-10 sh Moved common 'format' up one level.
2006-05-10 sh Replaced DRV_GEOMETRY_DESC with block size & count
2006-05-10 sh Added device access functions
2006-05-08 sh Corrected typo in ZPRINTF debug message
2006-05-08 sh Leave mountpoint directories present as NODEV
2006-05-05 sh Allow target override of default poll interval
2006-05-04 sh Close device on lock_dev, and open it for mount
2006-05-03 sh Added FTL to Hotplug
2006-05-03 sh Made lock_card device-specific
2006-04-22 sh Moved all private definitions into fs_hotplug_i.h
2006-04-18 sh Poll again immediately if any chages were detected
2006-04-17 sh Renamed lock/unlock card functions.
2006-04-17 nrs Moved is_mounted to fs_hotplug_remote
2006-04-14 sh Added more debug messages.
2006-04-14 sh Code review feedback implemented.
2006-04-13 sh Allow compilation without USB Mass Storage
2006-03-31 sch Modified hotplug_format to ignore leading slash
2006-03-31 sh USB unmount
2006-03-31 sh Lint cleanup
2006-03-28 nrs Fix typo in unmount code
2006-03-28 sch Use table-based hotplug.
2006-03-10 sch Added USB mass storage support
2006-03-21 nrs Add multi-processor support
2006-01-19 nrs Allocate SFAT memory structures if using MMC
2006-01-10 sh Fix Compiler warning again
2005-03-10 sch Added USB mass storage support
2005-11-18 nrs Fix Compiler warning
2005-10-21 dlb Support cardreader mode.
2005-09-27 dlb Mount to hidden dir and remount.
2005-09-20 dlb Create
===========================================================================*/
#include "customer.h"
#include "msg.h"
#include "rex.h"
#include "assert.h"
#include "task.h"
#include "string.h"
#include "jzap.h"
#include "fs_err.h"
#include "fs_efs2.h"
#include "fs_public.h"
#include "fs_benchmark.h"
#include "fs_hotplug.h"
#include "fs_hotplug_i.h"
#include "fs_hotplug_usb.h"
#include "fs_hotplug_sd.h"
#include "fs_hotplug_sd_cprm.h"
#include "fs_hotplug_devnull.h"
#include "fs_hotplug_ftl.h"
#include "fs_ext_sfat.h"
#include "fs_ext_hfat.h"
/*
* The remainder of this file is needed only if Hotplug is enabled
*/
#if defined FEATURE_EFS_HOTPLUG || defined FEATURE_EFS_COLDPLUG
/* If no header file defined a FAT_FORMAT for us, we make a failing stub */
#ifndef FS_FAT_FORMAT
# define FS_FAT_FORMAT(hdev) hotplug_fail_stub(hdev)
#endif
#ifdef FEATURE_EFS_HOTPLUG
/* Hotplug has its own task to asynchronously poll devices */
rex_tcb_type fs_hotplug_tcb;
static void fs_hotplug_task (dword arg);
#define FS_HOTPLUG_STACK_SIZE 2048 /* (needs a measured reduction) */
static unsigned char fs_hotplug_stack [FS_HOTPLUG_STACK_SIZE];
/* Timer to trigger periodic poll events */
static rex_timer_type fs_hotplug_poll_timer;
/* The interval time for the periodic hotplug polls */
static rex_timer_cnt_type hotplug_poll_interval;
/* Should hotplug be polling? This is the external polling enable state.
* This allows polling to be started and stopped by external control. */
static volatile int polling_enabled;
#endif /* FEATURE_EFS_HOTPLUG */
/*
* Static prototypes
*/
static int hotplug_force_directory (const char *dirname);
static void hotplug_nodev_mount (struct hotplug_device *hdev);
static int hotplug_umount (struct hotplug_device *hdev);
/* We need a Hotplug lock to make sure the hotplug data structures are
* only accessed by one thread at a time. Any access to the table
* should only take place with the lock held. */
#ifdef FS_STANDALONE
#define HOTPLUG_LOCK_INIT()
#define HOTPLUG_LOCK()
#define HOTPLUG_UNLOCK()
#else
static rex_crit_sect_type hotplug_crit_sect;
#define HOTPLUG_LOCK_INIT() rex_init_crit_sect (&hotplug_crit_sect)
#define HOTPLUG_LOCK() rex_enter_crit_sect (&hotplug_crit_sect)
#define HOTPLUG_UNLOCK() rex_leave_crit_sect (&hotplug_crit_sect)
#endif
/* On-target, the CPRM partition shares a physical device number with
* the user portion of the SD card, and the CPRM calls are distinct.
* Off-target, where we use the same calls for both, we use a
* different devno to tell them apart. */
#ifdef FS_UNIT_TEST
#error code not present
#else
#define CPRM_DEVNO 0
#endif
/*
* This is the list of devices and mountpoints that Hotplug will monitor
*
* Note: the leading slash in the pathname is mandatory.
*/
#define DEFAULT_INITS FALSE, DEV_SKIP, HOTPLUG_NO_INSTANCE, HOTPLUG_NO_HANDLE,\
USBSTATUS_UNCONNECTED, 0, 0
static struct hotplug_device hotplug_device_list[] =
{
#ifdef FS_HOTPLUG_SD
/* This build controls an MMC/SD controller.
* The first slot is identified by driveno "0". */
{ "/mmc1", 0, HOTPLUG_TYPE_MMC, &hotplug_sd_dev, NULL, DEFAULT_INITS },
#endif
#ifdef FS_HOTPLUG_SD_CPRM
/* Protected area of SD card 0, using MKB 0 (See CPRM_DEVNO above) */
{ "/mmc1_p", CPRM_DEVNO, HOTPLUG_TYPE_SD_CPRM, &hotplug_sd_cprm_functions,
NULL, DEFAULT_INITS },
#endif
#ifdef FS_HOTPLUG_FTL
/* This build controls the FTL layer */
{ "/ftl1", 99, HOTPLUG_TYPE_FTL, &hotplug_ftl_dev, NULL, DEFAULT_INITS },
#endif
#ifdef FS_HOTPLUG_USB
/* This build will poll for USB Mass Storage devices (OTG) */
{ "/usb1", 99, HOTPLUG_TYPE_USB_MS, &hotplug_usb_dev, NULL, DEFAULT_INITS },
{ "/usb2", 99, HOTPLUG_TYPE_USB_MS, &hotplug_usb_dev, NULL, DEFAULT_INITS },
{ "/usb3", 99, HOTPLUG_TYPE_USB_MS, &hotplug_usb_dev, NULL, DEFAULT_INITS },
{ "/usb4", 99, HOTPLUG_TYPE_USB_MS, &hotplug_usb_dev, NULL, DEFAULT_INITS },
{ "/usb5", 99, HOTPLUG_TYPE_USB_MS, &hotplug_usb_dev, NULL, DEFAULT_INITS },
{ "/usb6", 99, HOTPLUG_TYPE_USB_MS, &hotplug_usb_dev, NULL, DEFAULT_INITS },
{ "/usb7", 99, HOTPLUG_TYPE_USB_MS, &hotplug_usb_dev, NULL, DEFAULT_INITS },
{ "/usb8", 99, HOTPLUG_TYPE_USB_MS, &hotplug_usb_dev, NULL, DEFAULT_INITS },
#endif
#ifdef FS_HOTPLUG_DEVNULL
{ "/dev.null", 42, HOTPLUG_TYPE_DEVNULL, &hotplug_devnull_dev, NULL,
DEFAULT_INITS },
#endif
};
#define HOTPLUG_TOTAL_DEVICES \
(sizeof(hotplug_device_list)/sizeof(hotplug_device_list[0]))
/* Ensure that a directory of this name exists or is created */
static int
hotplug_force_directory (const char *dirname)
{
/* Kill any regular file that stands in our way. */
(void) efs_unlink (dirname);
/* Try to make the new directory.
* An existing directory of the same name is okay.
* We will just mount over it, hiding the contents. */
if ((efs_mkdir (dirname, 0755) != 0)
&& (efs_errno != EEXIST))
{
/* Failed to make the directory. Admit defeat. */
ZPRINTF ("Cannot make directory %s\n\r", dirname);
return -1;
} else {
return 0; /* Directory good */
}
}
/* To ensure that no process creates files in EFS2 under the hotplug
* mountpoints, we mount each of them to the 'nodev' filesystem until
* a device is available. This should remain the default state until
* something useable is mounted.
*
* This function must succeed, or something is very wrong. */
static void
hotplug_nodev_mount (struct hotplug_device *hdev)
{
if (efs_mount ("", hdev->name, "nodev", 0, NULL) != 0) {
ZPRINTF ("Mount of %s to nodev failed!\n\r", hdev->name);
ERR_FATAL ("Could not prepare hotplug directory %s", hdev->name, 0, 0);
}
}
/*
* Unmount the NODEV fs that was holding this inactive directory
* This is necessary so that we can remount a different filesystem
* there when ready.
*/
static void
hotplug_nodev_umount (struct hotplug_device *hdev)
{
if (efs_umount (hdev->name)) /* Should not fail */
ERR_FATAL ("Failed to unmount NODEV from %s!\n\r", hdev->name,0,0);
}
/* Mount a path using the FAT conventions.
* (Call only while holding the HOTPLUG_LOCK)
*/
int
hotplug_fat_mount (struct hotplug_device *hdev)
{
char drive_letter[3];
ASSERT (hdev->dev_state == DEV_UNMOUNTED);
ZPRINTF ("hotplug_fat_mount(%s)\n\r", hdev->name);
drive_letter[0] = 'a' + hdev->index;
drive_letter[1] = ':';
drive_letter[2] = '\0';
/* Now mount the FAT filesystem there */
if (efs_mount ("0", hdev->name, "extfs", 0, drive_letter) != 0) {
ZPRINTF ("Mount of %s to %s failed!\n\r", hdev->name, drive_letter);
return -1;
}
hdev->dev_state = DEV_MOUNTED;
return 0;
}
/*
* Unmount the hotplug filesystem and leave a NODEV filesystem in its
* place.
*/
static int
hotplug_umount (struct hotplug_device *hdev)
{
int status = 0;
ASSERT (hdev->dev_state == DEV_MOUNTED);
ZPRINTF ("hotplug_umount(%s)\n\r", hdev->name);
/* Unmount the filesystem */
if (efs_umount (hdev->name)) /* Should not fail */
status = -1;
/* Remount it to nodev. If the umount failed above, this might be fatal */
hotplug_nodev_mount (hdev);
hdev->dev_state = DEV_UNMOUNTED; /* Regardless... */
return status;
}
/* Stub function for open & close */
int
hotplug_success_stub (struct hotplug_device *hdev)
{
(void) hdev;
return 0; /* Success, ignore */
}
/* Stub function for unsupported erase */
int
hotplug_no_erase (struct hotplug_device *hdev,
uint32 lba, uint16 n_to_erase)
{
(void) hdev;
(void) lba;
(void) n_to_erase;
return -1; /* Unsupported */
}
/* Stub function for unsupported */
int
hotplug_fail_stub (struct hotplug_device *hdev)
{
(void) hdev;
return -1; /* Unsupported */
}
/* Returns the first device in the hotplug_device_list which has specified
* 'status' set. */
struct hotplug_device *
hotplug_find_dev_by_type (hotplug_dev_type type,
struct hotplug_device *last)
{
unsigned int index;
if (last == NULL)
index = 0;
else
index = last->index + 1;
while (index < HOTPLUG_TOTAL_DEVICES)
{
if (hotplug_device_list[index].device_type == type)
return &hotplug_device_list[index];
index++;
}
return NULL;
}
/* Returns the first device in the hotplug_device_list which has the
* specified path */
struct hotplug_device *
hotplug_find_dev_by_path (const char *path)
{
unsigned int i;
if (!path)
return NULL;
while (path[0] == '/') /* Strip leading slash(es) */
path++;
if (path[0] == '\0') /* Name is required */
return NULL;
for (i = 0; i < HOTPLUG_TOTAL_DEVICES; i++)
{
/* name match? */
if (strcmp ((hotplug_device_list[i].name + 1), path) == 0) {
return &hotplug_device_list[i];
}
}
return NULL;
}
/* This is where we actually check each device for media changes.
This is a private function that should be called from hotplug's task only,
since it can take significant time. */
void
hotplug_poll (void)
{
struct hotplug_device *hdev;
//MSG_MED ("hotplug_poll()",0,0,0);
/* Nobody else can manipulate our table during the whole poll */
HOTPLUG_LOCK();
/* Walk through each device in the hotplug device table... */
hdev = &hotplug_device_list[0];
while (hdev < &hotplug_device_list[HOTPLUG_TOTAL_DEVICES])
{
hotplug_dev_state prior_state = hdev->dev_state;
ZPRINTF ("Polling %s.. { ", hdev->name);
switch (hdev->dev_state)
{
/* Skip any devices we aren't supposed to look at */
case DEV_SKIP:
ZAPN ("SKIP ");
break;
case DEV_FORMATTING:
ZAPN ("FORMATTING ");
break;
/* Unmounted devices may now be available */
case DEV_UNMOUNTED:
if (hdev->dev->is_present (hdev)) {
ZAPN ("Found! ");
/* (Ideally we would prefer that there was NO window between
* unmounting NODEV and mounting the real one, but that
* would require grabbing the FS_GLOBAL_LOCK or somesuch. */
hotplug_nodev_umount (hdev);
if (hdev->dev->mount (hdev) == 0) {
ZAPN ("Mounted! ");
} else {
hotplug_nodev_mount (hdev); /* Put back NODEV */
ZPRINTF ("Unable to mount device: %s ", hdev->name);
}
} else {
ZAPN ("idle ");
}
break;
/* Check on our mounted devices to make sure they're still there */
case DEV_MOUNTED:
{
int present;
present = hdev->dev->is_present (hdev);
if (!present) {
ZAPN ("Removed. ");
if (hotplug_umount (hdev) == 0) {
ZAPN ("Unmounted. ");
} else {
ZPRINTF ("Unable to umount: %s ", hdev->name);
}
} else {
ZAPN ("mounted; still present. ");
}
break;
}
default:
ZAPN ("Invalid device status! ");
}
ZAP ("}");
/* If this device was unchanged, advance to the next device.
* Otherwise, this device will be polled again immediately
* until the state settles */
if (prior_state == hdev->dev_state)
hdev++;
}
HOTPLUG_UNLOCK();
}
/*
* Cause the Hotplug poll timer to expire and trigger an immediate poll.
*/
void
hotplug_force_poll_now (void)
{
/* If COLDPLUG is requested, then no task will poll and the polling
* must be done right now, and in the caller's context. */
#if defined FEATURE_EFS_COLDPLUG || defined FS_UNIT_TEST
hotplug_poll ();
#else
/* Otherwise, pretend the timer just expired. Hotplug Task will put
* the timer back if polling is still enabled */
rex_clr_timer (&fs_hotplug_poll_timer);
(void) rex_set_sigs (&fs_hotplug_tcb, HOTPLUG_POLL_SIG);
#endif
}
void
hotplug_init (void)
{
static int init_complete = 0;
unsigned int i;
#ifndef FS_UNIT_TEST
ASSERT (!init_complete);
#endif
/* Prepare each device in the table for hotplug */
for (i = 0; i < HOTPLUG_TOTAL_DEVICES; i++)
{
struct hotplug_device *hdev;
hdev = &hotplug_device_list[i];
hdev->index = i;
/* Create a directory for each mountpoint and mount it as nodev
* to prevent unintended access */
if (hotplug_force_directory (hdev->name) != 0)
ERR_FATAL ("Could not mkdir hotplug mountpoint #%d", hdev->index, 0, 0);
hotplug_nodev_mount (hdev);
/* Allow the device to do any device-specific reset */
if (hdev->dev->reset (hdev) == 0)
hdev->dev_state = DEV_UNMOUNTED; /* Ready */
else
hdev->dev_state = DEV_SKIP; /* Do not use */
}
#ifdef FEATURE_EFS_HOTPLUG
#ifdef TIMETEST_FS_HOTPLUG_TASK_ID
/* Set the task ID for TIMETEST */
fs_hotplug_tcb.leds = TIMETEST_FS_HOTPLUG_TASK_ID;
#endif
/* Start the hotplug management task. */
rex_def_task_ext (&fs_hotplug_tcb,
fs_hotplug_stack,
FS_HOTPLUG_STACK_SIZE,
FS_HOTPLUG_PRI,
fs_hotplug_task,
0,
"FS Hotplug Task",
FALSE);
#endif /* FEATURE_EFS_HOTPLUG */
init_complete = 1;
#ifdef FEATURE_EFS_COLDPLUG
/* This is the one and only poll we will do automatically for COLDPLUG. */
hotplug_poll();
#endif
}
#ifdef FEATURE_EFS_HOTPLUG /* Hotplug gets a task, Coldplug gets none. */
static void
fs_hotplug_task (dword arg)
{
rex_sigs_type sigs;
int timer_running = 0;
(void) arg; /* unused */
/* Create our timer for the poll cycle */
rex_def_timer (&fs_hotplug_poll_timer, &fs_hotplug_tcb,
HOTPLUG_POLL_SIG);
/* Set our default poll interval and clear the timer */
hotplug_set_polling_interval (FS_HOTPLUG_DEFAULT_POLL_INTERVAL_MS);
/* Register with USB for notifications */
hotplug_usbhost_register();
while (1)
{
/*
* This has to be protected, because we are checking multiple
* variables.
*/
HOTPLUG_LOCK();
if (polling_enabled && !timer_running)
{
rex_set_timer (&fs_hotplug_poll_timer, hotplug_poll_interval);
timer_running = 1;
}
else if (!polling_enabled && timer_running)
{
rex_clr_timer (&fs_hotplug_poll_timer);
timer_running = 0;
}
HOTPLUG_UNLOCK ();
sigs = rex_wait (HOTPLUG_POLL_SIG
| HOTPLUG_USBHOST_OPEN_SIG
| HOTPLUG_USBHOST_CLOSE_SIG);
/* Did we lose a connected device? Handle this FIRST */
if (sigs & HOTPLUG_USBHOST_CLOSE_SIG)
{
(void) rex_clr_sigs (&fs_hotplug_tcb, HOTPLUG_USBHOST_CLOSE_SIG);
hotplug_usbhost_close ();
}
/* Has hotplug_usbhost_callback signalled that a device is ready? */
if (sigs & HOTPLUG_USBHOST_OPEN_SIG)
{
(void) rex_clr_sigs (&fs_hotplug_tcb, HOTPLUG_USBHOST_OPEN_SIG);
hotplug_usbhost_open ();
}
/* Has our timer expired? Then it's time to visit our devices */
if (sigs & HOTPLUG_POLL_SIG)
{
timer_running = 0;
if (polling_enabled)
hotplug_poll ();
}
(void) rex_clr_sigs (&fs_hotplug_tcb, sigs);
}
}
#endif /* FEATURE_EFS_HOTPLUG */
/* Allow an external task to enable/disable hotplug polling and set
* the frequency (in milliseconds). Polling is disabled with a value
* of zero milliseconds.
*
* This also causes an immediate poll and restarts the timer any time
* the interval is changed.
*
* Returns the former polling interval value in milliseconds.
*/
unsigned int
hotplug_set_polling_interval (unsigned int milliseconds)
#ifdef FEATURE_EFS_HOTPLUG
{
unsigned int old_value;
old_value = (unsigned int) hotplug_poll_interval;
/* Do nothing if time isn't actually changed. This ignores
* redundant calls without resetting the timer and polling. */
if (old_value != milliseconds) {
hotplug_poll_interval = (rex_timer_cnt_type) milliseconds;
polling_enabled = (milliseconds != 0) ? 1 : 0;
/* Cause an immediate poll event to restart timer with new value.
* If polling is no longer enabled, then this will terminate the
* current timer. */
hotplug_force_poll_now();
}
return old_value;
}
#else /* function is meaningless on COLDPLUG. Do nothing. */
{
(void) milliseconds;
return 0; /* this is a clue */
}
#endif
/* Request that Hotplug cease mount operations on a device. Will
* forcibly unmount the device and disable polling. The device
* remains useable through direct read/write calls, but Hotplug itself
* will not attempt to (FAT) mount it.
*
* Media that is not locked should never be accessed directly with the
* hotplug_xxx_dev() functions.
*
* Returns 0 on success, or -1 if the media could not be locked.
*/
int
hotplug_lock_dev (struct hotplug_device *hdev)
{
int status = 0;
HOTPLUG_LOCK ();
if (hdev->dev_state == DEV_MOUNTED)
status = hotplug_umount (hdev);
/* Close the device, since someone else intends to open it. */
if (status == 0)
status = hdev->dev->close (hdev);
hdev->dev_state = DEV_SKIP; /* Now avoid this device */
HOTPLUG_UNLOCK ();
return status;
}
/* Called to indicate that the device is again available for hotplug
* (FAT) use. Merely allows the hotplug manager to begin polling and
* mounting found media in this device.
*
* Returns 0 for success, or -1 if the device wasn't
* locked. (harmless)
*/
int
hotplug_unlock_dev (struct hotplug_device *hdev)
{
int status = 0;
HOTPLUG_LOCK ();
if (hdev->dev_state == DEV_SKIP)
hdev->dev_state = DEV_UNMOUNTED; /* It's ours once again */
else
status = -1; /* It wasn't locked? */
HOTPLUG_UNLOCK ();
/* Force a poll immediately, since new media is now available */
hotplug_force_poll_now();
return status;
}
/* Lock all media of a specific type */
static void
hotplug_lock_by_type (hotplug_dev_type type)
{
struct hotplug_device *hdev;
/* Lock ALL the devices of this type */
hdev = hotplug_find_dev_by_type (type, NULL);
while (hdev != NULL) {
hotplug_lock_dev (hdev);
hdev = hotplug_find_dev_by_type (type, hdev);
}
}
/* Unlock all media of a specific type */
static void
hotplug_unlock_by_type (hotplug_dev_type type)
{
struct hotplug_device *hdev;
/* Unlock ALL the devices of this type */
hdev = hotplug_find_dev_by_type (type, NULL);
while (hdev != NULL) {
hotplug_unlock_dev (hdev);
hdev = hotplug_find_dev_by_type (type, hdev);
}
}
/* These are the old functions to lock all of SD/MMC
* DEPRECATED! Do not use in new code. */
void
fs_sfat_lock_card (void)
{
hotplug_lock_by_type (HOTPLUG_TYPE_MMC);
}
/* Unlock all SD/MMC cards (DEPRECATED)*/
void
fs_sfat_unlock_card (void)
{
hotplug_unlock_by_type (HOTPLUG_TYPE_MMC);
}
/* Format by pathname */
int
hotplug_format (const char *path)
{
struct hotplug_device *hdev;
hdev = hotplug_find_dev_by_path (path);
if (hdev) /* Found a name match */
return hotplug_format_dev (hdev);
else
return -1;
}
/* Format device */
int
hotplug_format_dev (struct hotplug_device *hdev)
{
int status = 0;
HOTPLUG_LOCK ();
/* Unmount it, if needed */
if (hdev->dev_state == DEV_MOUNTED) {
if (hotplug_umount (hdev) == 0)
ZPRINTF ("format unmounted the device %s\n\r", hdev->name);
else {
ZPRINTF ("format got bad status from umount: %s\n\r", hdev->name);
status = -1;
}
}
/* Is it in a state that doesn't permit formatting, like SKIP? */
if (hdev->dev_state != DEV_UNMOUNTED) {
ZPRINTF ("Can not format a device in state %d\n\r", hdev->dev_state);
status = -1;
}
/* Make sure the device is present (and open) */
if (! hdev->dev->is_present (hdev)) {
ZPRINTF ("Format requires a device is_present\n\r");
status = -1;
}
if (status == 0) {
/* Move to FORMATTING state so we don't attempt to mount it */
hdev->dev_state = DEV_FORMATTING;
HOTPLUG_UNLOCK (); /* Don't hold lock during format */
/* Prepare the device for format (warn the device layer) */
status = hdev->dev->format_prep (hdev);
/* Now do the filesystem-level format */
if (status == 0)
status = FS_FAT_FORMAT (hdev); /* Must return 0 for success */
HOTPLUG_LOCK (); /* Grab the lock again to change state */
hdev->dev_state = DEV_UNMOUNTED;
}
HOTPLUG_UNLOCK (); /* We're finished */
hotplug_force_poll_now(); /* Might have new media, how exciting! */
return status;
}
/* For a given drive number, return the hotplug entry for that device.
This exploits the assurance that the external drive id is really
the index into the table.
PRIVATE! Do not call this function from new code. The whole
concept of "driveno" or index is now internal and shouldn't be
accessed by outside code. Pathname or type is a preferred way to
locate hotplug devices.
(For SD devices, there is also an internal hardware "driveno" used
by the SD driver, unrelated to this index) */
struct hotplug_device *
hotplug_hdev (int16 index)
{
ASSERT ((index >= 0) && (index < (int)HOTPLUG_TOTAL_DEVICES));
return &hotplug_device_list[index];
}
/*
* Return TRUE if the named path is currently mounted by hotplug.
*
* (Dual-processor specific)
* This executes on the Apps (SD-controlling) processor.
* The modem calls this (via RPC) to find out if the device has been
* mounted on Apps and is ready for remote mounting.
*/
int
hotplug_is_mounted (const char *name)
{
return (hotplug_dev_is_mounted (hotplug_find_dev_by_path (name)));
}
/*
* These are transparent pass-through device access functions to allow
* us to keep 'struct hotplug_device' anonymous.
*/
/* Return TRUE if the device is currently mounted by hotplug. */
int
hotplug_dev_is_mounted (struct hotplug_device *hdev)
{
#if 0
ZPRINTF ("hotplug_dev_is_mounted(%s) %s\n\r", hdev->name,
(hdev && (hdev->dev_state == DEV_MOUNTED)) ? "YES" : "no ");
#endif
if (hdev && (hdev->dev_state == DEV_MOUNTED))
return 1;
else
return 0;
}
/* Return TRUE if media is believed to be present */
int
hotplug_dev_is_present (struct hotplug_device *hdev)
{
return hdev->dev->is_present (hdev);
}
int
hotplug_dev_open (struct hotplug_device *hdev)
{
return hdev->dev->open (hdev);
}
int
hotplug_dev_close (struct hotplug_device *hdev)
{
return hdev->dev->close (hdev);
}
int
hotplug_dev_read (struct hotplug_device *hdev,
uint32 lba,
unsigned char *buf,
uint16 n_to_read)
{
fs_counter.hotplug_read_sector_counter += n_to_read;
return hdev->dev->read (hdev, lba, buf, n_to_read);
}
int
hotplug_dev_write (struct hotplug_device *hdev,
uint32 lba,
unsigned char *buf,
uint16 n_to_write)
{
fs_counter.hotplug_write_sector_counter += n_to_write;
return hdev->dev->write (hdev, lba, buf, n_to_write);
}
/*
This device write is called when the write is specifically know to
be 'file' or payload data, rather than to directories or other file
system metadata.
In the case of CPRM, we need to be able to specify a special mode
for user data so that it is written using the correct MKB. The MKB
is different for metadata, which should use the standard write call.
For all non-CPRM devices, this write call performs identically to
the standard write call.
*/
int
hotplug_dev_write_udata(struct hotplug_device *hdev,
uint32 lba,
unsigned char *buf,
uint16 n_to_write)
{
fs_counter.hotplug_write_sector_counter += n_to_write;
return hdev->dev->user_write (hdev, lba, buf, n_to_write);
}
int
hotplug_dev_erase (struct hotplug_device *hdev,
uint32 lba,
uint16 n_to_erase)
{
return hdev->dev->erase (hdev, lba, n_to_erase);
}
int
hotplug_dev_get_size (struct hotplug_device *hdev,
uint32 *blocks,
uint16 *bytes_per_block)
{
return hdev->dev->get_size (hdev, blocks, bytes_per_block);
}
#else /* ! (defined FEATURE_EFS_HOTPLUG || defined FEATURE_EFS_COLDPLUG) */
extern int __dont_complain_about_empty_file;
#endif