summaryrefslogtreecommitdiff
path: root/drivers/dahdi
diff options
context:
space:
mode:
authorTzafrir Cohen <tzafrir.cohen@xorcom.com>2010-07-13 15:10:30 +0000
committerTzafrir Cohen <tzafrir.cohen@xorcom.com>2010-07-13 15:10:30 +0000
commitfe0081acc9a07f762121338e9e3f523b240ed178 (patch)
treee8e2174cb2e859ef0e22b987a0f9544e26d44628 /drivers/dahdi
parent921654884fd0ad506e7f7f6a34760a905f96b2ea (diff)
Keep SYSFS objects after disconnect
When the USB device disconnects, we keep references to them to make sure they don't disappear. git-svn-id: http://svn.asterisk.org/svn/dahdi/linux/trunk@8900 a0bf4364-ded3-4de4-8d8a-66a801d63aff
Diffstat (limited to 'drivers/dahdi')
-rw-r--r--drivers/dahdi/xpp/xbus-core.c37
-rw-r--r--drivers/dahdi/xpp/xbus-core.h5
-rw-r--r--drivers/dahdi/xpp/xbus-sysfs.c39
-rw-r--r--drivers/dahdi/xpp/xpd.h2
-rw-r--r--drivers/dahdi/xpp/xpp_dahdi.c26
5 files changed, 78 insertions, 31 deletions
diff --git a/drivers/dahdi/xpp/xbus-core.c b/drivers/dahdi/xpp/xbus-core.c
index 569b678..2d2ecb4 100644
--- a/drivers/dahdi/xpp/xbus-core.c
+++ b/drivers/dahdi/xpp/xbus-core.c
@@ -141,28 +141,36 @@ static void finalize_xbuses_array(void)
}
}
-xbus_t *get_xbus(const char *msg, xbus_t *xbus)
+/*
+ * Called by put_xbus() when XBUS has no more references.
+ */
+static void xbus_destroy(struct kref *kref)
{
- struct device *dev;
+ xbus_t *xbus;
+ xbus = kref_to_xbus(kref);
+ XBUS_NOTICE(xbus, "%s\n", __func__);
+ xbus_sysfs_remove(xbus);
+}
+
+xbus_t *get_xbus(const char *msg, xbus_t *xbus)
+{
XBUS_DBG(DEVICES, xbus, "%s: refcount_xbus=%d\n",
msg, refcount_xbus(xbus));
- dev = get_device(&xbus->astribank);
- if (!dev)
- return NULL;
- return dev_to_xbus(dev);
+ kref_get(&xbus->kref);
+ return xbus;
}
void put_xbus(const char *msg, xbus_t *xbus)
{
XBUS_DBG(DEVICES, xbus, "%s: refcount_xbus=%d\n",
msg, refcount_xbus(xbus));
- put_device(&xbus->astribank);
+ kref_put(&xbus->kref, xbus_destroy);
}
int refcount_xbus(xbus_t *xbus)
{
- struct kref *kref = &xbus->astribank.kobj.kref;
+ struct kref *kref = &xbus->kref;
return atomic_read(&kref->refcount);
}
@@ -1049,7 +1057,6 @@ static void worker_reset(xbus_t *xbus)
BUG_ON(!xbus);
worker = &xbus->worker;
- xbus = container_of(worker, xbus_t, worker);
name = (xbus) ? xbus->busname : "detached";
DBG(DEVICES, "%s\n", name);
if(!worker->xpds_init_done) {
@@ -1300,7 +1307,7 @@ void xbus_deactivate(xbus_t *xbus)
xbus_command_queue_waitempty(xbus);
xbus_setstate(xbus, XBUS_STATE_DEACTIVATED);
worker_reset(xbus);
- xbus_release_xpds(xbus); /* taken in xpd_device_register() */
+ xbus_release_xpds(xbus); /* taken in xpd_alloc() [kref_init] */
elect_syncer("deactivate");
}
@@ -1323,7 +1330,8 @@ void xbus_disconnect(xbus_t *xbus)
worker_destroy(xbus);
XBUS_DBG(DEVICES, xbus, "Deactivated refcount_xbus=%d\n",
refcount_xbus(xbus));
- xbus_sysfs_remove(xbus); /* Device-Model */
+ xbus_sysfs_transport_remove(xbus); /* Device-Model */
+ put_xbus(__func__, xbus); /* from xbus_new() [kref_init()] */
}
static xbus_t *xbus_alloc(void)
@@ -1427,6 +1435,7 @@ xbus_t *xbus_new(struct xbus_ops *ops, ushort max_send_size, struct device *tran
xbus->min_tx_sync = INT_MAX;
xbus->min_rx_sync = INT_MAX;
+ kref_init(&xbus->kref);
worker_init(xbus);
atomic_set(&xbus->num_xpds, 0);
xbus->sync_mode = SYNC_MODE_NONE;
@@ -1435,6 +1444,12 @@ xbus_t *xbus_new(struct xbus_ops *ops, ushort max_send_size, struct device *tran
XBUS_ERR(xbus, "SYSFS creation failed: %d\n", err);
goto nobus;
}
+ err = xbus_sysfs_transport_create(xbus);
+ if (err) {
+ XBUS_ERR(xbus, "SYSFS transport link creation failed: %d\n",
+ err);
+ goto nobus;
+ }
xbus_reset_counters(xbus);
#ifdef CONFIG_PROC_FS
XBUS_DBG(PROC, xbus, "Creating xbus proc directory\n");
diff --git a/drivers/dahdi/xpp/xbus-core.h b/drivers/dahdi/xpp/xbus-core.h
index 259f87a..026c112 100644
--- a/drivers/dahdi/xpp/xbus-core.h
+++ b/drivers/dahdi/xpp/xbus-core.h
@@ -24,6 +24,7 @@
#include <linux/wait.h>
#include <linux/interrupt.h> /* for tasklets */
+#include <linux/kref.h>
#include "xpd.h"
#include "xframe_queue.h"
#include "xbus-pcm.h"
@@ -206,6 +207,8 @@ struct xbus {
/* Device-Model */
struct device astribank;
#define dev_to_xbus(dev) container_of(dev, struct xbus, astribank)
+ struct kref kref;
+#define kref_to_xbus(k) container_of(k, struct xbus, kref)
spinlock_t lock;
@@ -326,6 +329,8 @@ void xpd_device_unregister(xpd_t *xpd);
int xpp_driver_init(void);
void xpp_driver_exit(void);
+int xbus_sysfs_transport_create(xbus_t *xbus);
+void xbus_sysfs_transport_remove(xbus_t *xbus);
int xbus_sysfs_create(xbus_t *xbus);
void xbus_sysfs_remove(xbus_t *xbus);
diff --git a/drivers/dahdi/xpp/xbus-sysfs.c b/drivers/dahdi/xpp/xbus-sysfs.c
index d107f39..0a15a1d 100644
--- a/drivers/dahdi/xpp/xbus-sysfs.c
+++ b/drivers/dahdi/xpp/xbus-sysfs.c
@@ -781,8 +781,6 @@ int xpd_device_register(xbus_t *xbus, xpd_t *xpd)
XPD_ERR(xpd, "%s: device_register failed: %d\n", __FUNCTION__, ret);
return ret;
}
- xpd = get_xpd(__func__, xpd); /* Released in xbus_release_xpds() */
- BUG_ON(!xpd);
return 0;
}
@@ -804,7 +802,7 @@ void xpd_device_unregister(xpd_t *xpd)
/*--------- Sysfs Device handling ----*/
-void xbus_sysfs_remove(xbus_t *xbus)
+void xbus_sysfs_transport_remove(xbus_t *xbus)
{
struct device *astribank;
@@ -812,6 +810,33 @@ void xbus_sysfs_remove(xbus_t *xbus)
XBUS_DBG(DEVICES, xbus, "\n");
astribank = &xbus->astribank;
sysfs_remove_link(&astribank->kobj, "transport");
+}
+
+int xbus_sysfs_transport_create(xbus_t *xbus)
+{
+ struct device *astribank;
+ int ret = 0;
+
+ BUG_ON(!xbus);
+ XBUS_DBG(DEVICES, xbus, "\n");
+ astribank = &xbus->astribank;
+ ret = sysfs_create_link(&astribank->kobj, &astribank->parent->kobj,
+ "transport");
+ if (ret < 0) {
+ XBUS_ERR(xbus, "%s: sysfs_create_link failed: %d\n",
+ __func__, ret);
+ dev_set_drvdata(astribank, NULL);
+ }
+ return ret;
+}
+
+void xbus_sysfs_remove(xbus_t *xbus)
+{
+ struct device *astribank;
+
+ BUG_ON(!xbus);
+ XBUS_DBG(DEVICES, xbus, "\n");
+ astribank = &xbus->astribank;
if(!dev_get_drvdata(astribank))
return;
BUG_ON(dev_get_drvdata(astribank) != xbus);
@@ -836,15 +861,7 @@ int xbus_sysfs_create(xbus_t *xbus)
if(ret) {
XBUS_ERR(xbus, "%s: device_register failed: %d\n", __FUNCTION__, ret);
dev_set_drvdata(astribank, NULL);
- goto out;
- }
- ret = sysfs_create_link(&astribank->kobj, &astribank->parent->kobj, "transport");
- if(ret < 0) {
- XBUS_ERR(xbus, "%s: sysfs_create_link failed: %d\n", __FUNCTION__, ret);
- dev_set_drvdata(astribank, NULL);
- goto out;
}
-out:
return ret;
}
diff --git a/drivers/dahdi/xpp/xpd.h b/drivers/dahdi/xpp/xpd.h
index a2c0d52..04d6713 100644
--- a/drivers/dahdi/xpp/xpd.h
+++ b/drivers/dahdi/xpp/xpd.h
@@ -177,6 +177,8 @@ struct xpd {
enum xpd_state xpd_state;
struct device xpd_dev;
#define dev_to_xpd(dev) container_of(dev, struct xpd, xpd_dev)
+ struct kref kref;
+#define kref_to_xpd(k) container_of(k, struct xpd, kref)
/* Assure atomicity of changes to pcm_len and wanted_pcm_mask */
spinlock_t lock_recompute_pcm;
diff --git a/drivers/dahdi/xpp/xpp_dahdi.c b/drivers/dahdi/xpp/xpp_dahdi.c
index 1f57878..07041fc 100644
--- a/drivers/dahdi/xpp/xpp_dahdi.c
+++ b/drivers/dahdi/xpp/xpp_dahdi.c
@@ -122,30 +122,38 @@ static int proc_xpd_blink_write(struct file *file, const char __user *buffer, un
/*------------------------- XPD Management -------------------------*/
+/*
+ * Called by put_xpd() when XPD has no more references.
+ */
+static void xpd_destroy(struct kref *kref)
+{
+ xpd_t *xpd;
+
+ xpd = kref_to_xpd(kref);
+ XPD_NOTICE(xpd, "%s\n", __func__);
+ xpd_device_unregister(xpd);
+}
+
int refcount_xpd(xpd_t *xpd)
{
- struct kref *kref = &xpd->xpd_dev.kobj.kref;
+ struct kref *kref = &xpd->kref;
return atomic_read(&kref->refcount);
}
xpd_t *get_xpd(const char *msg, xpd_t *xpd)
{
- struct device *dev;
-
XPD_DBG(DEVICES, xpd, "%s: refcount_xpd=%d\n",
msg, refcount_xpd(xpd));
- dev = get_device(&xpd->xpd_dev);
- if (!dev)
- return NULL;
- return dev_to_xpd(dev);
+ kref_get(&xpd->kref);
+ return xpd;
}
void put_xpd(const char *msg, xpd_t *xpd)
{
XPD_DBG(DEVICES, xpd, "%s: refcount_xpd=%d\n",
msg, refcount_xpd(xpd));
- put_device(&xpd->xpd_dev);
+ kref_put(&xpd->kref, xpd_destroy);
}
static void xpd_proc_remove(xbus_t *xbus, xpd_t *xpd)
@@ -539,6 +547,7 @@ __must_check xpd_t *xpd_alloc(xbus_t *xbus,
atomic_set(&xpd->dahdi_registered, 0);
atomic_set(&xpd->open_counter, 0);
+ kref_init(&xpd->kref);
/* For USB-1 disable some channels */
if(MAX_SEND_SIZE(xbus) < RPACKET_SIZE(GLOBAL, PCM_WRITE)) {
@@ -614,7 +623,6 @@ void xbus_request_removal(xbus_t *xbus)
dahdi_qevent_lock(XPD_CHAN(xpd, j),DAHDI_EVENT_REMOVED);
}
}
- xpd_device_unregister(xpd);
}
}
}