diff mbox

zr36067 no longer loads automatically (regression)

Message ID Pine.LNX.4.58.0901082156270.1626@shell2.speakeasy.net (mailing list archive)
State RFC
Headers show

Commit Message

Trent Piepho Jan. 9, 2009, 6:01 a.m. UTC
On Thu, 8 Jan 2009, Mauro Carvalho Chehab wrote:
> On Thu, 8 Jan 2009 13:20:19 -0800 (PST)
> Trent Piepho <xyzzy@speakeasy.org> wrote:
> > On Thu, 8 Jan 2009, Mauro Carvalho Chehab wrote:
> > It doesn't seem like any other driver needs to protect the module device
> > table with an ifdef.
>
> However, Zoran driver doesn't rely on pci_register_driver(). Instead, it uses a
> while() loop to probe for Zoran devices:
>
> static int __devinit
> find_zr36057 (void)
> {
> 	...
>
>         zoran_num = 0;
>         while (zoran_num < BUZ_MAX &&
>                (dev = pci_get_device(PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36057, dev)) != NULL) {
> 	...
> }

Yuck, why don't we fix this instead?

Here's an initial test.  I haven't yet found my dc10+ to test it with.

--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Comments

Jean Delvare Jan. 9, 2009, 9:05 a.m. UTC | #1
Hi Trent,

On Thu, 8 Jan 2009 22:01:08 -0800 (PST), Trent Piepho wrote:
> On Thu, 8 Jan 2009, Mauro Carvalho Chehab wrote:
> > On Thu, 8 Jan 2009 13:20:19 -0800 (PST)
> > Trent Piepho <xyzzy@speakeasy.org> wrote:
> > > On Thu, 8 Jan 2009, Mauro Carvalho Chehab wrote:
> > > It doesn't seem like any other driver needs to protect the module device
> > > table with an ifdef.
> >
> > However, Zoran driver doesn't rely on pci_register_driver(). Instead, it uses a
> > while() loop to probe for Zoran devices:
> >
> > static int __devinit
> > find_zr36057 (void)
> > {
> > 	...
> >
> >         zoran_num = 0;
> >         while (zoran_num < BUZ_MAX &&
> >                (dev = pci_get_device(PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36057, dev)) != NULL) {
> > 	...
> > }
> 
> Yuck, why don't we fix this instead?
> 
> Here's an initial test.  I haven't yet found my dc10+ to test it with.

I'm all for it, but what tree was your patch built against? It doesn't
seem to apply to anything I have.
Trent Piepho Jan. 9, 2009, 9:13 a.m. UTC | #2
On Fri, 9 Jan 2009, Jean Delvare wrote:
> On Thu, 8 Jan 2009 22:01:08 -0800 (PST), Trent Piepho wrote:
> > On Thu, 8 Jan 2009, Mauro Carvalho Chehab wrote:
> > > However, Zoran driver doesn't rely on pci_register_driver(). Instead, it uses a
> > > while() loop to probe for Zoran devices:
> > >
> > > static int __devinit
> > > find_zr36057 (void)
> > > {
> > > 	...
> > >
> > >         zoran_num = 0;
> > >         while (zoran_num < BUZ_MAX &&
> > >                (dev = pci_get_device(PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36057, dev)) != NULL) {
> > > 	...
> > > }
> >
> > Yuck, why don't we fix this instead?
> >
> > Here's an initial test.  I haven't yet found my dc10+ to test it with.
>
> I'm all for it, but what tree was your patch built against? It doesn't
> seem to apply to anything I have.

The v4l-dvb main Hg from yesterday.  Looks like Maruo's since committed the
small patch he posted earlier.
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Mauro Carvalho Chehab Jan. 9, 2009, 11:20 a.m. UTC | #3
On Thu, 8 Jan 2009 22:01:08 -0800 (PST)
Trent Piepho <xyzzy@speakeasy.org> wrote:

> On Thu, 8 Jan 2009, Mauro Carvalho Chehab wrote:
> > On Thu, 8 Jan 2009 13:20:19 -0800 (PST)
> > Trent Piepho <xyzzy@speakeasy.org> wrote:
> > > On Thu, 8 Jan 2009, Mauro Carvalho Chehab wrote:
> > > It doesn't seem like any other driver needs to protect the module device
> > > table with an ifdef.
> >
> > However, Zoran driver doesn't rely on pci_register_driver(). Instead, it uses a
> > while() loop to probe for Zoran devices:
> >
> > static int __devinit
> > find_zr36057 (void)
> > {
> > 	...
> >
> >         zoran_num = 0;
> >         while (zoran_num < BUZ_MAX &&
> >                (dev = pci_get_device(PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36057, dev)) != NULL) {
> > 	...
> > }
> 
> Yuck, why don't we fix this instead?

This will be much better.

> Here's an initial test.  I haven't yet found my dc10+ to test it with.

Unfortunately, I don't have any Zoran card here to test.

Jean, it is up to you to test Trent's patch.
Mauro Carvalho Chehab Jan. 9, 2009, 11:22 a.m. UTC | #4
On Fri, 9 Jan 2009 01:13:59 -0800 (PST)
Trent Piepho <xyzzy@speakeasy.org> wrote:

> > > Here's an initial test.  I haven't yet found my dc10+ to test it with.
> >
> > I'm all for it, but what tree was your patch built against? It doesn't
> > seem to apply to anything I have.
> 
> The v4l-dvb main Hg from yesterday.  Looks like Maruo's since committed the
> small patch he posted earlier.

Yes. Better to have for now an interim solution, to avoid others to complain. I
also sent the interim solution to linux-next, but I'll hold a pull request for
a while, since your solution is better.
Jean Delvare Jan. 9, 2009, 11:43 a.m. UTC | #5
On Fri, 9 Jan 2009 09:20:18 -0200, Mauro Carvalho Chehab wrote:
> 
> On Thu, 8 Jan 2009 22:01:08 -0800 (PST)
> Trent Piepho <xyzzy@speakeasy.org> wrote:
> 
> > On Thu, 8 Jan 2009, Mauro Carvalho Chehab wrote:
> > > On Thu, 8 Jan 2009 13:20:19 -0800 (PST)
> > > Trent Piepho <xyzzy@speakeasy.org> wrote:
> > > > On Thu, 8 Jan 2009, Mauro Carvalho Chehab wrote:
> > > > It doesn't seem like any other driver needs to protect the module device
> > > > table with an ifdef.
> > >
> > > However, Zoran driver doesn't rely on pci_register_driver(). Instead, it uses a
> > > while() loop to probe for Zoran devices:
> > >
> > > static int __devinit
> > > find_zr36057 (void)
> > > {
> > > 	...
> > >
> > >         zoran_num = 0;
> > >         while (zoran_num < BUZ_MAX &&
> > >                (dev = pci_get_device(PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36057, dev)) != NULL) {
> > > 	...
> > > }
> > 
> > Yuck, why don't we fix this instead?
> 
> This will be much better.
> 
> > Here's an initial test.  I haven't yet found my dc10+ to test it with.
> 
> Unfortunately, I don't have any Zoran card here to test.
> 
> Jean, it is up to you to test Trent's patch.

Will do as soon as I manage to apply it.
Trent Piepho Jan. 9, 2009, 8:12 p.m. UTC | #6
On Fri, 9 Jan 2009, Jean Delvare wrote:
> On Fri, 9 Jan 2009 09:20:18 -0200, Mauro Carvalho Chehab wrote:
> > On Thu, 8 Jan 2009 22:01:08 -0800 (PST)
> > Trent Piepho <xyzzy@speakeasy.org> wrote:
> > >
> > > Yuck, why don't we fix this instead?
> >
> > This will be much better.
> >
> > > Here's an initial test.  I haven't yet found my dc10+ to test it with.
> >
> > Unfortunately, I don't have any Zoran card here to test.
> >
> > Jean, it is up to you to test Trent's patch.
>
> Will do as soon as I manage to apply it.

Here is a new version against latest v4l-dvb sources.  Jean, are you trying
to apply against the kernel tree?  These patches are against the v4l-dvb Hg
repository which isn't quite the same as what's in the kernel.

I have some more patches at http://linuxtv.org/hg/~tap/zoran
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Jean Delvare Jan. 9, 2009, 8:28 p.m. UTC | #7
On Fri, 9 Jan 2009 12:12:09 -0800 (PST), Trent Piepho wrote:
> On Fri, 9 Jan 2009, Jean Delvare wrote:
> > On Fri, 9 Jan 2009 09:20:18 -0200, Mauro Carvalho Chehab wrote:
> > > Unfortunately, I don't have any Zoran card here to test.
> > >
> > > Jean, it is up to you to test Trent's patch.
> >
> > Will do as soon as I manage to apply it.
> 
> Here is a new version against latest v4l-dvb sources.

-ENOPATCH

>  Jean, are you trying
> to apply against the kernel tree?  These patches are against the v4l-dvb Hg
> repository which isn't quite the same as what's in the kernel.

I know that, I was working off the hg repository, but had some build
problems against Linus' latest kernel. Solved by building against
2.6.28 instead, but then I had to wait until I could reboot to that
kernel before I could test. This just happened. I'll report as soon as
I am done with testing.

> I have some more patches at http://linuxtv.org/hg/~tap/zoran

I'll take a look, thanks.
Jean Delvare Jan. 10, 2009, 1:56 p.m. UTC | #8
On Fri, 9 Jan 2009 21:28:31 +0100, Jean Delvare wrote:
> On Fri, 9 Jan 2009 12:12:09 -0800 (PST), Trent Piepho wrote:
> > I have some more patches at http://linuxtv.org/hg/~tap/zoran
> 
> I'll take a look, thanks.

As discussed on IRC: all patches tested, they worked fine for me,
thanks for your excellent work. Feel free to add:

Acked-by: Jean Delvare <khali@linux-fr.org>

to all 5 patches.
diff mbox

Patch

diff -r 1bfe820d27c6 linux/drivers/media/video/zoran/zoran_card.c
--- a/linux/drivers/media/video/zoran/zoran_card.c	Thu Jan 08 18:13:53 2009 -0200
+++ b/linux/drivers/media/video/zoran/zoran_card.c	Thu Jan 08 19:23:50 2009 -0800
@@ -154,16 +154,13 @@  MODULE_AUTHOR("Serguei Miridonov");
 MODULE_AUTHOR("Serguei Miridonov");
 MODULE_LICENSE("GPL");

-#if 0
 static struct pci_device_id zr36067_pci_tbl[] = {
-	{PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36057,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_DEVICE(PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36057), },
 	{0}
 };
 MODULE_DEVICE_TABLE(pci, zr36067_pci_tbl);
-#endif
-
-int zoran_num;			/* number of Buzs in use */
+
+atomic_t zoran_num = ATOMIC_INIT(0);		/* number of Buzs in use */
 struct zoran *zoran[BUZ_MAX];

 /* videocodec bus functions ZR36060 */
@@ -1147,7 +1144,7 @@  zr36057_init (struct zoran *zr)
 	strcpy(zr->video_dev->name, ZR_DEVNAME(zr));
 	err = video_register_device(zr->video_dev, VFL_TYPE_GRABBER, video_nr[zr->id]);
 	if (err < 0)
-		goto exit_unregister;
+		goto exit_free;

 	zoran_init_hardware(zr);
 	if (zr36067_debug > 2)
@@ -1162,19 +1159,19 @@  zr36057_init (struct zoran *zr)
 	zr->initialized = 1;
 	return 0;

-exit_unregister:
-	zoran_unregister_i2c(zr);
 exit_free:
 	kfree(zr->stat_com);
 	kfree(zr->video_dev);
 	return err;
 }

-static void
-zoran_release (struct zoran *zr)
-{
+static void __devexit zoran_remove(struct pci_dev *pdev)
+{
+	struct zoran *zr = pci_get_drvdata(pdev);
+
 	if (!zr->initialized)
 		goto exit_free;
+
 	/* unregister videocodec bus */
 	if (zr->codec) {
 		struct videocodec_master *master = zr->codec->master_data;
@@ -1203,6 +1200,7 @@  zoran_release (struct zoran *zr)
 	pci_disable_device(zr->pci_dev);
 	video_unregister_device(zr->video_dev);
 exit_free:
+	pci_set_drvdata(pdev, NULL);
 	kfree(zr);
 }

@@ -1265,323 +1263,342 @@  zoran_setup_videocodec (struct zoran *zr
  *   Scan for a Buz card (actually for the PCI controller ZR36057),
  *   request the irq and map the io memory
  */
-static int __devinit
-find_zr36057 (void)
+static int __devinit zoran_probe(struct pci_dev *pdev,
+				 const struct pci_device_id *ent)
 {
 	unsigned char latency, need_latency;
 	struct zoran *zr;
-	struct pci_dev *dev = NULL;
 	int result;
 	struct videocodec_master *master_vfe = NULL;
 	struct videocodec_master *master_codec = NULL;
 	int card_num;
 	char *i2c_enc_name, *i2c_dec_name, *codec_name, *vfe_name;
-
-	zoran_num = 0;
-	while (zoran_num < BUZ_MAX &&
-	       (dev = pci_get_device(PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36057, dev)) != NULL) {
-		card_num = card[zoran_num];
-		zr = kzalloc(sizeof(struct zoran), GFP_KERNEL);
-		if (!zr) {
+	unsigned int nr;
+
+
+	nr = atomic_inc_return(&zoran_num) - 1;
+	if (nr >= BUZ_MAX) {
+		dev_err(&pdev->dev, "driver limited to %d card(s) maximum\n", BUZ_MAX);
+		return -ENOENT;
+	}
+
+	card_num = card[nr];
+	zr = kzalloc(sizeof(struct zoran), GFP_KERNEL);
+	if (!zr) {
+		dprintk(1,
+			KERN_ERR
+			"%s: find_zr36057() - kzalloc failed\n",
+			ZORAN_NAME);
+		/* The entry in zoran[] gets leaked */
+		return -ENOMEM;
+	}
+	zr->pci_dev = pdev;
+	//zr->zr36057_mem = NULL;
+	zr->id = nr;
+	snprintf(ZR_DEVNAME(zr), sizeof(ZR_DEVNAME(zr)), "MJPEG[%u]", zr->id);
+	spin_lock_init(&zr->spinlock);
+	mutex_init(&zr->resource_lock);
+	if (pci_enable_device(pdev))
+		goto zr_free_mem;
+	zr->zr36057_adr = pci_resource_start(zr->pci_dev, 0);
+	pci_read_config_byte(zr->pci_dev, PCI_CLASS_REVISION,
+			     &zr->revision);
+	if (zr->revision < 2) {
+		dprintk(1,
+			KERN_INFO
+			"%s: Zoran ZR36057 (rev %d) irq: %d, memory: 0x%08x.\n",
+			ZR_DEVNAME(zr), zr->revision, zr->pci_dev->irq,
+			zr->zr36057_adr);
+
+		if (card_num == -1) {
 			dprintk(1,
 				KERN_ERR
-				"%s: find_zr36057() - kzalloc failed\n",
-				ZORAN_NAME);
-			continue;
+				"%s: find_zr36057() - no card specified, please use the card=X insmod option\n",
+				ZR_DEVNAME(zr));
+			goto zr_free_mem;
 		}
-		zr->pci_dev = dev;
-		//zr->zr36057_mem = NULL;
-		zr->id = zoran_num;
-		snprintf(ZR_DEVNAME(zr), sizeof(ZR_DEVNAME(zr)), "MJPEG[%u]", zr->id);
-		spin_lock_init(&zr->spinlock);
-		mutex_init(&zr->resource_lock);
-		if (pci_enable_device(dev))
-			goto zr_free_mem;
-		zr->zr36057_adr = pci_resource_start(zr->pci_dev, 0);
-		pci_read_config_byte(zr->pci_dev, PCI_CLASS_REVISION,
-				     &zr->revision);
-		if (zr->revision < 2) {
-			dprintk(1,
-				KERN_INFO
-				"%s: Zoran ZR36057 (rev %d) irq: %d, memory: 0x%08x.\n",
-				ZR_DEVNAME(zr), zr->revision, zr->pci_dev->irq,
-				zr->zr36057_adr);
-
-			if (card_num == -1) {
+	} else {
+		int i;
+		unsigned short ss_vendor, ss_device;
+
+		ss_vendor = zr->pci_dev->subsystem_vendor;
+		ss_device = zr->pci_dev->subsystem_device;
+		dprintk(1,
+			KERN_INFO
+			"%s: Zoran ZR36067 (rev %d) irq: %d, memory: 0x%08x\n",
+			ZR_DEVNAME(zr), zr->revision, zr->pci_dev->irq,
+			zr->zr36057_adr);
+		dprintk(1,
+			KERN_INFO
+			"%s: subsystem vendor=0x%04x id=0x%04x\n",
+			ZR_DEVNAME(zr), ss_vendor, ss_device);
+		if (card_num == -1) {
+			dprintk(3,
+				KERN_DEBUG
+				"%s: find_zr36057() - trying to autodetect card type\n",
+				ZR_DEVNAME(zr));
+			for (i=0;i<NUM_CARDS;i++) {
+				if (ss_vendor == zoran_cards[i].vendor_id &&
+				    ss_device == zoran_cards[i].device_id) {
+					dprintk(3,
+						KERN_DEBUG
+						"%s: find_zr36057() - card %s detected\n",
+						ZR_DEVNAME(zr),
+						zoran_cards[i].name);
+					card_num = i;
+					break;
+				}
+			}
+			if (i == NUM_CARDS) {
 				dprintk(1,
 					KERN_ERR
-					"%s: find_zr36057() - no card specified, please use the card=X insmod option\n",
+					"%s: find_zr36057() - unknown card\n",
 					ZR_DEVNAME(zr));
 				goto zr_free_mem;
 			}
-		} else {
-			int i;
-			unsigned short ss_vendor, ss_device;
-
-			ss_vendor = zr->pci_dev->subsystem_vendor;
-			ss_device = zr->pci_dev->subsystem_device;
-			dprintk(1,
-				KERN_INFO
-				"%s: Zoran ZR36067 (rev %d) irq: %d, memory: 0x%08x\n",
-				ZR_DEVNAME(zr), zr->revision, zr->pci_dev->irq,
-				zr->zr36057_adr);
-			dprintk(1,
-				KERN_INFO
-				"%s: subsystem vendor=0x%04x id=0x%04x\n",
-				ZR_DEVNAME(zr), ss_vendor, ss_device);
-			if (card_num == -1) {
-				dprintk(3,
-					KERN_DEBUG
-					"%s: find_zr36057() - trying to autodetect card type\n",
-					ZR_DEVNAME(zr));
-				for (i=0;i<NUM_CARDS;i++) {
-					if (ss_vendor == zoran_cards[i].vendor_id &&
-					    ss_device == zoran_cards[i].device_id) {
-						dprintk(3,
-							KERN_DEBUG
-							"%s: find_zr36057() - card %s detected\n",
-							ZR_DEVNAME(zr),
-							zoran_cards[i].name);
-						card_num = i;
-						break;
-					}
-				}
-				if (i == NUM_CARDS) {
-					dprintk(1,
-						KERN_ERR
-						"%s: find_zr36057() - unknown card\n",
-						ZR_DEVNAME(zr));
-					goto zr_free_mem;
-				}
-			}
 		}
-
-		if (card_num < 0 || card_num >= NUM_CARDS) {
-			dprintk(2,
-				KERN_ERR
-				"%s: find_zr36057() - invalid cardnum %d\n",
-				ZR_DEVNAME(zr), card_num);
-			goto zr_free_mem;
-		}
-
-		/* even though we make this a non pointer and thus
-		 * theoretically allow for making changes to this struct
-		 * on a per-individual card basis at runtime, this is
-		 * strongly discouraged. This structure is intended to
-		 * keep general card information, no settings or anything */
-		zr->card = zoran_cards[card_num];
-		snprintf(ZR_DEVNAME(zr), sizeof(ZR_DEVNAME(zr)),
-			 "%s[%u]", zr->card.name, zr->id);
-
-		zr->zr36057_mem = ioremap_nocache(zr->zr36057_adr, 0x1000);
-		if (!zr->zr36057_mem) {
+	}
+
+	if (card_num < 0 || card_num >= NUM_CARDS) {
+		dprintk(2,
+			KERN_ERR
+			"%s: find_zr36057() - invalid cardnum %d\n",
+			ZR_DEVNAME(zr), card_num);
+		goto zr_free_mem;
+	}
+
+	/* even though we make this a non pointer and thus
+	 * theoretically allow for making changes to this struct
+	 * on a per-individual card basis at runtime, this is
+	 * strongly discouraged. This structure is intended to
+	 * keep general card information, no settings or anything */
+	zr->card = zoran_cards[card_num];
+	snprintf(ZR_DEVNAME(zr), sizeof(ZR_DEVNAME(zr)),
+		 "%s[%u]", zr->card.name, zr->id);
+
+	zr->zr36057_mem = ioremap_nocache(zr->zr36057_adr, 0x1000);
+	if (!zr->zr36057_mem) {
+		dprintk(1,
+			KERN_ERR
+			"%s: find_zr36057() - ioremap failed\n",
+			ZR_DEVNAME(zr));
+		goto zr_free_mem;
+	}
+
+	result = request_irq(zr->pci_dev->irq,
+			     zoran_irq,
+			     IRQF_SHARED | IRQF_DISABLED,
+			     ZR_DEVNAME(zr),
+			     (void *) zr);
+	if (result < 0) {
+		if (result == -EINVAL) {
 			dprintk(1,
 				KERN_ERR
-				"%s: find_zr36057() - ioremap failed\n",
+				"%s: find_zr36057() - bad irq number or handler\n",
 				ZR_DEVNAME(zr));
-			goto zr_free_mem;
-		}
-
-		result = request_irq(zr->pci_dev->irq,
-				     zoran_irq,
-				     IRQF_SHARED | IRQF_DISABLED,
-				     ZR_DEVNAME(zr),
-				     (void *) zr);
-		if (result < 0) {
-			if (result == -EINVAL) {
-				dprintk(1,
-					KERN_ERR
-					"%s: find_zr36057() - bad irq number or handler\n",
-					ZR_DEVNAME(zr));
-			} else if (result == -EBUSY) {
-				dprintk(1,
-					KERN_ERR
-					"%s: find_zr36057() - IRQ %d busy, change your PnP config in BIOS\n",
-					ZR_DEVNAME(zr), zr->pci_dev->irq);
-			} else {
-				dprintk(1,
-					KERN_ERR
-					"%s: find_zr36057() - can't assign irq, error code %d\n",
-					ZR_DEVNAME(zr), result);
-			}
-			goto zr_unmap;
-		}
-
-		/* set PCI latency timer */
-		pci_read_config_byte(zr->pci_dev, PCI_LATENCY_TIMER,
-				     &latency);
-		need_latency = zr->revision > 1 ? 32 : 48;
-		if (latency != need_latency) {
-			dprintk(2,
-				KERN_INFO
-				"%s: Changing PCI latency from %d to %d.\n",
-				ZR_DEVNAME(zr), latency, need_latency);
-			pci_write_config_byte(zr->pci_dev,
-					      PCI_LATENCY_TIMER,
-					      need_latency);
-		}
-
-		zr36057_restart(zr);
-		/* i2c */
-		dprintk(2, KERN_INFO "%s: Initializing i2c bus...\n",
-			ZR_DEVNAME(zr));
-
-		/* i2c decoder */
-		if (decoder[zr->id] != -1) {
-			i2c_dec_name = i2cid_to_modulename(decoder[zr->id]);
-			zr->card.i2c_decoder = decoder[zr->id];
-		} else if (zr->card.i2c_decoder != 0) {
-			i2c_dec_name =
-				i2cid_to_modulename(zr->card.i2c_decoder);
-		} else {
-			i2c_dec_name = NULL;
-		}
-
-		if (i2c_dec_name) {
-			if ((result = request_module(i2c_dec_name)) < 0) {
-				dprintk(1,
-					KERN_ERR
-					"%s: failed to load module %s: %d\n",
-					ZR_DEVNAME(zr), i2c_dec_name, result);
-			}
-		}
-
-		/* i2c encoder */
-		if (encoder[zr->id] != -1) {
-			i2c_enc_name = i2cid_to_modulename(encoder[zr->id]);
-			zr->card.i2c_encoder = encoder[zr->id];
-		} else if (zr->card.i2c_encoder != 0) {
-			i2c_enc_name =
-				i2cid_to_modulename(zr->card.i2c_encoder);
-		} else {
-			i2c_enc_name = NULL;
-		}
-
-		if (i2c_enc_name) {
-			if ((result = request_module(i2c_enc_name)) < 0) {
-				dprintk(1,
-					KERN_ERR
-					"%s: failed to load module %s: %d\n",
-					ZR_DEVNAME(zr), i2c_enc_name, result);
-			}
-		}
-
-		if (zoran_register_i2c(zr) < 0) {
+		} else if (result == -EBUSY) {
 			dprintk(1,
 				KERN_ERR
-				"%s: find_zr36057() - can't initialize i2c bus\n",
+				"%s: find_zr36057() - IRQ %d busy, change your PnP config in BIOS\n",
+				ZR_DEVNAME(zr), zr->pci_dev->irq);
+		} else {
+			dprintk(1,
+				KERN_ERR
+				"%s: find_zr36057() - can't assign irq, error code %d\n",
+				ZR_DEVNAME(zr), result);
+		}
+		goto zr_unmap;
+	}
+
+	/* set PCI latency timer */
+	pci_read_config_byte(zr->pci_dev, PCI_LATENCY_TIMER,
+			     &latency);
+	need_latency = zr->revision > 1 ? 32 : 48;
+	if (latency != need_latency) {
+		dprintk(2,
+			KERN_INFO
+			"%s: Changing PCI latency from %d to %d.\n",
+			ZR_DEVNAME(zr), latency, need_latency);
+		pci_write_config_byte(zr->pci_dev,
+				      PCI_LATENCY_TIMER,
+				      need_latency);
+	}
+
+	zr36057_restart(zr);
+	/* i2c */
+	dprintk(2, KERN_INFO "%s: Initializing i2c bus...\n",
+		ZR_DEVNAME(zr));
+
+	/* i2c decoder */
+	if (decoder[zr->id] != -1) {
+		i2c_dec_name = i2cid_to_modulename(decoder[zr->id]);
+		zr->card.i2c_decoder = decoder[zr->id];
+	} else if (zr->card.i2c_decoder != 0) {
+		i2c_dec_name =
+			i2cid_to_modulename(zr->card.i2c_decoder);
+	} else {
+		i2c_dec_name = NULL;
+	}
+
+	if (i2c_dec_name) {
+		if ((result = request_module(i2c_dec_name)) < 0) {
+			dprintk(1,
+				KERN_ERR
+				"%s: failed to load module %s: %d\n",
+				ZR_DEVNAME(zr), i2c_dec_name, result);
+		}
+	}
+
+	/* i2c encoder */
+	if (encoder[zr->id] != -1) {
+		i2c_enc_name = i2cid_to_modulename(encoder[zr->id]);
+		zr->card.i2c_encoder = encoder[zr->id];
+	} else if (zr->card.i2c_encoder != 0) {
+		i2c_enc_name =
+			i2cid_to_modulename(zr->card.i2c_encoder);
+	} else {
+		i2c_enc_name = NULL;
+	}
+
+	if (i2c_enc_name) {
+		if ((result = request_module(i2c_enc_name)) < 0) {
+			dprintk(1,
+				KERN_ERR
+				"%s: failed to load module %s: %d\n",
+				ZR_DEVNAME(zr), i2c_enc_name, result);
+		}
+	}
+
+	if (zoran_register_i2c(zr) < 0) {
+		dprintk(1,
+			KERN_ERR
+			"%s: find_zr36057() - can't initialize i2c bus\n",
+			ZR_DEVNAME(zr));
+		goto zr_free_irq;
+	}
+
+	dprintk(2,
+		KERN_INFO "%s: Initializing videocodec bus...\n",
+		ZR_DEVNAME(zr));
+
+	if (zr->card.video_codec != 0 &&
+	    (codec_name =
+	     codecid_to_modulename(zr->card.video_codec)) != NULL) {
+		if ((result = request_module(codec_name)) < 0) {
+			dprintk(1,
+				KERN_ERR
+				"%s: failed to load modules %s: %d\n",
+				ZR_DEVNAME(zr), codec_name, result);
+		}
+	}
+	if (zr->card.video_vfe != 0 &&
+	    (vfe_name =
+	     codecid_to_modulename(zr->card.video_vfe)) != NULL) {
+		if ((result = request_module(vfe_name)) < 0) {
+			dprintk(1,
+				KERN_ERR
+				"%s: failed to load modules %s: %d\n",
+				ZR_DEVNAME(zr), vfe_name, result);
+		}
+	}
+
+	/* reset JPEG codec */
+	jpeg_codec_sleep(zr, 1);
+	jpeg_codec_reset(zr);
+	/* video bus enabled */
+	/* display codec revision */
+	if (zr->card.video_codec != 0) {
+		master_codec = zoran_setup_videocodec(zr,
+						      zr->card.video_codec);
+		if (!master_codec)
+			goto zr_unreg_i2c;
+		zr->codec = videocodec_attach(master_codec);
+		if (!zr->codec) {
+			dprintk(1,
+				KERN_ERR
+				"%s: find_zr36057() - no codec found\n",
 				ZR_DEVNAME(zr));
-			goto zr_free_irq;
+			goto zr_free_codec;
 		}
-
-		dprintk(2,
-			KERN_INFO "%s: Initializing videocodec bus...\n",
+		if (zr->codec->type != zr->card.video_codec) {
+			dprintk(1,
+				KERN_ERR
+				"%s: find_zr36057() - wrong codec\n",
+				ZR_DEVNAME(zr));
+			goto zr_detach_codec;
+		}
+	}
+	if (zr->card.video_vfe != 0) {
+		master_vfe = zoran_setup_videocodec(zr,
+						    zr->card.video_vfe);
+		if (!master_vfe)
+			goto zr_detach_codec;
+		zr->vfe = videocodec_attach(master_vfe);
+		if (!zr->vfe) {
+			dprintk(1,
+				KERN_ERR
+				"%s: find_zr36057() - no VFE found\n",
+				ZR_DEVNAME(zr));
+			goto zr_free_vfe;
+		}
+		if (zr->vfe->type != zr->card.video_vfe) {
+			dprintk(1,
+				KERN_ERR
+				"%s: find_zr36057() = wrong VFE\n",
+				ZR_DEVNAME(zr));
+			goto zr_detach_vfe;
+		}
+	}
+	zoran[nr] = zr;
+
+	/* take care of Natoma chipset and a revision 1 zr36057 */
+	if ((pci_pci_problems & PCIPCI_NATOMA) && zr->revision <= 1) {
+		zr->jpg_buffers.need_contiguous = 1;
+		dprintk(1,
+			KERN_INFO
+			"%s: ZR36057/Natoma bug, max. buffer size is 128K\n",
 			ZR_DEVNAME(zr));
-
-		if (zr->card.video_codec != 0 &&
-		    (codec_name =
-		     codecid_to_modulename(zr->card.video_codec)) != NULL) {
-			if ((result = request_module(codec_name)) < 0) {
-				dprintk(1,
-					KERN_ERR
-					"%s: failed to load modules %s: %d\n",
-					ZR_DEVNAME(zr), codec_name, result);
-			}
-		}
-		if (zr->card.video_vfe != 0 &&
-		    (vfe_name =
-		     codecid_to_modulename(zr->card.video_vfe)) != NULL) {
-			if ((result = request_module(vfe_name)) < 0) {
-				dprintk(1,
-					KERN_ERR
-					"%s: failed to load modules %s: %d\n",
-					ZR_DEVNAME(zr), vfe_name, result);
-			}
-		}
-
-		/* reset JPEG codec */
-		jpeg_codec_sleep(zr, 1);
-		jpeg_codec_reset(zr);
-		/* video bus enabled */
-		/* display codec revision */
-		if (zr->card.video_codec != 0) {
-			master_codec = zoran_setup_videocodec(zr,
-							      zr->card.video_codec);
-			if (!master_codec)
-				goto zr_unreg_i2c;
-			zr->codec = videocodec_attach(master_codec);
-			if (!zr->codec) {
-				dprintk(1,
-					KERN_ERR
-					"%s: find_zr36057() - no codec found\n",
-					ZR_DEVNAME(zr));
-				goto zr_free_codec;
-			}
-			if (zr->codec->type != zr->card.video_codec) {
-				dprintk(1,
-					KERN_ERR
-					"%s: find_zr36057() - wrong codec\n",
-					ZR_DEVNAME(zr));
-				goto zr_detach_codec;
-			}
-		}
-		if (zr->card.video_vfe != 0) {
-			master_vfe = zoran_setup_videocodec(zr,
-							    zr->card.video_vfe);
-			if (!master_vfe)
-				goto zr_detach_codec;
-			zr->vfe = videocodec_attach(master_vfe);
-			if (!zr->vfe) {
-				dprintk(1,
-					KERN_ERR
-					"%s: find_zr36057() - no VFE found\n",
-					ZR_DEVNAME(zr));
-				goto zr_free_vfe;
-			}
-			if (zr->vfe->type != zr->card.video_vfe) {
-				dprintk(1,
-					KERN_ERR
-					"%s: find_zr36057() = wrong VFE\n",
-					ZR_DEVNAME(zr));
-				goto zr_detach_vfe;
-			}
-		}
-		/* Success so keep the pci_dev referenced */
-		pci_dev_get(zr->pci_dev);
-		zoran[zoran_num++] = zr;
-		continue;
-
-		// Init errors
-	      zr_detach_vfe:
-		videocodec_detach(zr->vfe);
-	      zr_free_vfe:
-		kfree(master_vfe);
-	      zr_detach_codec:
-		videocodec_detach(zr->codec);
-	      zr_free_codec:
-		kfree(master_codec);
-	      zr_unreg_i2c:
-		zoran_unregister_i2c(zr);
-	      zr_free_irq:
-		btwrite(0, ZR36057_SPGPPCR);
-		free_irq(zr->pci_dev->irq, zr);
-	      zr_unmap:
-		iounmap(zr->zr36057_mem);
-	      zr_free_mem:
-		kfree(zr);
-		continue;
-	}
-	if (dev)	/* Clean up ref count on early exit */
-		pci_dev_put(dev);
-
-	if (zoran_num == 0) {
-		dprintk(1, KERN_INFO "No known MJPEG cards found.\n");
-	}
-	return zoran_num;
-}
-
-static int __init
-init_dc10_cards (void)
+	}
+
+	if (zr36057_init(zr) < 0)
+		goto zr_detach_vfe;
+
+	zoran_proc_init(zr);
+
+	pci_set_drvdata(pdev, zr);
+
+	return 0;
+
+	// Init errors
+      zr_detach_vfe:
+	videocodec_detach(zr->vfe);
+      zr_free_vfe:
+	kfree(master_vfe);
+      zr_detach_codec:
+	videocodec_detach(zr->codec);
+      zr_free_codec:
+	kfree(master_codec);
+      zr_unreg_i2c:
+	zoran_unregister_i2c(zr);
+      zr_free_irq:
+	btwrite(0, ZR36057_SPGPPCR);
+	free_irq(zr->pci_dev->irq, zr);
+      zr_unmap:
+	iounmap(zr->zr36057_mem);
+      zr_free_mem:
+	kfree(zr);
+
+	return -ENODEV;
+}
+
+static struct pci_driver zoran_driver = {
+	.name = "zr36057",
+	.id_table = zr36067_pci_tbl,
+	.probe = zoran_probe,
+	.remove = zoran_remove,
+};
+
+static int __init zoran_init(void)
 {
 	int i;

@@ -1589,14 +1606,6 @@  init_dc10_cards (void)
 	printk(KERN_INFO "Zoran MJPEG board driver version %d.%d.%d\n",
 	       MAJOR_VERSION, MINOR_VERSION, RELEASE_VERSION);

-	/* Look for cards */
-	if (find_zr36057() < 0) {
-		return -EIO;
-	}
-	if (zoran_num == 0)
-		return -ENODEV;
-	dprintk(1, KERN_INFO "%s: %d card(s) found\n", ZORAN_NAME,
-		zoran_num);
 	/* check the parameters we have been given, adjust if necessary */
 	if (v4l_nbufs < 2)
 		v4l_nbufs = 2;
@@ -1638,37 +1647,29 @@  init_dc10_cards (void)
 			ZORAN_NAME);
 	}

-	/* take care of Natoma chipset and a revision 1 zr36057 */
-	for (i = 0; i < zoran_num; i++) {
-		struct zoran *zr = zoran[i];
-
-		if ((pci_pci_problems & PCIPCI_NATOMA) && zr->revision <= 1) {
-			zr->jpg_buffers.need_contiguous = 1;
-			dprintk(1,
-				KERN_INFO
-				"%s: ZR36057/Natoma bug, max. buffer size is 128K\n",
-				ZR_DEVNAME(zr));
-		}
-
-		if (zr36057_init(zr) < 0) {
-			for (i = 0; i < zoran_num; i++)
-				zoran_release(zoran[i]);
-			return -EIO;
-		}
-		zoran_proc_init(zr);
+	i = pci_register_driver(&zoran_driver);
+	if (i) {
+		pr_err("Unable to register ZR36057 driver\n");
+		return i;
 	}

 	return 0;
 }

-static void __exit
-unload_dc10_cards (void)
-{
-	int i;
-
-	for (i = 0; i < zoran_num; i++)
-		zoran_release(zoran[i]);
-}
-
-module_init(init_dc10_cards);
-module_exit(unload_dc10_cards);
+static void __exit zoran_exit(void)
+{
+	pci_unregister_driver(&zoran_driver);
+}
+
+module_init(zoran_init);
+module_exit(zoran_exit);
+
+/*
+todo:
+	use pci ioremap functions
+
+	use id table to provide card type
+
+	get rid of zoran[] array
+*/
+
diff -r 1bfe820d27c6 linux/drivers/media/video/zoran/zoran_card.h
--- a/linux/drivers/media/video/zoran/zoran_card.h	Thu Jan 08 18:13:53 2009 -0200
+++ b/linux/drivers/media/video/zoran/zoran_card.h	Thu Jan 08 19:21:17 2009 -0800
@@ -40,7 +40,7 @@  extern int zr36067_debug;

 /* Anybody who uses more than four? */
 #define BUZ_MAX 4
-extern int zoran_num;
+extern atomic_t zoran_num;
 extern struct zoran *zoran[BUZ_MAX];

 extern struct video_device zoran_template;
diff -r 1bfe820d27c6 linux/drivers/media/video/zoran/zoran_driver.c
--- a/linux/drivers/media/video/zoran/zoran_driver.c	Thu Jan 08 18:13:53 2009 -0200
+++ b/linux/drivers/media/video/zoran/zoran_driver.c	Thu Jan 08 19:21:47 2009 -0800
@@ -1271,7 +1271,7 @@  zoran_open(struct file  *file)

 	lock_kernel();
 	/* find the device */
-	for (i = 0; i < zoran_num; i++) {
+	for (i = 0; i < atomic_read(&zoran_num); i++) {
 		if (zoran[i]->video_dev->minor == minor) {
 			zr = zoran[i];
 			break;