summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/dahdi/voicebus/vpmoct.c269
-rw-r--r--drivers/dahdi/voicebus/vpmoct.h8
-rw-r--r--drivers/dahdi/wctdm24xxp/base.c112
-rw-r--r--drivers/dahdi/wctdm24xxp/wctdm24xxp.h8
-rw-r--r--drivers/dahdi/wctdm24xxp/xhfc.c10
-rw-r--r--drivers/dahdi/wcte12xp/base.c177
-rw-r--r--drivers/dahdi/wcte12xp/wcte12xp.h2
7 files changed, 401 insertions, 185 deletions
diff --git a/drivers/dahdi/voicebus/vpmoct.c b/drivers/dahdi/voicebus/vpmoct.c
index 26db816..0a31c97 100644
--- a/drivers/dahdi/voicebus/vpmoct.c
+++ b/drivers/dahdi/voicebus/vpmoct.c
@@ -23,6 +23,7 @@
*/
#include <linux/jiffies.h>
+#include <linux/delay.h>
#include <linux/sched.h>
#include <linux/crc32.h>
@@ -291,9 +292,36 @@ error:
return -1;
}
+/**
+ * vpmoct_get_mode - Return the current operating mode of the VPMOCT032.
+ * @vpm: The vpm to query.
+ *
+ * Will be either BOOTLOADER, APPLICATION, or UNKNOWN.
+ *
+ */
+static enum vpmoct_mode vpmoct_get_mode(struct vpmoct *vpm)
+{
+ int i;
+ enum vpmoct_mode ret = UNKNOWN;
+ char identifier[11] = {0};
+
+ for (i = 0; i < ARRAY_SIZE(identifier) - 1; i++)
+ identifier[i] = vpmoct_read_byte(vpm, VPMOCT_IDENT+i);
+
+ if (!memcmp(identifier, "bootloader", sizeof(identifier) - 1))
+ ret = BOOTLOADER;
+ else if (!memcmp(identifier, "VPMOCT032\0", sizeof(identifier) - 1))
+ ret = APPLICATION;
+
+ dev_dbg(vpm->dev, "vpmoct identifier: %s\n", identifier);
+ return ret;
+}
+
+
static inline short
vpmoct_check_firmware_crc(struct vpmoct *vpm, size_t size, u8 major, u8 minor)
{
+ short ret = 0;
u8 status;
/* Load firmware size */
@@ -311,15 +339,29 @@ vpmoct_check_firmware_crc(struct vpmoct *vpm, size_t size, u8 major, u8 minor)
dev_info(vpm->dev,
"vpmoct firmware CRC check failed: %x\n", status);
/* TODO: Try the load again */
- return -1;
+ ret = -1;
} else {
- dev_info(vpm->dev, "vpmoct firmware uploaded successfully\n");
+
/* Switch to application code */
vpmoct_write_dword(vpm, VPMOCT_BOOT_ADDRESS2, 0xDEADBEEF);
- /* Soft reset the processor */
vpmoct_write_byte(vpm, VPMOCT_BOOT_CMD, VPMOCT_BOOT_REBOOT);
- return 0;
+
+ msleep(250);
+ status = vpmoct_resync(vpm);
+
+ if (APPLICATION != vpmoct_get_mode(vpm)) {
+ dev_info(vpm->dev,
+ "vpmoct firmware failed to switch to "
+ "application. (%x)\n", status);
+ ret = -1;
+ } else {
+ vpm->mode = APPLICATION;
+ dev_info(vpm->dev,
+ "vpmoct firmware uploaded successfully\n");
+ }
}
+
+ return ret;
}
static inline short vpmoct_switch_to_boot(struct vpmoct *vpm)
@@ -330,10 +372,62 @@ static inline short vpmoct_switch_to_boot(struct vpmoct *vpm)
dev_info(vpm->dev, "Failed to switch to bootloader\n");
return -1;
}
- vpm->mode = VPMOCT_MODE_BOOTLOADER;
+ vpm->mode = BOOTLOADER;
return 0;
}
+struct vpmoct_load_work {
+ struct vpmoct *vpm;
+ struct work_struct work;
+ struct workqueue_struct *wq;
+ load_complete_func_t load_complete;
+ bool operational;
+};
+
+/**
+ * vpmoct_load_complete_fn -
+ *
+ * This function should run in the context of one of the system workqueues so
+ * that it can destroy any workqueues that may have been created to setup a
+ * long running firmware load.
+ *
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+static void vpmoct_load_complete_fn(void *data)
+{
+ struct vpmoct_load_work *work = data;
+#else
+static void vpmoct_load_complete_fn(struct work_struct *data)
+{
+ struct vpmoct_load_work *work =
+ container_of(data, struct vpmoct_load_work, work);
+#endif
+ /* Do not touch work->vpm after calling load complete. It may have
+ * been freed in the function by the board driver. */
+ work->load_complete(work->vpm->dev, work->operational);
+ destroy_workqueue(work->wq);
+ kfree(work);
+}
+
+/**
+ * vpmoct_load_complete - Call the load_complete function in a system workqueue.
+ * @work:
+ * @operational: Whether the VPM is functioning or not.
+ *
+ */
+static void
+vpmoct_load_complete(struct vpmoct_load_work *work, bool operational)
+{
+ work->operational = operational;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+ INIT_WORK(&work->work, vpmoct_load_complete_fn, work);
+#else
+ INIT_WORK(&work->work, vpmoct_load_complete_fn);
+#endif
+ schedule_work(&work->work);
+}
+
static bool is_valid_vpmoct_firmware(const struct firmware *fw)
{
const struct vpmoct_header *header =
@@ -353,38 +447,38 @@ static void vpmoct_set_defaults(struct vpmoct *vpm)
* vpmoct_load_flash - Check the current flash version and possibly load.
* @vpm: The VPMOCT032 module to check / load.
*
- * Returns 0 on success, otherwise an error message.
- *
- * Must be called in process context.
- *
*/
-static int vpmoct_load_flash(struct vpmoct *vpm)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+static void vpmoct_load_flash(void *data)
+{
+ struct vpmoct_load_work *work = data;
+#else
+static void vpmoct_load_flash(struct work_struct *data)
{
- int firm;
+ struct vpmoct_load_work *work =
+ container_of(data, struct vpmoct_load_work, work);
+#endif
+ int res;
+ struct vpmoct *const vpm = work->vpm;
const struct firmware *fw;
const struct vpmoct_header *header;
char serial[VPMOCT_SERIAL_SIZE+1];
const char *const FIRMWARE_NAME = "dahdi-fw-vpmoct032.bin";
int i;
- /* Load the firmware */
- firm = request_firmware(&fw, FIRMWARE_NAME, vpm->dev);
- if (firm) {
- dev_info(vpm->dev, "vpmoct: Failed to load firmware from"\
- " userspace!, %d\n", firm);
- return -ENOMEM;
- }
-
- if (!is_valid_vpmoct_firmware(fw)) {
+ res = request_firmware(&fw, FIRMWARE_NAME, vpm->dev);
+ if (res) {
dev_warn(vpm->dev,
- "%s is invalid. Please reinstall.\n", FIRMWARE_NAME);
- release_firmware(fw);
- return -EINVAL;
+ "vpmoct: Failed to load firmware from userspace! %d\n",
+ res);
+ header = NULL;
+ fw = NULL;
+ } else {
+ header = (const struct vpmoct_header *)fw->data;
}
- header = (const struct vpmoct_header *)fw->data;
+ if (vpm->mode == APPLICATION) {
- if (vpm->mode == VPMOCT_MODE_APPLICATION) {
/* Check the running application firmware
* for the proper version */
vpm->major = vpmoct_read_byte(vpm, VPMOCT_MAJOR);
@@ -393,16 +487,37 @@ static int vpmoct_load_flash(struct vpmoct *vpm)
serial[i] = vpmoct_read_byte(vpm, VPMOCT_SERIAL+i);
serial[VPMOCT_SERIAL_SIZE] = '\0';
- dev_info(vpm->dev, "vpmoct: Detected firmware v%d.%d\n",
- vpm->major, vpm->minor);
- dev_info(vpm->dev, "vpmoct: Serial %s\n", serial);
+ dev_info(vpm->dev,
+ "vpmoct: Detected firmware v%d.%d Serial: %s\n",
+ vpm->major, vpm->minor,
+ (serial[0] != -1) ? serial : "(None)");
+
+ if (!fw) {
+ /* Again, we'll use the existing loaded firmware. */
+ vpmoct_set_defaults(vpm);
+ vpmoct_load_complete(work, true);
+ return;
+ }
+
+ if (!is_valid_vpmoct_firmware(fw)) {
+ dev_warn(vpm->dev,
+ "%s is invalid. Please reinstall.\n",
+ FIRMWARE_NAME);
+
+ /* Just use the old version of the fimware. */
+ release_firmware(fw);
+ vpmoct_set_defaults(vpm);
+ vpmoct_load_complete(work, true);
+ return;
+ }
if (vpm->minor == header->minor &&
vpm->major == header->major) {
/* Proper version is running */
release_firmware(fw);
vpmoct_set_defaults(vpm);
- return 0;
+ vpmoct_load_complete(work, true);
+ return;
} else {
/* Incorrect version of application code is
@@ -412,6 +527,15 @@ static int vpmoct_load_flash(struct vpmoct *vpm)
}
}
+ if (!fw) {
+ vpmoct_load_complete(work, false);
+ return;
+ } else if (!is_valid_vpmoct_firmware(fw)) {
+ dev_warn(vpm->dev,
+ "%s is invalid. Please reinstall.\n", FIRMWARE_NAME);
+ goto error;
+ }
+
dev_info(vpm->dev, "vpmoct: Uploading firmware, v%d.%d. This can "\
"take up to 1 minute\n",
header->major, header->minor);
@@ -426,12 +550,15 @@ static int vpmoct_load_flash(struct vpmoct *vpm)
goto error;
release_firmware(fw);
vpmoct_set_defaults(vpm);
- return 0;
+ vpmoct_load_complete(work, true);
+ return;
error:
dev_info(vpm->dev, "Unable to load firmware\n");
release_firmware(fw);
- return -1;
+ /* TODO: Should we disable module if the firmware doesn't load? */
+ vpmoct_load_complete(work, false);
+ return;
}
struct vpmoct *vpmoct_alloc(void)
@@ -452,44 +579,82 @@ EXPORT_SYMBOL(vpmoct_alloc);
void vpmoct_free(struct vpmoct *vpm)
{
+ unsigned long flags;
+ struct vpmoct_cmd *cmd;
+ LIST_HEAD(list);
+
+ if (!vpm)
+ return;
+
+ spin_lock_irqsave(&vpm->list_lock, flags);
+ list_splice(&vpm->active_list, &list);
+ list_splice(&vpm->pending_list, &list);
+ spin_unlock_irqrestore(&vpm->list_lock, flags);
+
+ while (!list_empty(&list)) {
+ cmd = list_entry(list.next, struct vpmoct_cmd, node);
+ list_del(&cmd->node);
+ kfree(cmd);
+ }
+
kfree(vpm);
}
EXPORT_SYMBOL(vpmoct_free);
/**
* vpmoct_init - Check for / initialize VPMOCT032 module.
- * @vpm: struct vpmoct allocated with vpmoct_alloc
+ * @vpm: struct vpmoct allocated with vpmoct_alloc
+ * @load_complete_fn: Function to call when the load is complete.
*
- * Returns 0 on success or an error code.
+ * Check to see if there is a VPMOCT module installed. If there appears to be
+ * one return 0 and perform any necessary setup in the background. The
+ * load_complete function will be called in a system global workqueue when the
+ * initialization is complete.
*
* Must be called in process context.
*/
-int vpmoct_init(struct vpmoct *vpm)
+int vpmoct_init(struct vpmoct *vpm, load_complete_func_t load_complete)
{
- unsigned int i;
- char identifier[10];
+ struct vpmoct_load_work *work;
- if (vpmoct_resync(vpm))
+ if (!vpm || !vpm->dev || !load_complete)
+ return -EINVAL;
+
+ if (vpmoct_resync(vpm)) {
+ load_complete(vpm->dev, false);
return -ENODEV;
+ }
- /* Probe for vpmoct ident string */
- for (i = 0; i < ARRAY_SIZE(identifier); i++)
- identifier[i] = vpmoct_read_byte(vpm, VPMOCT_IDENT+i);
+ vpm->mode = vpmoct_get_mode(vpm);
- if (!memcmp(identifier, "bootloader", sizeof(identifier))) {
- /* vpmoct is in bootloader mode */
- dev_info(vpm->dev, "Detected vpmoct bootloader, attempting "\
- "to load firmware\n");
- vpm->mode = VPMOCT_MODE_BOOTLOADER;
- return vpmoct_load_flash(vpm);
- } else if (!memcmp(identifier, "VPMOCT032\0", sizeof(identifier))) {
- /* vpmoct is in application mode */
- vpm->mode = VPMOCT_MODE_APPLICATION;
- return vpmoct_load_flash(vpm);
- } else {
- /* No vpmoct is installed */
+ if (UNKNOWN == vpm->mode) {
+ load_complete(vpm->dev, false);
return -ENODEV;
}
+
+ work = kzalloc(sizeof(*work), GFP_KERNEL);
+ if (!work) {
+ load_complete(vpm->dev, false);
+ return -ENOMEM;
+ }
+
+ work->wq = create_singlethread_workqueue("vpmoct");
+ if (!work->wq) {
+ kfree(work);
+ load_complete(vpm->dev, false);
+ return -ENOMEM;
+ }
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+ INIT_WORK(&work->work, vpmoct_load_flash, work);
+#else
+ INIT_WORK(&work->work, vpmoct_load_flash);
+#endif
+
+ work->vpm = vpm;
+ work->load_complete = load_complete;
+ queue_work(work->wq, &work->work);
+ return 0;
}
EXPORT_SYMBOL(vpmoct_init);
diff --git a/drivers/dahdi/voicebus/vpmoct.h b/drivers/dahdi/voicebus/vpmoct.h
index 486a80d..cb55826 100644
--- a/drivers/dahdi/voicebus/vpmoct.h
+++ b/drivers/dahdi/voicebus/vpmoct.h
@@ -61,15 +61,14 @@
#define VPMOCT_BOOT_ADDRESS2 0x1c
#define VPMOCT_BOOT_RAM 0x20
-#define VPMOCT_MODE_BOOTLOADER 0
-#define VPMOCT_MODE_APPLICATION 1
+enum vpmoct_mode { UNKNOWN = 0, APPLICATION, BOOTLOADER };
struct vpmoct {
struct list_head pending_list;
struct list_head active_list;
spinlock_t list_lock;
struct mutex mutex;
- unsigned short int mode;
+ enum vpmoct_mode mode;
struct device *dev;
u32 companding;
u32 echo;
@@ -99,7 +98,8 @@ static inline bool is_vpmoct_cmd_read(const struct vpmoct_cmd *cmd)
struct vpmoct *vpmoct_alloc(void);
void vpmoct_free(struct vpmoct *vpm);
-int vpmoct_init(struct vpmoct *vpm);
+typedef void (*load_complete_func_t)(struct device *dev, bool operational);
+int vpmoct_init(struct vpmoct *vpm, load_complete_func_t load_complete);
int vpmoct_echocan_create(struct vpmoct *vpm,
int channo,
int companding);
diff --git a/drivers/dahdi/wctdm24xxp/base.c b/drivers/dahdi/wctdm24xxp/base.c
index 73bcae6..98c0f0e 100644
--- a/drivers/dahdi/wctdm24xxp/base.c
+++ b/drivers/dahdi/wctdm24xxp/base.c
@@ -309,12 +309,6 @@ static inline __attribute_const__ int VPM_CMD_BYTE(int timeslot, int bit)
return ((((timeslot) & 0x3) * 3 + (bit)) * 7) + ((timeslot) >> 2);
}
-static inline bool is_initialized(struct wctdm *wc)
-{
- WARN_ON(wc->initialized < 0);
- return (wc->initialized == 0);
-}
-
static void
setchanconfig_from_state(struct vpmadt032 *vpm, int channel,
GpakChannelConfig_t *chanconfig)
@@ -2131,6 +2125,7 @@ static const char *wctdm_echocan_name(const struct dahdi_chan *chan)
return vpmadt032_name;
else if (wc->vpmoct)
return vpmoct_name;
+
return NULL;
}
@@ -4374,12 +4369,37 @@ static int wctdm_initialize_vpmadt032(struct wctdm *wc)
return 0;
}
+static void wctdm_vpm_load_complete(struct device *dev, bool operational)
+{
+ unsigned long flags;
+ struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
+ struct wctdm *wc = pci_get_drvdata(pdev);
+ struct vpmoct *vpm = NULL;
+
+ WARN_ON(!wc || !wc->not_ready);
+ if (!wc || !wc->not_ready)
+ return;
+
+ spin_lock_irqsave(&wc->reglock, flags);
+ wc->not_ready--;
+ if (operational) {
+ wc->ctlreg |= 0x10;
+ } else {
+ vpm = wc->vpmoct;
+ wc->vpmoct = NULL;
+ }
+ spin_unlock_irqrestore(&wc->reglock, flags);
+
+ if (vpm)
+ vpmoct_free(vpm);
+}
+
static void wctdm_initialize_vpm(struct wctdm *wc)
{
int res = 0;
if (!vpmsupport)
- goto cleanup;
+ return;
res = wctdm_initialize_vpmadt032(wc);
if (!res) {
@@ -4393,29 +4413,26 @@ static void wctdm_initialize_vpm(struct wctdm *wc)
if (!vpm) {
dev_info(&wc->vb.pdev->dev,
"Unable to allocate memory for struct vpmoct\n");
- goto cleanup;
+ return;
}
vpm->dev = &wc->vb.pdev->dev;
spin_lock_irqsave(&wc->reglock, flags);
wc->vpmoct = vpm;
+ wc->not_ready++;
spin_unlock_irqrestore(&wc->reglock, flags);
- if (!vpmoct_init(vpm)) {
- wc->ctlreg |= 0x10;
- return;
- } else {
+ res = vpmoct_init(vpm, wctdm_vpm_load_complete);
+ if (-EINVAL == res) {
spin_lock_irqsave(&wc->reglock, flags);
wc->vpmoct = NULL;
+ wc->not_ready--;
spin_unlock_irqrestore(&wc->reglock, flags);
vpmoct_free(vpm);
- goto cleanup;
}
}
-
-cleanup:
- dev_info(&wc->vb.pdev->dev, "VPM: Support Disabled\n");
+ return;
}
static void wctdm_identify_modules(struct wctdm *wc)
@@ -5214,7 +5231,7 @@ __wctdm_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (!wc)
return -ENOMEM;
- wc->initialized = 1;
+ wc->not_ready = 1;
down(&ifacelock);
/* \todo this is a candidate for removal... */
@@ -5460,7 +5477,7 @@ __wctdm_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
}
}
- wc->initialized--;
+ wc->not_ready--;
dev_info(&wc->vb.pdev->dev,
"Found a %s: %s (%d BRI spans, %d analog %s)\n",
@@ -5531,38 +5548,51 @@ static void wctdm_release(struct wctdm *wc)
static void __devexit wctdm_remove_one(struct pci_dev *pdev)
{
- struct wctdm *wc = pci_get_drvdata(pdev);
- struct vpmadt032 *vpm = wc->vpmadt032;
int i;
+ unsigned long flags;
+ struct wctdm *wc = pci_get_drvdata(pdev);
+ struct vpmadt032 *vpmadt032;
+ struct vpmoct *vpmoct;
+ if (!wc)
+ return;
- if (wc) {
-
- remove_sysfs_files(wc);
+ vpmadt032 = wc->vpmadt032;
+ vpmoct = wc->vpmoct;
- if (vpm) {
- clear_bit(VPM150M_ACTIVE, &vpm->control);
- flush_scheduled_work();
- }
+ remove_sysfs_files(wc);
- /* shut down any BRI modules */
- for (i = 0; i < wc->mods_per_board; i += 4) {
- if (wc->mods[i].type == BRI)
- wctdm_unload_b400m(wc, i);
- }
+ if (vpmadt032) {
+ clear_bit(VPM150M_ACTIVE, &vpmadt032->control);
+ flush_scheduled_work();
+ } else if (vpmoct) {
+ while (wctdm_wait_for_ready(wc))
+ schedule();
+ }
- voicebus_stop(&wc->vb);
+ /* shut down any BRI modules */
+ for (i = 0; i < wc->mods_per_board; i += 4) {
+ if (wc->mods[i].type == BRI)
+ wctdm_unload_b400m(wc, i);
+ }
- if (vpm) {
- vpmadt032_free(wc->vpmadt032);
- wc->vpmadt032 = NULL;
- }
+ voicebus_stop(&wc->vb);
- dev_info(&wc->vb.pdev->dev, "Freed a %s\n",
- (is_hx8(wc)) ? "Hybrid card" : "Wildcard");
- /* Release span */
- wctdm_release(wc);
+ if (vpmadt032) {
+ vpmadt032_free(vpmadt032);
+ wc->vpmadt032 = NULL;
+ } else if (vpmoct) {
+ spin_lock_irqsave(&wc->reglock, flags);
+ wc->vpmoct = NULL;
+ spin_unlock_irqrestore(&wc->reglock, flags);
+ vpmoct_free(vpmoct);
}
+
+ dev_info(&wc->vb.pdev->dev, "Freed a %s\n",
+ (is_hx8(wc)) ? "Hybrid card" : "Wildcard");
+
+ /* Release span */
+ wctdm_release(wc);
}
static DEFINE_PCI_DEVICE_TABLE(wctdm_pci_tbl) = {
diff --git a/drivers/dahdi/wctdm24xxp/wctdm24xxp.h b/drivers/dahdi/wctdm24xxp/wctdm24xxp.h
index 0f497aa..4ab313d 100644
--- a/drivers/dahdi/wctdm24xxp/wctdm24xxp.h
+++ b/drivers/dahdi/wctdm24xxp/wctdm24xxp.h
@@ -273,11 +273,17 @@ struct wctdm {
struct semaphore syncsem;
int oldsync;
- int initialized; /* 0 when the entire card is ready to go */
+ int not_ready; /* 0 when the entire card is ready to go */
unsigned long checkflag; /* Internal state flags and task bits */
int companding;
};
+static inline bool is_initialized(struct wctdm *wc)
+{
+ WARN_ON(wc->not_ready < 0);
+ return (wc->not_ready == 0);
+}
+
/* Atomic flag bits for checkflag field */
#define WCTDM_CHECK_TIMING 0
diff --git a/drivers/dahdi/wctdm24xxp/xhfc.c b/drivers/dahdi/wctdm24xxp/xhfc.c
index de6ad89..c5eb5a6 100644
--- a/drivers/dahdi/wctdm24xxp/xhfc.c
+++ b/drivers/dahdi/wctdm24xxp/xhfc.c
@@ -1160,7 +1160,7 @@ static int xhfc_find_sync_with_timingcable(struct b400m *b4)
}
for (j = 0; j < WC_MAX_IFACES && ifaces[j]; j++) {
- if (!ifaces[j]->initialized) {
+ if (is_initialized(ifaces[j])) {
set_bit(WCTDM_CHECK_TIMING, &wc->checkflag);
osrc = -2;
goto out;
@@ -2194,7 +2194,7 @@ int b400m_spanconfig(struct file *file, struct dahdi_span *span,
b4 = bspan->parent;
wc = b4->wc;
- if ((file->f_flags & O_NONBLOCK) && !wc->initialized)
+ if ((file->f_flags & O_NONBLOCK) && !is_initialized(wc))
return -EAGAIN;
res = wctdm_wait_for_ready(wc);
@@ -2271,7 +2271,7 @@ int b400m_chanconfig(struct file *file, struct dahdi_chan *chan, int sigtype)
struct b400m *b4 = bspan->parent;
int res;
- if ((file->f_flags & O_NONBLOCK) && !b4->wc->initialized)
+ if ((file->f_flags & O_NONBLOCK) && !is_initialized(b4->wc))
return -EAGAIN;
res = wctdm_wait_for_ready(b4->wc);
@@ -2395,7 +2395,7 @@ static void xhfc_work(struct work_struct *work)
int i, j, k, fifo;
unsigned char b, b2;
- if (b4->shutdown || !b4->wc->initialized)
+ if (b4->shutdown || !is_initialized(b4->wc))
return;
b4->irq_oview = b400m_getreg(b4, R_IRQ_OVIEW);
@@ -2518,7 +2518,7 @@ void wctdm_bri_checkisr(struct wctdm *wc, struct wctdm_module *const mod,
return;
/* DEFINITELY don't do anything if our structures aren't ready! */
- if (!wc->initialized || !b4 || !b4->inited)
+ if (!is_initialized(wc) || !b4 || !b4->inited)
return;
if (offset == 0) {
diff --git a/drivers/dahdi/wcte12xp/base.c b/drivers/dahdi/wcte12xp/base.c
index 28afdf6..68fcd96 100644
--- a/drivers/dahdi/wcte12xp/base.c
+++ b/drivers/dahdi/wcte12xp/base.c
@@ -1054,8 +1054,24 @@ static int t1xxp_startup(struct file *file, struct dahdi_span *span)
static inline bool is_initialized(struct t1 *wc)
{
- WARN_ON(wc->initialized < 0);
- return (wc->initialized == 0);
+ WARN_ON(wc->not_ready < 0);
+ return (wc->not_ready == 0);
+}
+
+/**
+ * t1_wait_for_ready
+ *
+ * Check if the board has finished any setup and is ready to start processing
+ * calls.
+ */
+static int t1_wait_for_ready(struct t1 *wc)
+{
+ while (!is_initialized(wc)) {
+ if (fatal_signal_pending(current))
+ return -EIO;
+ msleep_interruptible(250);
+ }
+ return 0;
}
static int t1xxp_chanconfig(struct file *file,
@@ -1066,11 +1082,7 @@ static int t1xxp_chanconfig(struct file *file,
if (file->f_flags & O_NONBLOCK && !is_initialized(wc)) {
return -EAGAIN;
} else {
- while (!is_initialized(wc)) {
- if (fatal_signal_pending(current))
- return -EIO;
- msleep_interruptible(250);
- }
+ t1_wait_for_ready(wc);
}
if (test_bit(DAHDI_FLAGBIT_RUNNING, &chan->span->flags) &&
@@ -1539,7 +1551,7 @@ static void vpm_load_func(struct work_struct *work)
set_bit(0, &wc->ctlreg);
}
- wc->initialized--;
+ wc->not_ready--;
kfree(w);
}
@@ -1561,26 +1573,42 @@ static int vpm_start_load(struct t1 *wc)
return 0;
}
-static int check_and_load_vpm(struct t1 *wc)
+static void t1_vpm_load_complete(struct device *dev, bool operational)
{
- int res;
unsigned long flags;
- struct vpmadt032_options options;
- struct vpmadt032 *vpm = NULL;
+ struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
+ struct t1 *wc = pci_get_drvdata(pdev);
+ struct vpmoct *vpm = NULL;
- if (!vpmsupport) {
- t1_info(wc, "VPM Support Disabled\n");
- vpmadt032_free(wc->vpmadt032);
- wc->vpmadt032 = NULL;
- return 0;
+ if (!wc || is_initialized(wc)) {
+ WARN_ON(!wc);
+ return;
}
- /* The firmware may already be loaded. */
- if (wc->vpmadt032) {
- u16 version;
- res = gpakPingDsp(wc->vpmadt032->dspid, &version);
- if (!res)
- return 0;
+ spin_lock_irqsave(&wc->reglock, flags);
+ wc->not_ready--;
+ if (operational) {
+ set_bit(VPM150M_ACTIVE, &wc->ctlreg);
+ } else {
+ clear_bit(VPM150M_ACTIVE, &wc->ctlreg);
+ vpm = wc->vpmoct;
+ wc->vpmoct = NULL;
+ }
+ spin_unlock_irqrestore(&wc->reglock, flags);
+
+ if (vpm)
+ vpmoct_free(vpm);
+}
+
+static void check_and_load_vpm(struct t1 *wc)
+{
+ unsigned long flags;
+ struct vpmadt032_options options;
+ struct vpmadt032 *vpmadt = NULL;
+
+ if (!vpmsupport) {
+ t1_info(wc, "VPM Support Disabled via module parameter\n");
+ return;
}
memset(&options, 0, sizeof(options));
@@ -1594,69 +1622,49 @@ static int check_and_load_vpm(struct t1 *wc)
* done setting it up here, an hour should cover it... */
wc->vpm_check = jiffies + HZ*3600;
- vpm = vpmadt032_alloc(&options);
- if (!vpm)
- return -ENOMEM;
+ vpmadt = vpmadt032_alloc(&options);
+ if (!vpmadt)
+ return;
- vpm->setchanconfig_from_state = setchanconfig_from_state;
+ vpmadt->setchanconfig_from_state = setchanconfig_from_state;
spin_lock_irqsave(&wc->reglock, flags);
- wc->vpmadt032 = vpm;
+ wc->vpmadt032 = vpmadt;
spin_unlock_irqrestore(&wc->reglock, flags);
- res = vpmadt032_test(vpm, &wc->vb);
- if (-ENODEV == res) {
- struct vpmoct *vpmoct;
-
+ /* Probe for and attempt to load a vpmadt032 module */
+ if (vpmadt032_test(vpmadt, &wc->vb) || vpm_start_load(wc)) {
/* There does not appear to be a VPMADT032 installed. */
clear_bit(VPM150M_ACTIVE, &wc->ctlreg);
spin_lock_irqsave(&wc->reglock, flags);
wc->vpmadt032 = NULL;
spin_unlock_irqrestore(&wc->reglock, flags);
- vpmadt032_free(vpm);
+ vpmadt032_free(vpmadt);
+ }
+
+ /* Probe for and attempt to load a vpmoct032 module */
+ if (NULL == wc->vpmadt032) {
+ struct vpmoct *vpmoct;
/* Check for vpmoct */
vpmoct = vpmoct_alloc();
if (!vpmoct)
- return -ENOMEM;
+ return;
vpmoct->dev = &wc->vb.pdev->dev;
spin_lock_irqsave(&wc->reglock, flags);
wc->vpmoct = vpmoct;
+ wc->not_ready++;
spin_unlock_irqrestore(&wc->reglock, flags);
- res = vpmoct_init(wc->vpmoct);
- if (res) {
- dev_info(&wc->vb.pdev->dev,
- "Unable to initialize vpmoct module\n");
- spin_lock_irqsave(&wc->reglock, flags);
- wc->vpmoct = NULL;
- spin_unlock_irqrestore(&wc->reglock, flags);
- vpmoct_free(vpmoct);
- } else {
- set_bit(VPM150M_ACTIVE, &wc->ctlreg);
- }
-
- return res;
- }
-
- res = vpm_start_load(wc);
- if (res) {
- /* There does not appear to be a VPMADT032 installed. */
- clear_bit(VPM150M_ACTIVE, &wc->ctlreg);
- spin_lock_irqsave(&wc->reglock, flags);
- wc->vpmadt032 = NULL;
- spin_unlock_irqrestore(&wc->reglock, flags);
- vpmadt032_free(vpm);
- return res;
+ vpmoct_init(vpmoct, t1_vpm_load_complete);
}
- return res;
}
#else
-static inline int check_and_load_vpm(const struct t1 *wc)
+static inline void check_and_load_vpm(const struct t1 *wc)
{
- return 0;
+ return;
}
#endif
@@ -1706,11 +1714,7 @@ t1xxp_spanconfig(struct file *file, struct dahdi_span *span,
if (!is_initialized(wc))
return -EAGAIN;
} else {
- while (!is_initialized(wc)) {
- if (fatal_signal_pending(current))
- return -EIO;
- msleep_interruptible(250);
- }
+ t1_wait_for_ready(wc);
}
/* Do we want to SYNC on receive or not */
@@ -2340,7 +2344,7 @@ static void vpm_check_func(struct work_struct *work)
/* If there is a failed VPM module, do not block dahdi_cfg
* indefinitely. */
if (++wc->vpm_check_count > MAX_CHECKS) {
- wc->initialized--;
+ wc->not_ready--;
wc->vpm_check = MAX_JIFFY_OFFSET;
t1_info(wc, "Disabling VPMADT032 Checking.\n");
return;
@@ -2395,7 +2399,7 @@ static void vpm_check_func(struct work_struct *work)
set_bit(VPM150M_ACTIVE, &wc->ctlreg);
t1_info(wc, "VPMADT032 is reenabled.\n");
wc->vpm_check = jiffies + HZ*5;
- wc->initialized--;
+ wc->not_ready--;
return;
}
@@ -2544,7 +2548,7 @@ static int __devinit te12xp_init_one(struct pci_dev *pdev, const struct pci_devi
if (!wc)
return -ENOMEM;
- wc->initialized = 1;
+ wc->not_ready = 1;
ifaces[index] = wc;
@@ -2659,11 +2663,10 @@ static int __devinit te12xp_init_one(struct pci_dev *pdev, const struct pci_devi
t1_info(wc, "Found a %s\n", wc->variety);
voicebus_unlock_latency(&wc->vb);
- /* If there is VPMADT032 or VPMOCT032 module attached to this device,
- * it will signal ready after the channels are configured and ready
- * for use. */
- if (!wc->vpmadt032 && !wc->vpmoct)
- wc->initialized--;
+ /* If there is VPMADT032 module attached to this device, it will
+ * signal ready after the channels are configured and ready for use. */
+ if (!wc->vpmadt032)
+ wc->not_ready--;
return 0;
}
@@ -2671,7 +2674,9 @@ static void __devexit te12xp_remove_one(struct pci_dev *pdev)
{
struct t1 *wc = pci_get_drvdata(pdev);
#ifdef VPM_SUPPORT
- struct vpmadt032 *vpm = wc->vpmadt032;
+ unsigned long flags;
+ struct vpmadt032 *vpmadt = wc->vpmadt032;
+ struct vpmoct *vpmoct = wc->vpmoct;
#endif
if (!wc)
return;
@@ -2685,20 +2690,30 @@ static void __devexit te12xp_remove_one(struct pci_dev *pdev)
del_timer_sync(&wc->timer);
flush_workqueue(wc->wq);
#ifdef VPM_SUPPORT
- if (vpm)
- flush_workqueue(vpm->wq);
+ if (vpmadt) {
+ clear_bit(VPM150M_ACTIVE, &vpmadt->control);
+ flush_workqueue(vpmadt->wq);
+ } else if (vpmoct) {
+ while (t1_wait_for_ready(wc))
+ schedule();
+ }
#endif
del_timer_sync(&wc->timer);
voicebus_release(&wc->vb);
#ifdef VPM_SUPPORT
- if(vpm) {
+ if (vpmadt) {
+ spin_lock_irqsave(&wc->reglock, flags);
wc->vpmadt032 = NULL;
- clear_bit(VPM150M_ACTIVE, &vpm->control);
- vpmadt032_free(vpm);
+ spin_unlock_irqrestore(&wc->reglock, flags);
+ vpmadt032_free(vpmadt);
+ } else if (vpmoct) {
+ spin_lock_irqsave(&wc->reglock, flags);
+ wc->vpmoct = NULL;
+ spin_unlock_irqrestore(&wc->reglock, flags);
+ vpmoct_free(vpmoct);
}
-
#endif
t1_info(wc, "Freed a Wildcard TE12xP.\n");
diff --git a/drivers/dahdi/wcte12xp/wcte12xp.h b/drivers/dahdi/wcte12xp/wcte12xp.h
index a927e07..507a43e 100644
--- a/drivers/dahdi/wcte12xp/wcte12xp.h
+++ b/drivers/dahdi/wcte12xp/wcte12xp.h
@@ -139,7 +139,7 @@ struct t1 {
struct timer_list timer;
struct work_struct timer_work;
struct workqueue_struct *wq;
- bool initialized; /* 0 when entire card is ready to go */
+ unsigned int not_ready; /* 0 when entire card is ready to go */
};
#define t1_info(t1, format, arg...) \