diff options
author | Tzafrir Cohen <tzafrir.cohen@xorcom.com> | 2010-07-13 15:10:30 +0000 |
---|---|---|
committer | Tzafrir Cohen <tzafrir.cohen@xorcom.com> | 2010-07-13 15:10:30 +0000 |
commit | fe0081acc9a07f762121338e9e3f523b240ed178 (patch) | |
tree | e8e2174cb2e859ef0e22b987a0f9544e26d44628 /drivers | |
parent | 921654884fd0ad506e7f7f6a34760a905f96b2ea (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')
-rw-r--r-- | drivers/dahdi/xpp/xbus-core.c | 37 | ||||
-rw-r--r-- | drivers/dahdi/xpp/xbus-core.h | 5 | ||||
-rw-r--r-- | drivers/dahdi/xpp/xbus-sysfs.c | 39 | ||||
-rw-r--r-- | drivers/dahdi/xpp/xpd.h | 2 | ||||
-rw-r--r-- | drivers/dahdi/xpp/xpp_dahdi.c | 26 |
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); } } } |