162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Access to HP-HIL MLC through HP System Device Controller.
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Copyright (c) 2001 Brian S. Julin
562306a36Sopenharmony_ci * All rights reserved.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or without
862306a36Sopenharmony_ci * modification, are permitted provided that the following conditions
962306a36Sopenharmony_ci * are met:
1062306a36Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright
1162306a36Sopenharmony_ci *    notice, this list of conditions, and the following disclaimer,
1262306a36Sopenharmony_ci *    without modification.
1362306a36Sopenharmony_ci * 2. The name of the author may not be used to endorse or promote products
1462306a36Sopenharmony_ci *    derived from this software without specific prior written permission.
1562306a36Sopenharmony_ci *
1662306a36Sopenharmony_ci * Alternatively, this software may be distributed under the terms of the
1762306a36Sopenharmony_ci * GNU General Public License ("GPL").
1862306a36Sopenharmony_ci *
1962306a36Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2062306a36Sopenharmony_ci * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2162306a36Sopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2262306a36Sopenharmony_ci * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
2362306a36Sopenharmony_ci * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2462306a36Sopenharmony_ci * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2562306a36Sopenharmony_ci * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2662306a36Sopenharmony_ci * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2762306a36Sopenharmony_ci * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2862306a36Sopenharmony_ci *
2962306a36Sopenharmony_ci * References:
3062306a36Sopenharmony_ci * HP-HIL Technical Reference Manual.  Hewlett Packard Product No. 45918A
3162306a36Sopenharmony_ci * System Device Controller Microprocessor Firmware Theory of Operation
3262306a36Sopenharmony_ci *      for Part Number 1820-4784 Revision B.  Dwg No. A-1820-4784-2
3362306a36Sopenharmony_ci *
3462306a36Sopenharmony_ci */
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#include <linux/hil_mlc.h>
3762306a36Sopenharmony_ci#include <linux/hp_sdc.h>
3862306a36Sopenharmony_ci#include <linux/errno.h>
3962306a36Sopenharmony_ci#include <linux/kernel.h>
4062306a36Sopenharmony_ci#include <linux/module.h>
4162306a36Sopenharmony_ci#include <linux/init.h>
4262306a36Sopenharmony_ci#include <linux/string.h>
4362306a36Sopenharmony_ci#include <linux/semaphore.h>
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci#define PREFIX "HP SDC MLC: "
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_cistatic hil_mlc hp_sdc_mlc;
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ciMODULE_AUTHOR("Brian S. Julin <bri@calyx.com>");
5062306a36Sopenharmony_ciMODULE_DESCRIPTION("Glue for onboard HIL MLC in HP-PARISC machines");
5162306a36Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL");
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cistatic struct hp_sdc_mlc_priv_s {
5462306a36Sopenharmony_ci	int emtestmode;
5562306a36Sopenharmony_ci	hp_sdc_transaction trans;
5662306a36Sopenharmony_ci	u8 tseq[16];
5762306a36Sopenharmony_ci	int got5x;
5862306a36Sopenharmony_ci} hp_sdc_mlc_priv;
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci/************************* Interrupt context ******************************/
6162306a36Sopenharmony_cistatic void hp_sdc_mlc_isr (int irq, void *dev_id,
6262306a36Sopenharmony_ci			    uint8_t status, uint8_t data)
6362306a36Sopenharmony_ci{
6462306a36Sopenharmony_ci	int idx;
6562306a36Sopenharmony_ci	hil_mlc *mlc = &hp_sdc_mlc;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	write_lock(&mlc->lock);
6862306a36Sopenharmony_ci	if (mlc->icount < 0) {
6962306a36Sopenharmony_ci		printk(KERN_WARNING PREFIX "HIL Overflow!\n");
7062306a36Sopenharmony_ci		up(&mlc->isem);
7162306a36Sopenharmony_ci		goto out;
7262306a36Sopenharmony_ci	}
7362306a36Sopenharmony_ci	idx = 15 - mlc->icount;
7462306a36Sopenharmony_ci	if ((status & HP_SDC_STATUS_IRQMASK) == HP_SDC_STATUS_HILDATA) {
7562306a36Sopenharmony_ci		mlc->ipacket[idx] |= data | HIL_ERR_INT;
7662306a36Sopenharmony_ci		mlc->icount--;
7762306a36Sopenharmony_ci		if (hp_sdc_mlc_priv.got5x || !idx)
7862306a36Sopenharmony_ci			goto check;
7962306a36Sopenharmony_ci		if ((mlc->ipacket[idx - 1] & HIL_PKT_ADDR_MASK) !=
8062306a36Sopenharmony_ci		    (mlc->ipacket[idx] & HIL_PKT_ADDR_MASK)) {
8162306a36Sopenharmony_ci			mlc->ipacket[idx] &= ~HIL_PKT_ADDR_MASK;
8262306a36Sopenharmony_ci			mlc->ipacket[idx] |= (mlc->ipacket[idx - 1]
8362306a36Sopenharmony_ci						& HIL_PKT_ADDR_MASK);
8462306a36Sopenharmony_ci		}
8562306a36Sopenharmony_ci		goto check;
8662306a36Sopenharmony_ci	}
8762306a36Sopenharmony_ci	/* We know status is 5X */
8862306a36Sopenharmony_ci	if (data & HP_SDC_HIL_ISERR)
8962306a36Sopenharmony_ci		goto err;
9062306a36Sopenharmony_ci	mlc->ipacket[idx] =
9162306a36Sopenharmony_ci		(data & HP_SDC_HIL_R1MASK) << HIL_PKT_ADDR_SHIFT;
9262306a36Sopenharmony_ci	hp_sdc_mlc_priv.got5x = 1;
9362306a36Sopenharmony_ci	goto out;
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci check:
9662306a36Sopenharmony_ci	hp_sdc_mlc_priv.got5x = 0;
9762306a36Sopenharmony_ci	if (mlc->imatch == 0)
9862306a36Sopenharmony_ci		goto done;
9962306a36Sopenharmony_ci	if ((mlc->imatch == (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL))
10062306a36Sopenharmony_ci	    && (mlc->ipacket[idx] == (mlc->imatch | idx)))
10162306a36Sopenharmony_ci		goto done;
10262306a36Sopenharmony_ci	if (mlc->ipacket[idx] == mlc->imatch)
10362306a36Sopenharmony_ci		goto done;
10462306a36Sopenharmony_ci	goto out;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci err:
10762306a36Sopenharmony_ci	printk(KERN_DEBUG PREFIX "err code %x\n", data);
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	switch (data) {
11062306a36Sopenharmony_ci	case HP_SDC_HIL_RC_DONE:
11162306a36Sopenharmony_ci		printk(KERN_WARNING PREFIX "Bastard SDC reconfigured loop!\n");
11262306a36Sopenharmony_ci		break;
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	case HP_SDC_HIL_ERR:
11562306a36Sopenharmony_ci		mlc->ipacket[idx] |= HIL_ERR_INT | HIL_ERR_PERR |
11662306a36Sopenharmony_ci					HIL_ERR_FERR | HIL_ERR_FOF;
11762306a36Sopenharmony_ci		break;
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	case HP_SDC_HIL_TO:
12062306a36Sopenharmony_ci		mlc->ipacket[idx] |= HIL_ERR_INT | HIL_ERR_LERR;
12162306a36Sopenharmony_ci		break;
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	case HP_SDC_HIL_RC:
12462306a36Sopenharmony_ci		printk(KERN_WARNING PREFIX "Bastard SDC decided to reconfigure loop!\n");
12562306a36Sopenharmony_ci		break;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	default:
12862306a36Sopenharmony_ci		printk(KERN_WARNING PREFIX "Unknown HIL Error status (%x)!\n", data);
12962306a36Sopenharmony_ci		break;
13062306a36Sopenharmony_ci	}
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	/* No more data will be coming due to an error. */
13362306a36Sopenharmony_ci done:
13462306a36Sopenharmony_ci	tasklet_schedule(mlc->tasklet);
13562306a36Sopenharmony_ci	up(&mlc->isem);
13662306a36Sopenharmony_ci out:
13762306a36Sopenharmony_ci	write_unlock(&mlc->lock);
13862306a36Sopenharmony_ci}
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci/******************** Tasklet or userspace context functions ****************/
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_cistatic int hp_sdc_mlc_in(hil_mlc *mlc, suseconds_t timeout)
14462306a36Sopenharmony_ci{
14562306a36Sopenharmony_ci	struct hp_sdc_mlc_priv_s *priv;
14662306a36Sopenharmony_ci	int rc = 2;
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	priv = mlc->priv;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	/* Try to down the semaphore */
15162306a36Sopenharmony_ci	if (down_trylock(&mlc->isem)) {
15262306a36Sopenharmony_ci		if (priv->emtestmode) {
15362306a36Sopenharmony_ci			mlc->ipacket[0] =
15462306a36Sopenharmony_ci				HIL_ERR_INT | (mlc->opacket &
15562306a36Sopenharmony_ci					       (HIL_PKT_CMD |
15662306a36Sopenharmony_ci						HIL_PKT_ADDR_MASK |
15762306a36Sopenharmony_ci						HIL_PKT_DATA_MASK));
15862306a36Sopenharmony_ci			mlc->icount = 14;
15962306a36Sopenharmony_ci			/* printk(KERN_DEBUG PREFIX ">[%x]\n", mlc->ipacket[0]); */
16062306a36Sopenharmony_ci			goto wasup;
16162306a36Sopenharmony_ci		}
16262306a36Sopenharmony_ci		if (time_after(jiffies, mlc->instart + mlc->intimeout)) {
16362306a36Sopenharmony_ci			/*	printk("!%i %i",
16462306a36Sopenharmony_ci				tv.tv_usec - mlc->instart.tv_usec,
16562306a36Sopenharmony_ci				mlc->intimeout);
16662306a36Sopenharmony_ci			 */
16762306a36Sopenharmony_ci			rc = 1;
16862306a36Sopenharmony_ci			up(&mlc->isem);
16962306a36Sopenharmony_ci		}
17062306a36Sopenharmony_ci		goto done;
17162306a36Sopenharmony_ci	}
17262306a36Sopenharmony_ci wasup:
17362306a36Sopenharmony_ci	up(&mlc->isem);
17462306a36Sopenharmony_ci	rc = 0;
17562306a36Sopenharmony_ci done:
17662306a36Sopenharmony_ci	return rc;
17762306a36Sopenharmony_ci}
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_cistatic int hp_sdc_mlc_cts(hil_mlc *mlc)
18062306a36Sopenharmony_ci{
18162306a36Sopenharmony_ci	struct hp_sdc_mlc_priv_s *priv;
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	priv = mlc->priv;
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	/* Try to down the semaphores -- they should be up. */
18662306a36Sopenharmony_ci	BUG_ON(down_trylock(&mlc->isem));
18762306a36Sopenharmony_ci	BUG_ON(down_trylock(&mlc->osem));
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	up(&mlc->isem);
19062306a36Sopenharmony_ci	up(&mlc->osem);
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	if (down_trylock(&mlc->csem)) {
19362306a36Sopenharmony_ci		if (priv->trans.act.semaphore != &mlc->csem)
19462306a36Sopenharmony_ci			goto poll;
19562306a36Sopenharmony_ci		else
19662306a36Sopenharmony_ci			goto busy;
19762306a36Sopenharmony_ci	}
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	if (!(priv->tseq[4] & HP_SDC_USE_LOOP))
20062306a36Sopenharmony_ci		goto done;
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci poll:
20362306a36Sopenharmony_ci	priv->trans.act.semaphore = &mlc->csem;
20462306a36Sopenharmony_ci	priv->trans.actidx = 0;
20562306a36Sopenharmony_ci	priv->trans.idx = 1;
20662306a36Sopenharmony_ci	priv->trans.endidx = 5;
20762306a36Sopenharmony_ci	priv->tseq[0] =
20862306a36Sopenharmony_ci		HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN | HP_SDC_ACT_SEMAPHORE;
20962306a36Sopenharmony_ci	priv->tseq[1] = HP_SDC_CMD_READ_USE;
21062306a36Sopenharmony_ci	priv->tseq[2] = 1;
21162306a36Sopenharmony_ci	priv->tseq[3] = 0;
21262306a36Sopenharmony_ci	priv->tseq[4] = 0;
21362306a36Sopenharmony_ci	return __hp_sdc_enqueue_transaction(&priv->trans);
21462306a36Sopenharmony_ci busy:
21562306a36Sopenharmony_ci	return 1;
21662306a36Sopenharmony_ci done:
21762306a36Sopenharmony_ci	priv->trans.act.semaphore = &mlc->osem;
21862306a36Sopenharmony_ci	up(&mlc->csem);
21962306a36Sopenharmony_ci	return 0;
22062306a36Sopenharmony_ci}
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_cistatic int hp_sdc_mlc_out(hil_mlc *mlc)
22362306a36Sopenharmony_ci{
22462306a36Sopenharmony_ci	struct hp_sdc_mlc_priv_s *priv;
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	priv = mlc->priv;
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	/* Try to down the semaphore -- it should be up. */
22962306a36Sopenharmony_ci	BUG_ON(down_trylock(&mlc->osem));
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	if (mlc->opacket & HIL_DO_ALTER_CTRL)
23262306a36Sopenharmony_ci		goto do_control;
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci do_data:
23562306a36Sopenharmony_ci	if (priv->emtestmode) {
23662306a36Sopenharmony_ci		up(&mlc->osem);
23762306a36Sopenharmony_ci		return 0;
23862306a36Sopenharmony_ci	}
23962306a36Sopenharmony_ci	/* Shouldn't be sending commands when loop may be busy */
24062306a36Sopenharmony_ci	BUG_ON(down_trylock(&mlc->csem));
24162306a36Sopenharmony_ci	up(&mlc->csem);
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	priv->trans.actidx = 0;
24462306a36Sopenharmony_ci	priv->trans.idx = 1;
24562306a36Sopenharmony_ci	priv->trans.act.semaphore = &mlc->osem;
24662306a36Sopenharmony_ci	priv->trans.endidx = 6;
24762306a36Sopenharmony_ci	priv->tseq[0] =
24862306a36Sopenharmony_ci		HP_SDC_ACT_DATAREG | HP_SDC_ACT_POSTCMD | HP_SDC_ACT_SEMAPHORE;
24962306a36Sopenharmony_ci	priv->tseq[1] = 0x7;
25062306a36Sopenharmony_ci	priv->tseq[2] =
25162306a36Sopenharmony_ci		(mlc->opacket &
25262306a36Sopenharmony_ci		 (HIL_PKT_ADDR_MASK | HIL_PKT_CMD))
25362306a36Sopenharmony_ci		   >> HIL_PKT_ADDR_SHIFT;
25462306a36Sopenharmony_ci	priv->tseq[3] =
25562306a36Sopenharmony_ci		(mlc->opacket & HIL_PKT_DATA_MASK)
25662306a36Sopenharmony_ci		  >> HIL_PKT_DATA_SHIFT;
25762306a36Sopenharmony_ci	priv->tseq[4] = 0;  /* No timeout */
25862306a36Sopenharmony_ci	if (priv->tseq[3] == HIL_CMD_DHR)
25962306a36Sopenharmony_ci		priv->tseq[4] = 1;
26062306a36Sopenharmony_ci	priv->tseq[5] = HP_SDC_CMD_DO_HIL;
26162306a36Sopenharmony_ci	goto enqueue;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci do_control:
26462306a36Sopenharmony_ci	priv->emtestmode = mlc->opacket & HIL_CTRL_TEST;
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	/* we cannot emulate this, it should not be used. */
26762306a36Sopenharmony_ci	BUG_ON((mlc->opacket & (HIL_CTRL_APE | HIL_CTRL_IPF)) == HIL_CTRL_APE);
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	if ((mlc->opacket & HIL_CTRL_ONLY) == HIL_CTRL_ONLY)
27062306a36Sopenharmony_ci		goto control_only;
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	/* Should not send command/data after engaging APE */
27362306a36Sopenharmony_ci	BUG_ON(mlc->opacket & HIL_CTRL_APE);
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	/* Disengaging APE this way would not be valid either since
27662306a36Sopenharmony_ci	 * the loop must be allowed to idle.
27762306a36Sopenharmony_ci	 *
27862306a36Sopenharmony_ci	 * So, it works out that we really never actually send control
27962306a36Sopenharmony_ci	 * and data when using SDC, we just send the data.
28062306a36Sopenharmony_ci	 */
28162306a36Sopenharmony_ci	goto do_data;
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci control_only:
28462306a36Sopenharmony_ci	priv->trans.actidx = 0;
28562306a36Sopenharmony_ci	priv->trans.idx = 1;
28662306a36Sopenharmony_ci	priv->trans.act.semaphore = &mlc->osem;
28762306a36Sopenharmony_ci	priv->trans.endidx = 4;
28862306a36Sopenharmony_ci	priv->tseq[0] =
28962306a36Sopenharmony_ci	  HP_SDC_ACT_PRECMD | HP_SDC_ACT_DATAOUT | HP_SDC_ACT_SEMAPHORE;
29062306a36Sopenharmony_ci	priv->tseq[1] = HP_SDC_CMD_SET_LPC;
29162306a36Sopenharmony_ci	priv->tseq[2] = 1;
29262306a36Sopenharmony_ci	/* priv->tseq[3] = (mlc->ddc + 1) | HP_SDC_LPS_ACSUCC; */
29362306a36Sopenharmony_ci	priv->tseq[3] = 0;
29462306a36Sopenharmony_ci	if (mlc->opacket & HIL_CTRL_APE) {
29562306a36Sopenharmony_ci		priv->tseq[3] |= HP_SDC_LPC_APE_IPF;
29662306a36Sopenharmony_ci		BUG_ON(down_trylock(&mlc->csem));
29762306a36Sopenharmony_ci	}
29862306a36Sopenharmony_ci enqueue:
29962306a36Sopenharmony_ci	return hp_sdc_enqueue_transaction(&priv->trans);
30062306a36Sopenharmony_ci}
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_cistatic int __init hp_sdc_mlc_init(void)
30362306a36Sopenharmony_ci{
30462306a36Sopenharmony_ci	hil_mlc *mlc = &hp_sdc_mlc;
30562306a36Sopenharmony_ci	int err;
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci#ifdef __mc68000__
30862306a36Sopenharmony_ci	if (!MACH_IS_HP300)
30962306a36Sopenharmony_ci		return -ENODEV;
31062306a36Sopenharmony_ci#endif
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	printk(KERN_INFO PREFIX "Registering the System Domain Controller's HIL MLC.\n");
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	hp_sdc_mlc_priv.emtestmode = 0;
31562306a36Sopenharmony_ci	hp_sdc_mlc_priv.trans.seq = hp_sdc_mlc_priv.tseq;
31662306a36Sopenharmony_ci	hp_sdc_mlc_priv.trans.act.semaphore = &mlc->osem;
31762306a36Sopenharmony_ci	hp_sdc_mlc_priv.got5x = 0;
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	mlc->cts = &hp_sdc_mlc_cts;
32062306a36Sopenharmony_ci	mlc->in	= &hp_sdc_mlc_in;
32162306a36Sopenharmony_ci	mlc->out = &hp_sdc_mlc_out;
32262306a36Sopenharmony_ci	mlc->priv = &hp_sdc_mlc_priv;
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	err = hil_mlc_register(mlc);
32562306a36Sopenharmony_ci	if (err) {
32662306a36Sopenharmony_ci		printk(KERN_WARNING PREFIX "Failed to register MLC structure with hil_mlc\n");
32762306a36Sopenharmony_ci		return err;
32862306a36Sopenharmony_ci	}
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	if (hp_sdc_request_hil_irq(&hp_sdc_mlc_isr)) {
33162306a36Sopenharmony_ci		printk(KERN_WARNING PREFIX "Request for raw HIL ISR hook denied\n");
33262306a36Sopenharmony_ci		if (hil_mlc_unregister(mlc))
33362306a36Sopenharmony_ci			printk(KERN_ERR PREFIX "Failed to unregister MLC structure with hil_mlc.\n"
33462306a36Sopenharmony_ci				"This is bad.  Could cause an oops.\n");
33562306a36Sopenharmony_ci		return -EBUSY;
33662306a36Sopenharmony_ci	}
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	return 0;
33962306a36Sopenharmony_ci}
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_cistatic void __exit hp_sdc_mlc_exit(void)
34262306a36Sopenharmony_ci{
34362306a36Sopenharmony_ci	hil_mlc *mlc = &hp_sdc_mlc;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	if (hp_sdc_release_hil_irq(&hp_sdc_mlc_isr))
34662306a36Sopenharmony_ci		printk(KERN_ERR PREFIX "Failed to release the raw HIL ISR hook.\n"
34762306a36Sopenharmony_ci			"This is bad.  Could cause an oops.\n");
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	if (hil_mlc_unregister(mlc))
35062306a36Sopenharmony_ci		printk(KERN_ERR PREFIX "Failed to unregister MLC structure with hil_mlc.\n"
35162306a36Sopenharmony_ci			"This is bad.  Could cause an oops.\n");
35262306a36Sopenharmony_ci}
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_cimodule_init(hp_sdc_mlc_init);
35562306a36Sopenharmony_cimodule_exit(hp_sdc_mlc_exit);
356