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 linux-dvb@xxxxxxxxxxx http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb