Hello,
I sent a post a few days ago outlining a crash that I was experiencing
when trying to remove the xc3028_tuner module with the
v4l-dvb-experimental codebase. I have investigated the issue further
and determined that my previously suggested fix is not sufficient. With
my previous suggestion, dvb_frontend_detach would still try to call
symbol_put_addr on xc3028_release even though there was no previous
symbol_request call for that symbol. That would cause the "Used by"
reference counter for xc3028_tuner to become a negative value meaning
that the module could not be unloaded.
The attached patch fixes this by exporting xc3028_release from
xc3028_tuner and then requesting it in cxusb_xc3028_tuner_attach. This
means that xc3028_tuner cannot be unloaded before dvb_usb_cxusb (or else
dvb_frontend_detach will try to call xc3028_release even though
xc3028_tuner is not loaded).
Daniel
diff -ruN v4l-dvb-experimental.orig/linux/drivers/media/dvb/dvb-usb/cxusb.c v4l-dvb-experimental/linux/drivers/media/dvb/dvb-usb/cxusb.c
--- v4l-dvb-experimental.orig/linux/drivers/media/dvb/dvb-usb/cxusb.c 2007-05-06 18:36:26.000000000 +1000
+++ v4l-dvb-experimental/linux/drivers/media/dvb/dvb-usb/cxusb.c 2007-05-07 03:24:35.480456621 +1000
@@ -448,6 +448,9 @@
adap->fe->ops.tuner_ops.ioctl = cxusb_xc3028_ioctl;
adap->fe->ops.tuner_ops.dev = adap;
dvb_attach(xc3028_attach,&adap->fe->ops.tuner_ops, &adap->dev->i2c_adap, NULL);
+#ifdef CONFIG_DVB_CORE_ATTACH
+ symbol_request(xc3028_release);
+#endif
return 0;
}
diff -ruN v4l-dvb-experimental.orig/linux/drivers/media/tuners/xc3028-tuner.c v4l-dvb-experimental/linux/drivers/media/tuners/xc3028-tuner.c
--- v4l-dvb-experimental.orig/linux/drivers/media/tuners/xc3028-tuner.c 2007-05-06 18:36:26.000000000 +1000
+++ v4l-dvb-experimental/linux/drivers/media/tuners/xc3028-tuner.c 2007-05-07 03:21:07.439948871 +1000
@@ -512,14 +512,13 @@
return 0;
}
-static int xc3028_release(struct v4l_dvb_tuner_ops *t)
+int xc3028_release(struct v4l_dvb_tuner_ops *t)
{
struct xc3028_priv *priv = t->priv;
if(priv)
kfree(priv);
t->priv = NULL;
- t->release=NULL;
return 0;
}
@@ -578,6 +577,7 @@
}
EXPORT_SYMBOL(xc3028_attach);
+EXPORT_SYMBOL(xc3028_release);
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
diff -ruN v4l-dvb-experimental.orig/linux/drivers/media/tuners/xc3028-tuner.h v4l-dvb-experimental/linux/drivers/media/tuners/xc3028-tuner.h
--- v4l-dvb-experimental.orig/linux/drivers/media/tuners/xc3028-tuner.h 2007-05-06 18:36:26.000000000 +1000
+++ v4l-dvb-experimental/linux/drivers/media/tuners/xc3028-tuner.h 2007-05-07 03:20:01.824003768 +1000
@@ -8,6 +8,7 @@
#if defined(CONFIG_XC3028_TUNER) || (defined(CONFIG_XC3028_TUNER_MODULE) && defined(MODULE))
extern struct v4l_dvb_tuner_ops *xc3028_attach(struct v4l_dvb_tuner_ops *dev, struct i2c_adapter *i2c, struct xc3028_config *config);
+int xc3028_release(struct v4l_dvb_tuner_ops *t);
#else
static inline struct v4l_dvb_tuner_ops *xc3028_attach(struct v4l_dvb_tuner_ops *dev,
struct i2c_adapter *i2c, struct xc3028_config *config)
_______________________________________________
linux-dvb mailing list
[email protected]
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb