summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/base/firmware_class.c79
-rw-r--r--drivers/block/aoe/aoedev.c2
-rw-r--r--drivers/block/cfq-iosched.c3
-rw-r--r--drivers/block/deadline-iosched.c12
-rw-r--r--drivers/block/genhd.c2
-rw-r--r--drivers/block/ll_rw_blk.c4
-rw-r--r--drivers/char/Kconfig2
-rw-r--r--drivers/char/digi1.h38
-rw-r--r--drivers/char/digiFep1.h154
-rw-r--r--drivers/char/epca.c1588
-rw-r--r--drivers/char/epca.h108
-rw-r--r--drivers/char/hpet.c4
-rw-r--r--drivers/char/ipmi/ipmi_bt_sm.c69
-rw-r--r--drivers/char/ipmi/ipmi_devintf.c101
-rw-r--r--drivers/char/ipmi/ipmi_kcs_sm.c3
-rw-r--r--drivers/char/ipmi/ipmi_msghandler.c336
-rw-r--r--drivers/char/ipmi/ipmi_poweroff.c168
-rw-r--r--drivers/char/ipmi/ipmi_si_intf.c395
-rw-r--r--drivers/char/ipmi/ipmi_smic_sm.c3
-rw-r--r--drivers/char/ipmi/ipmi_watchdog.c46
-rw-r--r--drivers/char/mbcs.c2
-rw-r--r--drivers/char/mem.c4
-rw-r--r--drivers/char/misc.c9
-rw-r--r--drivers/char/sonypi.c118
-rw-r--r--drivers/char/tpm/tpm_atmel.c3
-rw-r--r--drivers/char/tty_io.c6
-rw-r--r--drivers/char/vt.c21
-rw-r--r--drivers/firmware/Kconfig27
-rw-r--r--drivers/firmware/Makefile2
-rw-r--r--drivers/firmware/dcdbas.c596
-rw-r--r--drivers/firmware/dcdbas.h107
-rw-r--r--drivers/firmware/dell_rbu.c634
-rw-r--r--drivers/i2c/chips/isp1301_omap.c2
-rw-r--r--drivers/ieee1394/nodemgr.c8
-rw-r--r--drivers/infiniband/core/sysfs.c2
-rw-r--r--drivers/input/evdev.c8
-rw-r--r--drivers/input/gameport/emu10k1-gp.c2
-rw-r--r--drivers/input/gameport/fm801-gp.c2
-rw-r--r--drivers/input/gameport/ns558.c4
-rw-r--r--drivers/input/input.c11
-rw-r--r--drivers/input/joystick/a3d.c2
-rw-r--r--drivers/input/joystick/adi.c2
-rw-r--r--drivers/input/joystick/analog.c2
-rw-r--r--drivers/input/joystick/cobra.c2
-rw-r--r--drivers/input/joystick/db9.c2
-rw-r--r--drivers/input/joystick/gamecon.c2
-rw-r--r--drivers/input/joystick/gf2k.c2
-rw-r--r--drivers/input/joystick/grip.c2
-rw-r--r--drivers/input/joystick/grip_mp.c2
-rw-r--r--drivers/input/joystick/guillemot.c2
-rw-r--r--drivers/input/joystick/interact.c2
-rw-r--r--drivers/input/joystick/sidewinder.c2
-rw-r--r--drivers/input/joystick/tmdc.c2
-rw-r--r--drivers/input/joystick/turbografx.c2
-rw-r--r--drivers/input/keyboard/corgikbd.c104
-rw-r--r--drivers/input/mouse/psmouse-base.c2
-rw-r--r--drivers/input/serio/serport.c4
-rw-r--r--drivers/input/touchscreen/corgi_ts.c51
-rw-r--r--drivers/isdn/hisax/hisax.h1
-rw-r--r--drivers/isdn/i4l/isdn_v110.c4
-rw-r--r--drivers/md/dm-io.c6
-rw-r--r--drivers/md/dm.c6
-rw-r--r--drivers/media/dvb/bt8xx/Kconfig6
-rw-r--r--drivers/media/dvb/frontends/lgdt330x.c50
-rw-r--r--drivers/media/video/Makefile2
-rw-r--r--drivers/media/video/adv7170.c1
-rw-r--r--drivers/media/video/adv7175.c1
-rw-r--r--drivers/media/video/bt819.c1
-rw-r--r--drivers/media/video/bt856.c1
-rw-r--r--drivers/media/video/indycam.c412
-rw-r--r--drivers/media/video/indycam.h112
-rw-r--r--drivers/media/video/meye.c3
-rw-r--r--drivers/media/video/saa7111.c1
-rw-r--r--drivers/media/video/saa7114.c1
-rw-r--r--drivers/media/video/saa7185.c1
-rw-r--r--drivers/media/video/saa7191.c512
-rw-r--r--drivers/media/video/saa7191.h139
-rw-r--r--drivers/media/video/vino.c4273
-rw-r--r--drivers/media/video/vino.h61
-rw-r--r--drivers/mmc/mmc.c518
-rw-r--r--drivers/mmc/mmc_block.c9
-rw-r--r--drivers/mmc/mmc_sysfs.c21
-rw-r--r--drivers/mmc/pxamci.c11
-rw-r--r--drivers/mmc/wbsd.c60
-rw-r--r--drivers/mmc/wbsd.h3
-rw-r--r--drivers/mtd/nand/nand_base.c1
-rw-r--r--drivers/net/3c59x.c19
-rw-r--r--drivers/net/irda/smsc-ircc2.c1179
-rw-r--r--drivers/net/irda/smsc-ircc2.h50
-rw-r--r--drivers/parport/parport_pc.c3
-rw-r--r--drivers/pci/msi.c17
-rw-r--r--drivers/pci/msi.h5
-rw-r--r--drivers/pcmcia/topic.h17
-rw-r--r--drivers/pcmcia/yenta_socket.c125
-rw-r--r--drivers/pcmcia/yenta_socket.h8
-rw-r--r--drivers/pnp/card.c7
-rw-r--r--drivers/pnp/driver.c7
-rw-r--r--drivers/pnp/isapnp/core.c33
-rw-r--r--drivers/pnp/manager.c7
-rw-r--r--drivers/pnp/pnpacpi/core.c16
-rw-r--r--drivers/pnp/pnpacpi/pnpacpi.h1
-rw-r--r--drivers/pnp/pnpacpi/rsparser.c18
-rw-r--r--drivers/pnp/pnpbios/core.c26
-rw-r--r--drivers/pnp/pnpbios/pnpbios.h1
-rw-r--r--drivers/pnp/pnpbios/proc.c8
-rw-r--r--drivers/pnp/pnpbios/rsparser.c16
-rw-r--r--drivers/pnp/quirks.c7
-rw-r--r--drivers/pnp/support.c7
-rw-r--r--drivers/scsi/sata_qstor.c2
-rw-r--r--drivers/serial/68328serial.c1
-rw-r--r--drivers/serial/68360serial.c8
-rw-r--r--drivers/serial/crisv10.c1
-rw-r--r--drivers/serial/icom.c1
-rw-r--r--drivers/serial/mcfserial.c1
-rw-r--r--drivers/usb/atm/usbatm.c2
-rw-r--r--drivers/usb/core/hcd.c2
-rw-r--r--drivers/usb/host/ehci-sched.c2
-rw-r--r--drivers/usb/host/isp116x-hcd.c2
-rw-r--r--drivers/usb/host/sl811-hcd.c2
-rw-r--r--drivers/usb/input/acecad.c2
-rw-r--r--drivers/usb/input/itmtouch.c2
-rw-r--r--drivers/usb/input/pid.c2
-rw-r--r--drivers/video/backlight/Makefile1
-rw-r--r--drivers/video/backlight/locomolcd.c157
-rw-r--r--drivers/video/q40fb.c1
-rw-r--r--drivers/video/w100fb.c1912
-rw-r--r--drivers/video/w100fb.h777
127 files changed, 11015 insertions, 4531 deletions
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 652281402c92..5bfa2e9a7c26 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -28,6 +28,7 @@ enum {
FW_STATUS_DONE,
FW_STATUS_ABORT,
FW_STATUS_READY,
+ FW_STATUS_READY_NOHOTPLUG,
};
static int loading_timeout = 10; /* In seconds */
@@ -344,7 +345,7 @@ error_kfree:
static int
fw_setup_class_device(struct firmware *fw, struct class_device **class_dev_p,
- const char *fw_name, struct device *device)
+ const char *fw_name, struct device *device, int hotplug)
{
struct class_device *class_dev;
struct firmware_priv *fw_priv;
@@ -376,7 +377,10 @@ fw_setup_class_device(struct firmware *fw, struct class_device **class_dev_p,
goto error_unreg;
}
- set_bit(FW_STATUS_READY, &fw_priv->status);
+ if (hotplug)
+ set_bit(FW_STATUS_READY, &fw_priv->status);
+ else
+ set_bit(FW_STATUS_READY_NOHOTPLUG, &fw_priv->status);
*class_dev_p = class_dev;
goto out;
@@ -386,21 +390,9 @@ out:
return retval;
}
-/**
- * request_firmware: - request firmware to hotplug and wait for it
- * Description:
- * @firmware will be used to return a firmware image by the name
- * of @name for device @device.
- *
- * Should be called from user context where sleeping is allowed.
- *
- * @name will be use as $FIRMWARE in the hotplug environment and
- * should be distinctive enough not to be confused with any other
- * firmware image for this or any other device.
- **/
-int
-request_firmware(const struct firmware **firmware_p, const char *name,
- struct device *device)
+static int
+_request_firmware(const struct firmware **firmware_p, const char *name,
+ struct device *device, int hotplug)
{
struct class_device *class_dev;
struct firmware_priv *fw_priv;
@@ -419,22 +411,25 @@ request_firmware(const struct firmware **firmware_p, const char *name,
}
memset(firmware, 0, sizeof (*firmware));
- retval = fw_setup_class_device(firmware, &class_dev, name, device);
+ retval = fw_setup_class_device(firmware, &class_dev, name, device,
+ hotplug);
if (retval)
goto error_kfree_fw;
fw_priv = class_get_devdata(class_dev);
- if (loading_timeout > 0) {
- fw_priv->timeout.expires = jiffies + loading_timeout * HZ;
- add_timer(&fw_priv->timeout);
- }
-
- kobject_hotplug(&class_dev->kobj, KOBJ_ADD);
- wait_for_completion(&fw_priv->completion);
- set_bit(FW_STATUS_DONE, &fw_priv->status);
+ if (hotplug) {
+ if (loading_timeout > 0) {
+ fw_priv->timeout.expires = jiffies + loading_timeout * HZ;
+ add_timer(&fw_priv->timeout);
+ }
- del_timer_sync(&fw_priv->timeout);
+ kobject_hotplug(&class_dev->kobj, KOBJ_ADD);
+ wait_for_completion(&fw_priv->completion);
+ set_bit(FW_STATUS_DONE, &fw_priv->status);
+ del_timer_sync(&fw_priv->timeout);
+ } else
+ wait_for_completion(&fw_priv->completion);
down(&fw_lock);
if (!fw_priv->fw->size || test_bit(FW_STATUS_ABORT, &fw_priv->status)) {
@@ -455,6 +450,26 @@ out:
}
/**
+ * request_firmware: - request firmware to hotplug and wait for it
+ * Description:
+ * @firmware will be used to return a firmware image by the name
+ * of @name for device @device.
+ *
+ * Should be called from user context where sleeping is allowed.
+ *
+ * @name will be use as $FIRMWARE in the hotplug environment and
+ * should be distinctive enough not to be confused with any other
+ * firmware image for this or any other device.
+ **/
+int
+request_firmware(const struct firmware **firmware_p, const char *name,
+ struct device *device)
+{
+ int hotplug = 1;
+ return _request_firmware(firmware_p, name, device, hotplug);
+}
+
+/**
* release_firmware: - release the resource associated with a firmware image
**/
void
@@ -491,6 +506,7 @@ struct firmware_work {
struct device *device;
void *context;
void (*cont)(const struct firmware *fw, void *context);
+ int hotplug;
};
static int
@@ -503,7 +519,8 @@ request_firmware_work_func(void *arg)
return 0;
}
daemonize("%s/%s", "firmware", fw_work->name);
- request_firmware(&fw, fw_work->name, fw_work->device);
+ _request_firmware(&fw, fw_work->name, fw_work->device,
+ fw_work->hotplug);
fw_work->cont(fw, fw_work->context);
release_firmware(fw);
module_put(fw_work->module);
@@ -518,6 +535,9 @@ request_firmware_work_func(void *arg)
* Asynchronous variant of request_firmware() for contexts where
* it is not possible to sleep.
*
+ * @hotplug invokes hotplug event to copy the firmware image if this flag
+ * is non-zero else the firmware copy must be done manually.
+ *
* @cont will be called asynchronously when the firmware request is over.
*
* @context will be passed over to @cont.
@@ -527,7 +547,7 @@ request_firmware_work_func(void *arg)
**/
int
request_firmware_nowait(
- struct module *module,
+ struct module *module, int hotplug,
const char *name, struct device *device, void *context,
void (*cont)(const struct firmware *fw, void *context))
{
@@ -548,6 +568,7 @@ request_firmware_nowait(
.device = device,
.context = context,
.cont = cont,
+ .hotplug = hotplug,
};
ret = kernel_thread(request_firmware_work_func, fw_work,
diff --git a/drivers/block/aoe/aoedev.c b/drivers/block/aoe/aoedev.c
index 6e231c5a1199..ded33ba31acc 100644
--- a/drivers/block/aoe/aoedev.c
+++ b/drivers/block/aoe/aoedev.c
@@ -35,7 +35,7 @@ aoedev_newdev(ulong nframes)
struct aoedev *d;
struct frame *f, *e;
- d = kcalloc(1, sizeof *d, GFP_ATOMIC);
+ d = kzalloc(sizeof *d, GFP_ATOMIC);
if (d == NULL)
return NULL;
f = kcalloc(nframes, sizeof *f, GFP_ATOMIC);
diff --git a/drivers/block/cfq-iosched.c b/drivers/block/cfq-iosched.c
index cd056e7e64ec..30c0903c7cdd 100644
--- a/drivers/block/cfq-iosched.c
+++ b/drivers/block/cfq-iosched.c
@@ -2260,8 +2260,6 @@ static void cfq_put_cfqd(struct cfq_data *cfqd)
if (!atomic_dec_and_test(&cfqd->ref))
return;
- blk_put_queue(q);
-
cfq_shutdown_timer_wq(cfqd);
q->elevator->elevator_data = NULL;
@@ -2318,7 +2316,6 @@ static int cfq_init_queue(request_queue_t *q, elevator_t *e)
e->elevator_data = cfqd;
cfqd->queue = q;
- atomic_inc(&q->refcnt);
cfqd->max_queued = q->nr_requests / 4;
q->nr_batching = cfq_queued;
diff --git a/drivers/block/deadline-iosched.c b/drivers/block/deadline-iosched.c
index ff5201e02153..24594c57c323 100644
--- a/drivers/block/deadline-iosched.c
+++ b/drivers/block/deadline-iosched.c
@@ -507,18 +507,12 @@ static int deadline_dispatch_requests(struct deadline_data *dd)
const int reads = !list_empty(&dd->fifo_list[READ]);
const int writes = !list_empty(&dd->fifo_list[WRITE]);
struct deadline_rq *drq;
- int data_dir, other_dir;
+ int data_dir;
/*
* batches are currently reads XOR writes
*/
- drq = NULL;
-
- if (dd->next_drq[READ])
- drq = dd->next_drq[READ];
-
- if (dd->next_drq[WRITE])
- drq = dd->next_drq[WRITE];
+ drq = dd->next_drq[WRITE] ? : dd->next_drq[READ];
if (drq) {
/* we have a "next request" */
@@ -544,7 +538,6 @@ static int deadline_dispatch_requests(struct deadline_data *dd)
goto dispatch_writes;
data_dir = READ;
- other_dir = WRITE;
goto dispatch_find_request;
}
@@ -560,7 +553,6 @@ dispatch_writes:
dd->starved = 0;
data_dir = WRITE;
- other_dir = READ;
goto dispatch_find_request;
}
diff --git a/drivers/block/genhd.c b/drivers/block/genhd.c
index 47fd3659a061..d42840cc0d1d 100644
--- a/drivers/block/genhd.c
+++ b/drivers/block/genhd.c
@@ -45,7 +45,7 @@ int get_blkdev_list(char *p, int used)
struct blk_major_name *n;
int i, len;
- len = sprintf(p, "\nBlock devices:\n");
+ len = snprintf(p, (PAGE_SIZE-used), "\nBlock devices:\n");
down(&block_subsys_sem);
for (i = 0; i < ARRAY_SIZE(major_names); i++) {
diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c
index 3c818544475e..b4b17958d101 100644
--- a/drivers/block/ll_rw_blk.c
+++ b/drivers/block/ll_rw_blk.c
@@ -235,8 +235,8 @@ void blk_queue_make_request(request_queue_t * q, make_request_fn * mfn)
* set defaults
*/
q->nr_requests = BLKDEV_MAX_RQ;
- q->max_phys_segments = MAX_PHYS_SEGMENTS;
- q->max_hw_segments = MAX_HW_SEGMENTS;
+ blk_queue_max_phys_segments(q, MAX_PHYS_SEGMENTS);
+ blk_queue_max_hw_segments(q, MAX_HW_SEGMENTS);
q->make_request_fn = mfn;
q->backing_dev_info.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE;
q->backing_dev_info.state = 0;
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index a1de06d76de6..2bc9d64db106 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -138,7 +138,7 @@ config CYZ_INTR
config DIGIEPCA
tristate "Digiboard Intelligent Async Support"
- depends on SERIAL_NONSTANDARD && BROKEN_ON_SMP && (!64BIT || BROKEN)
+ depends on SERIAL_NONSTANDARD
---help---
This is a driver for Digi International's Xx, Xeve, and Xem series
of cards which provide multiple serial ports. You would need
diff --git a/drivers/char/digi1.h b/drivers/char/digi1.h
index 184378d23f8c..94d4eab5d3ca 100644
--- a/drivers/char/digi1.h
+++ b/drivers/char/digi1.h
@@ -1,46 +1,46 @@
/* Definitions for DigiBoard ditty(1) command. */
#if !defined(TIOCMODG)
-#define TIOCMODG ('d'<<8) | 250 /* get modem ctrl state */
-#define TIOCMODS ('d'<<8) | 251 /* set modem ctrl state */
+#define TIOCMODG (('d'<<8) | 250) /* get modem ctrl state */
+#define TIOCMODS (('d'<<8) | 251) /* set modem ctrl state */
#endif
#if !defined(TIOCMSET)
-#define TIOCMSET ('d'<<8) | 252 /* set modem ctrl state */
-#define TIOCMGET ('d'<<8) | 253 /* set modem ctrl state */
+#define TIOCMSET (('d'<<8) | 252) /* set modem ctrl state */
+#define TIOCMGET (('d'<<8) | 253) /* set modem ctrl state */
#endif
#if !defined(TIOCMBIC)
-#define TIOCMBIC ('d'<<8) | 254 /* set modem ctrl state */
-#define TIOCMBIS ('d'<<8) | 255 /* set modem ctrl state */
+#define TIOCMBIC (('d'<<8) | 254) /* set modem ctrl state */
+#define TIOCMBIS (('d'<<8) | 255) /* set modem ctrl state */
#endif
#if !defined(TIOCSDTR)
-#define TIOCSDTR ('e'<<8) | 0 /* set DTR */
-#define TIOCCDTR ('e'<<8) | 1 /* clear DTR */
+#define TIOCSDTR (('e'<<8) | 0) /* set DTR */
+#define TIOCCDTR (('e'<<8) | 1) /* clear DTR */
#endif
/************************************************************************
* Ioctl command arguments for DIGI parameters.
************************************************************************/
-#define DIGI_GETA ('e'<<8) | 94 /* Read params */
+#define DIGI_GETA (('e'<<8) | 94) /* Read params */
-#define DIGI_SETA ('e'<<8) | 95 /* Set params */
-#define DIGI_SETAW ('e'<<8) | 96 /* Drain & set params */
-#define DIGI_SETAF ('e'<<8) | 97 /* Drain, flush & set params */
+#define DIGI_SETA (('e'<<8) | 95) /* Set params */
+#define DIGI_SETAW (('e'<<8) | 96) /* Drain & set params */
+#define DIGI_SETAF (('e'<<8) | 97) /* Drain, flush & set params */
-#define DIGI_GETFLOW ('e'<<8) | 99 /* Get startc/stopc flow */
+#define DIGI_GETFLOW (('e'<<8) | 99) /* Get startc/stopc flow */
/* control characters */
-#define DIGI_SETFLOW ('e'<<8) | 100 /* Set startc/stopc flow */
+#define DIGI_SETFLOW (('e'<<8) | 100) /* Set startc/stopc flow */
/* control characters */
-#define DIGI_GETAFLOW ('e'<<8) | 101 /* Get Aux. startc/stopc */
+#define DIGI_GETAFLOW (('e'<<8) | 101) /* Get Aux. startc/stopc */
/* flow control chars */
-#define DIGI_SETAFLOW ('e'<<8) | 102 /* Set Aux. startc/stopc */
+#define DIGI_SETAFLOW (('e'<<8) | 102) /* Set Aux. startc/stopc */
/* flow control chars */
-#define DIGI_GETINFO ('e'<<8) | 103 /* Fill in digi_info */
-#define DIGI_POLLER ('e'<<8) | 104 /* Turn on/off poller */
-#define DIGI_INIT ('e'<<8) | 105 /* Allow things to run. */
+#define DIGI_GETINFO (('e'<<8) | 103) /* Fill in digi_info */
+#define DIGI_POLLER (('e'<<8) | 104) /* Turn on/off poller */
+#define DIGI_INIT (('e'<<8) | 105) /* Allow things to run. */
struct digiflow_struct
{
diff --git a/drivers/char/digiFep1.h b/drivers/char/digiFep1.h
index c47d7fcb8400..3c1f1922c798 100644
--- a/drivers/char/digiFep1.h
+++ b/drivers/char/digiFep1.h
@@ -13,88 +13,88 @@
struct global_data
{
- volatile ushort cin;
- volatile ushort cout;
- volatile ushort cstart;
- volatile ushort cmax;
- volatile ushort ein;
- volatile ushort eout;
- volatile ushort istart;
- volatile ushort imax;
+ u16 cin;
+ u16 cout;
+ u16 cstart;
+ u16 cmax;
+ u16 ein;
+ u16 eout;
+ u16 istart;
+ u16 imax;
};
struct board_chan
{
- int filler1;
- int filler2;
- volatile ushort tseg;
- volatile ushort tin;
- volatile ushort tout;
- volatile ushort tmax;
-
- volatile ushort rseg;
- volatile ushort rin;
- volatile ushort rout;
- volatile ushort rmax;
-
- volatile ushort tlow;
- volatile ushort rlow;
- volatile ushort rhigh;
- volatile ushort incr;
-
- volatile ushort etime;
- volatile ushort edelay;
- volatile unchar *dev;
-
- volatile ushort iflag;
- volatile ushort oflag;
- volatile ushort cflag;
- volatile ushort gmask;
-
- volatile ushort col;
- volatile ushort delay;
- volatile ushort imask;
- volatile ushort tflush;
-
- int filler3;
- int filler4;
- int filler5;
- int filler6;
-
- volatile unchar num;
- volatile unchar ract;
- volatile unchar bstat;
- volatile unchar tbusy;
- volatile unchar iempty;
- volatile unchar ilow;
- volatile unchar idata;
- volatile unchar eflag;
-
- volatile unchar tflag;
- volatile unchar rflag;
- volatile unchar xmask;
- volatile unchar xval;
- volatile unchar mstat;
- volatile unchar mchange;
- volatile unchar mint;
- volatile unchar lstat;
-
- volatile unchar mtran;
- volatile unchar orun;
- volatile unchar startca;
- volatile unchar stopca;
- volatile unchar startc;
- volatile unchar stopc;
- volatile unchar vnext;
- volatile unchar hflow;
-
- volatile unchar fillc;
- volatile unchar ochar;
- volatile unchar omask;
-
- unchar filler7;
- unchar filler8[28];
+ u32 filler1;
+ u32 filler2;
+ u16 tseg;
+ u16 tin;
+ u16 tout;
+ u16 tmax;
+
+ u16 rseg;
+ u16 rin;
+ u16 rout;
+ u16 rmax;
+
+ u16 tlow;
+ u16 rlow;
+ u16 rhigh;
+ u16 incr;
+
+ u16 etime;
+ u16 edelay;
+ unchar *dev;
+
+ u16 iflag;
+ u16 oflag;
+ u16 cflag;
+ u16 gmask;
+
+ u16 col;
+ u16 delay;
+ u16 imask;
+ u16 tflush;
+
+ u32 filler3;
+ u32 filler4;
+ u32 filler5;
+ u32 filler6;
+
+ u8 num;
+ u8 ract;
+ u8 bstat;
+ u8 tbusy;
+ u8 iempty;
+ u8 ilow;
+ u8 idata;
+ u8 eflag;
+
+ u8 tflag;
+ u8 rflag;
+ u8 xmask;
+ u8 xval;
+ u8 mstat;
+ u8 mchange;
+ u8 mint;
+ u8 lstat;
+
+ u8 mtran;
+ u8 orun;
+ u8 startca;
+ u8 stopca;
+ u8 startc;
+ u8 stopc;
+ u8 vnext;
+ u8 hflow;
+
+ u8 fillc;
+ u8 ochar;
+ u8 omask;
+
+ u8 filler7;
+ u8 filler8[28];
};
diff --git a/drivers/char/epca.c b/drivers/char/epca.c
index 6025e1866c7e..58d3738a2b7f 100644
--- a/drivers/char/epca.c
+++ b/drivers/char/epca.c
@@ -6,6 +6,8 @@
For technical support please email digiLinux@dgii.com or
call Digi tech support at (612) 912-3456
+ ** This driver is no longer supported by Digi **
+
Much of this design and code came from epca.c which was
copyright (C) 1994, 1995 Troy De Jongh, and subsquently
modified by David Nugent, Christoph Lameter, Mike McLagan.
@@ -43,31 +45,19 @@
#include <linux/interrupt.h>
#include <asm/uaccess.h>
#include <asm/io.h>
-
-#ifdef CONFIG_PCI
-#define ENABLE_PCI
-#endif /* CONFIG_PCI */
-
-#define putUser(arg1, arg2) put_user(arg1, (unsigned long __user *)arg2)
-#define getUser(arg1, arg2) get_user(arg1, (unsigned __user *)arg2)
-
-#ifdef ENABLE_PCI
+#include <linux/spinlock.h>
#include <linux/pci.h>
#include "digiPCI.h"
-#endif /* ENABLE_PCI */
+
#include "digi1.h"
#include "digiFep1.h"
#include "epca.h"
#include "epcaconfig.h"
-#if BITS_PER_LONG != 32
-# error FIXME: this driver only works on 32-bit platforms
-#endif
-
/* ---------------------- Begin defines ------------------------ */
-#define VERSION "1.3.0.1-LK"
+#define VERSION "1.3.0.1-LK2.6"
/* This major needs to be submitted to Linux to join the majors list */
@@ -81,13 +71,17 @@
/* ----------------- Begin global definitions ------------------- */
-static char mesg[100];
static int nbdevs, num_cards, liloconfig;
static int digi_poller_inhibited = 1 ;
static int setup_error_code;
static int invalid_lilo_config;
+/* The ISA boards do window flipping into the same spaces so its only sane
+ with a single lock. It's still pretty efficient */
+
+static spinlock_t epca_lock = SPIN_LOCK_UNLOCKED;
+
/* -----------------------------------------------------------------------
MAXBOARDS is typically 12, but ISA and EISA cards are restricted to
7 below.
@@ -129,58 +123,58 @@ static struct timer_list epca_timer;
configured.
----------------------------------------------------------------------- */
-static inline void memwinon(struct board_info *b, unsigned int win);
-static inline void memwinoff(struct board_info *b, unsigned int win);
-static inline void globalwinon(struct channel *ch);
-static inline void rxwinon(struct channel *ch);
-static inline void txwinon(struct channel *ch);
-static inline void memoff(struct channel *ch);
-static inline void assertgwinon(struct channel *ch);
-static inline void assertmemoff(struct channel *ch);
+static void memwinon(struct board_info *b, unsigned int win);
+static void memwinoff(struct board_info *b, unsigned int win);
+static void globalwinon(struct channel *ch);
+static void rxwinon(struct channel *ch);
+static void txwinon(struct channel *ch);
+static void memoff(struct channel *ch);
+static void assertgwinon(struct channel *ch);
+static void assertmemoff(struct channel *ch);
/* ---- Begin more 'specific' memory functions for cx_like products --- */
-static inline void pcxem_memwinon(struct board_info *b, unsigned int win);
-static inline void pcxem_memwinoff(struct board_info *b, unsigned int win);
-static inline void pcxem_globalwinon(struct channel *ch);
-static inline void pcxem_rxwinon(struct channel *ch);
-static inline void pcxem_txwinon(struct channel *ch);
-static inline void pcxem_memoff(struct channel *ch);
+static void pcxem_memwinon(struct board_info *b, unsigned int win);
+static void pcxem_memwinoff(struct board_info *b, unsigned int win);
+static void pcxem_globalwinon(struct channel *ch);
+static void pcxem_rxwinon(struct channel *ch);
+static void pcxem_txwinon(struct channel *ch);
+static void pcxem_memoff(struct channel *ch);
/* ------ Begin more 'specific' memory functions for the pcxe ------- */
-static inline void pcxe_memwinon(struct board_info *b, unsigned int win);
-static inline void pcxe_memwinoff(struct board_info *b, unsigned int win);
-static inline void pcxe_globalwinon(struct channel *ch);
-static inline void pcxe_rxwinon(struct channel *ch);
-static inline void pcxe_txwinon(struct channel *ch);
-static inline void pcxe_memoff(struct channel *ch);
+static void pcxe_memwinon(struct board_info *b, unsigned int win);
+static void pcxe_memwinoff(struct board_info *b, unsigned int win);
+static void pcxe_globalwinon(struct channel *ch);
+static void pcxe_rxwinon(struct channel *ch);
+static void pcxe_txwinon(struct channel *ch);
+static void pcxe_memoff(struct channel *ch);
/* ---- Begin more 'specific' memory functions for the pc64xe and pcxi ---- */
/* Note : pc64xe and pcxi share the same windowing routines */
-static inline void pcxi_memwinon(struct board_info *b, unsigned int win);
-static inline void pcxi_memwinoff(struct board_info *b, unsigned int win);
-static inline void pcxi_globalwinon(struct channel *ch);
-static inline void pcxi_rxwinon(struct channel *ch);
-static inline void pcxi_txwinon(struct channel *ch);
-static inline void pcxi_memoff(struct channel *ch);
+static void pcxi_memwinon(struct board_info *b, unsigned int win);
+static void pcxi_memwinoff(struct board_info *b, unsigned int win);
+static void pcxi_globalwinon(struct channel *ch);
+static void pcxi_rxwinon(struct channel *ch);
+static void pcxi_txwinon(struct channel *ch);
+static void pcxi_memoff(struct channel *ch);
/* - Begin 'specific' do nothing memory functions needed for some cards - */
-static inline void dummy_memwinon(struct board_info *b, unsigned int win);
-static inline void dummy_memwinoff(struct board_info *b, unsigned int win);
-static inline void dummy_globalwinon(struct channel *ch);
-static inline void dummy_rxwinon(struct channel *ch);
-static inline void dummy_txwinon(struct channel *ch);
-static inline void dummy_memoff(struct channel *ch);
-static inline void dummy_assertgwinon(struct channel *ch);
-static inline void dummy_assertmemoff(struct channel *ch);
+static void dummy_memwinon(struct board_info *b, unsigned int win);
+static void dummy_memwinoff(struct board_info *b, unsigned int win);
+static void dummy_globalwinon(struct channel *ch);
+static void dummy_rxwinon(struct channel *ch);
+static void dummy_txwinon(struct channel *ch);
+static void dummy_memoff(struct channel *ch);
+static void dummy_assertgwinon(struct channel *ch);
+static void dummy_assertmemoff(struct channel *ch);
/* ------------------- Begin declare functions ----------------------- */
-static inline struct channel *verifyChannel(register struct tty_struct *);
-static inline void pc_sched_event(struct channel *, int);
+static struct channel *verifyChannel(struct tty_struct *);
+static void pc_sched_event(struct channel *, int);
static void epca_error(int, char *);
static void pc_close(struct tty_struct *, struct file *);
static void shutdown(struct channel *);
@@ -215,15 +209,11 @@ static void pc_unthrottle(struct tty_struct *tty);
static void digi_send_break(struct channel *ch, int msec);
static void setup_empty_event(struct tty_struct *tty, struct channel *ch);
void epca_setup(char *, int *);
-void console_print(const char *);
static int get_termio(struct tty_struct *, struct termio __user *);
static int pc_write(struct tty_struct *, const unsigned char *, int);
-int pc_init(void);
-
-#ifdef ENABLE_PCI
+static int pc_init(void);
static int init_PCI(void);
-#endif /* ENABLE_PCI */
/* ------------------------------------------------------------------
@@ -237,41 +227,41 @@ static int init_PCI(void);
making direct calls deserves what they get.
-------------------------------------------------------------------- */
-static inline void memwinon(struct board_info *b, unsigned int win)
+static void memwinon(struct board_info *b, unsigned int win)
{
(b->memwinon)(b, win);
}
-static inline void memwinoff(struct board_info *b, unsigned int win)
+static void memwinoff(struct board_info *b, unsigned int win)
{
(b->memwinoff)(b, win);
}
-static inline void globalwinon(struct channel *ch)
+static void globalwinon(struct channel *ch)
{
(ch->board->globalwinon)(ch);
}
-static inline void rxwinon(struct channel *ch)
+static void rxwinon(struct channel *ch)
{
(ch->board->rxwinon)(ch);
}
-static inline void txwinon(struct channel *ch)
+static void txwinon(struct channel *ch)
{
(ch->board->txwinon)(ch);
}
-static inline void memoff(struct channel *ch)
+static void memoff(struct channel *ch)
{
(ch->board->memoff)(ch);
}
-static inline void assertgwinon(struct channel *ch)
+static void assertgwinon(struct channel *ch)
{
(ch->board->assertgwinon)(ch);
}
-static inline void assertmemoff(struct channel *ch)
+static void assertmemoff(struct channel *ch)
{
(ch->board->assertmemoff)(ch);
}
@@ -281,66 +271,66 @@ static inline void assertmemoff(struct channel *ch)
and CX series cards.
------------------------------------------------------------ */
-static inline void pcxem_memwinon(struct board_info *b, unsigned int win)
+static void pcxem_memwinon(struct board_info *b, unsigned int win)
{
- outb_p(FEPWIN|win, (int)b->port + 1);
+ outb_p(FEPWIN|win, b->port + 1);
}
-static inline void pcxem_memwinoff(struct board_info *b, unsigned int win)
+static void pcxem_memwinoff(struct board_info *b, unsigned int win)
{
- outb_p(0, (int)b->port + 1);
+ outb_p(0, b->port + 1);
}
-static inline void pcxem_globalwinon(struct channel *ch)
+static void pcxem_globalwinon(struct channel *ch)
{
outb_p( FEPWIN, (int)ch->board->port + 1);
}
-static inline void pcxem_rxwinon(struct channel *ch)
+static void pcxem_rxwinon(struct channel *ch)
{
outb_p(ch->rxwin, (int)ch->board->port + 1);
}
-static inline void pcxem_txwinon(struct channel *ch)
+static void pcxem_txwinon(struct channel *ch)
{
outb_p(ch->txwin, (int)ch->board->port + 1);
}
-static inline void pcxem_memoff(struct channel *ch)
+static void pcxem_memoff(struct channel *ch)
{
outb_p(0, (int)ch->board->port + 1);
}
/* ----------------- Begin pcxe memory window stuff ------------------ */
-static inline void pcxe_memwinon(struct board_info *b, unsigned int win)
+static void pcxe_memwinon(struct board_info *b, unsigned int win)
{
- outb_p(FEPWIN | win, (int)b->port + 1);
+ outb_p(FEPWIN | win, b->port + 1);
}
-static inline void pcxe_memwinoff(struct board_info *b, unsigned int win)
+static void pcxe_memwinoff(struct board_info *b, unsigned int win)
{
- outb_p(inb((int)b->port) & ~FEPMEM,
- (int)b->port + 1);
- outb_p(0, (int)b->port + 1);
+ outb_p(inb(b->port) & ~FEPMEM,
+ b->port + 1);
+ outb_p(0, b->port + 1);
}
-static inline void pcxe_globalwinon(struct channel *ch)
+static void pcxe_globalwinon(struct channel *ch)
{
outb_p( FEPWIN, (int)ch->board->port + 1);
}
-static inline void pcxe_rxwinon(struct channel *ch)
+static void pcxe_rxwinon(struct channel *ch)
{
outb_p(ch->rxwin, (int)ch->board->port + 1);
}
-static inline void pcxe_txwinon(struct channel *ch)
+static void pcxe_txwinon(struct channel *ch)
{
outb_p(ch->txwin, (int)ch->board->port + 1);
}
-static inline void pcxe_memoff(struct channel *ch)
+static void pcxe_memoff(struct channel *ch)
{
outb_p(0, (int)ch->board->port);
outb_p(0, (int)ch->board->port + 1);
@@ -348,44 +338,44 @@ static inline void pcxe_memoff(struct channel *ch)
/* ------------- Begin pc64xe and pcxi memory window stuff -------------- */
-static inline void pcxi_memwinon(struct board_info *b, unsigned int win)
+static void pcxi_memwinon(struct board_info *b, unsigned int win)
{
- outb_p(inb((int)b->port) | FEPMEM, (int)b->port);
+ outb_p(inb(b->port) | FEPMEM, b->port);
}
-static inline void pcxi_memwinoff(struct board_info *b, unsigned int win)
+static void pcxi_memwinoff(struct board_info *b, unsigned int win)
{
- outb_p(inb((int)b->port) & ~FEPMEM, (int)b->port);
+ outb_p(inb(b->port) & ~FEPMEM, b->port);
}
-static inline void pcxi_globalwinon(struct channel *ch)
+static void pcxi_globalwinon(struct channel *ch)
{
- outb_p(FEPMEM, (int)ch->board->port);
+ outb_p(FEPMEM, ch->board->port);
}
-static inline void pcxi_rxwinon(struct channel *ch)
+static void pcxi_rxwinon(struct channel *ch)
{
- outb_p(FEPMEM, (int)ch->board->port);
+ outb_p(FEPMEM, ch->board->port);
}
-static inline void pcxi_txwinon(struct channel *ch)
+static void pcxi_txwinon(struct channel *ch)
{
- outb_p(FEPMEM, (int)ch->board->port);
+ outb_p(FEPMEM, ch->board->port);
}
-static inline void pcxi_memoff(struct channel *ch)
+static void pcxi_memoff(struct channel *ch)
{
- outb_p(0, (int)ch->board->port);
+ outb_p(0, ch->board->port);
}
-static inline void pcxi_assertgwinon(struct channel *ch)
+static void pcxi_assertgwinon(struct channel *ch)
{
- epcaassert(inb((int)ch->board->port) & FEPMEM, "Global memory off");
+ epcaassert(inb(ch->board->port) & FEPMEM, "Global memory off");
}
-static inline void pcxi_assertmemoff(struct channel *ch)
+static void pcxi_assertmemoff(struct channel *ch)
{
- epcaassert(!(inb((int)ch->board->port) & FEPMEM), "Memory on");
+ epcaassert(!(inb(ch->board->port) & FEPMEM), "Memory on");
}
@@ -398,185 +388,143 @@ static inline void pcxi_assertmemoff(struct channel *ch)
may or may not do anything.
---------------------------------------------------------------------------*/
-static inline void dummy_memwinon(struct board_info *b, unsigned int win)
+static void dummy_memwinon(struct board_info *b, unsigned int win)
{
}
-static inline void dummy_memwinoff(struct board_info *b, unsigned int win)
+static void dummy_memwinoff(struct board_info *b, unsigned int win)
{
}
-static inline void dummy_globalwinon(struct channel *ch)
+static void dummy_globalwinon(struct channel *ch)
{
}
-static inline void dummy_rxwinon(struct channel *ch)
+static void dummy_rxwinon(struct channel *ch)
{
}
-static inline void dummy_txwinon(struct channel *ch)
+static void dummy_txwinon(struct channel *ch)
{
}
-static inline void dummy_memoff(struct channel *ch)
+static void dummy_memoff(struct channel *ch)
{
}
-static inline void dummy_assertgwinon(struct channel *ch)
+static void dummy_assertgwinon(struct channel *ch)
{
}
-static inline void dummy_assertmemoff(struct channel *ch)
+static void dummy_assertmemoff(struct channel *ch)
{
}
/* ----------------- Begin verifyChannel function ----------------------- */
-static inline struct channel *verifyChannel(register struct tty_struct *tty)
+static struct channel *verifyChannel(struct tty_struct *tty)
{ /* Begin verifyChannel */
-
/* --------------------------------------------------------------------
This routine basically provides a sanity check. It insures that
the channel returned is within the proper range of addresses as
well as properly initialized. If some bogus info gets passed in
through tty->driver_data this should catch it.
- --------------------------------------------------------------------- */
-
- if (tty)
- { /* Begin if tty */
-
- register struct channel *ch = (struct channel *)tty->driver_data;
-
- if ((ch >= &digi_channels[0]) && (ch < &digi_channels[nbdevs]))
- {
+ --------------------------------------------------------------------- */
+ if (tty) {
+ struct channel *ch = (struct channel *)tty->driver_data;
+ if ((ch >= &digi_channels[0]) && (ch < &digi_channels[nbdevs])) {
if (ch->magic == EPCA_MAGIC)
return ch;
}
-
- } /* End if tty */
-
- /* Else return a NULL for invalid */
+ }
return NULL;
} /* End verifyChannel */
/* ------------------ Begin pc_sched_event ------------------------- */
-static inline void pc_sched_event(struct channel *ch, int event)
-{ /* Begin pc_sched_event */
-
-
+static void pc_sched_event(struct channel *ch, int event)
+{
/* ----------------------------------------------------------------------
We call this to schedule interrupt processing on some event. The
kernel sees our request and calls the related routine in OUR driver.
-------------------------------------------------------------------------*/
-
ch->event |= 1 << event;
schedule_work(&ch->tqueue);
-
-
} /* End pc_sched_event */
/* ------------------ Begin epca_error ------------------------- */
static void epca_error(int line, char *msg)
-{ /* Begin epca_error */
-
+{
printk(KERN_ERR "epca_error (Digi): line = %d %s\n",line,msg);
- return;
-
-} /* End epca_error */
+}
/* ------------------ Begin pc_close ------------------------- */
static void pc_close(struct tty_struct * tty, struct file * filp)
-{ /* Begin pc_close */
-
+{
struct channel *ch;
unsigned long flags;
-
/* ---------------------------------------------------------
verifyChannel returns the channel from the tty struct
if it is valid. This serves as a sanity check.
------------------------------------------------------------- */
-
- if ((ch = verifyChannel(tty)) != NULL)
- { /* Begin if ch != NULL */
-
- save_flags(flags);
- cli();
-
- if (tty_hung_up_p(filp))
- {
- restore_flags(flags);
+ if ((ch = verifyChannel(tty)) != NULL) { /* Begin if ch != NULL */
+ spin_lock_irqsave(&epca_lock, flags);
+ if (tty_hung_up_p(filp)) {
+ spin_unlock_irqrestore(&epca_lock, flags);
return;
}
-
/* Check to see if the channel is open more than once */
- if (ch->count-- > 1)
- { /* Begin channel is open more than once */
-
+ if (ch->count-- > 1) {
+ /* Begin channel is open more than once */
/* -------------------------------------------------------------
Return without doing anything. Someone might still be using
the channel.
---------------------------------------------------------------- */
-
- restore_flags(flags);
+ spin_unlock_irqrestore(&epca_lock, flags);
return;
} /* End channel is open more than once */
/* Port open only once go ahead with shutdown & reset */
-
- if (ch->count < 0)
- {
- ch->count = 0;
- }
+ if (ch->count < 0)
+ BUG();
/* ---------------------------------------------------------------
Let the rest of the driver know the channel is being closed.
This becomes important if an open is attempted before close
is finished.
------------------------------------------------------------------ */
-
ch->asyncflags |= ASYNC_CLOSING;
-
tty->closing = 1;
- if (ch->asyncflags & ASYNC_INITIALIZED)
- {
+ spin_unlock_irqrestore(&epca_lock, flags);
+
+ if (ch->asyncflags & ASYNC_INITIALIZED) {
/* Setup an event to indicate when the transmit buffer empties */
setup_empty_event(tty, ch);
tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */
}
-
if (tty->driver->flush_buffer)
tty->driver->flush_buffer(tty);
tty_ldisc_flush(tty);
shutdown(ch);
+
+ spin_lock_irqsave(&epca_lock, flags);
tty->closing = 0;
ch->event = 0;
ch->tty = NULL;
+ spin_unlock_irqrestore(&epca_lock, flags);
- if (ch->blocked_open)
- { /* Begin if blocked_open */
-
+ if (ch->blocked_open) { /* Begin if blocked_open */
if (ch->close_delay)
- {
msleep_interruptible(jiffies_to_msecs(ch->close_delay));
- }
-
wake_up_interruptible(&ch->open_wait);
-
} /* End if blocked_open */
-
ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED |
ASYNC_CLOSING);
wake_up_interruptible(&ch->close_wait);
-
-
- restore_flags(flags);
-
} /* End if ch != NULL */
-
} /* End pc_close */
/* ------------------ Begin shutdown ------------------------- */
@@ -586,15 +534,14 @@ static void shutdown(struct channel *ch)
unsigned long flags;
struct tty_struct *tty;
- volatile struct board_chan *bc;
+ struct board_chan *bc;
if (!(ch->asyncflags & ASYNC_INITIALIZED))
return;
- save_flags(flags);
- cli();
- globalwinon(ch);
+ spin_lock_irqsave(&epca_lock, flags);
+ globalwinon(ch);
bc = ch->brdchan;
/* ------------------------------------------------------------------
@@ -604,20 +551,17 @@ static void shutdown(struct channel *ch)
--------------------------------------------------------------------- */
if (bc)
- bc->idata = 0;
-
+ writeb(0, &bc->idata);
tty = ch->tty;
/* ----------------------------------------------------------------
If we're a modem control device and HUPCL is on, drop RTS & DTR.
------------------------------------------------------------------ */
- if (tty->termios->c_cflag & HUPCL)
- {
+ if (tty->termios->c_cflag & HUPCL) {
ch->omodem &= ~(ch->m_rts | ch->m_dtr);
fepcmd(ch, SETMODEM, 0, ch->m_dtr | ch->m_rts, 10, 1);
}
-
memoff(ch);
/* ------------------------------------------------------------------
@@ -628,7 +572,7 @@ static void shutdown(struct channel *ch)
/* Prevent future Digi programmed interrupts from coming active */
ch->asyncflags &= ~ASYNC_INITIALIZED;
- restore_flags(flags);
+ spin_unlock_irqrestore(&epca_lock, flags);
} /* End shutdown */
@@ -636,7 +580,6 @@ static void shutdown(struct channel *ch)
static void pc_hangup(struct tty_struct *tty)
{ /* Begin pc_hangup */
-
struct channel *ch;
/* ---------------------------------------------------------
@@ -644,25 +587,21 @@ static void pc_hangup(struct tty_struct *tty)
if it is valid. This serves as a sanity check.
------------------------------------------------------------- */
- if ((ch = verifyChannel(tty)) != NULL)
- { /* Begin if ch != NULL */
-
+ if ((ch = verifyChannel(tty)) != NULL) { /* Begin if ch != NULL */
unsigned long flags;
- save_flags(flags);
- cli();
if (tty->driver->flush_buffer)
tty->driver->flush_buffer(tty);
tty_ldisc_flush(tty);
shutdown(ch);
+ spin_lock_irqsave(&epca_lock, flags);
ch->tty = NULL;
ch->event = 0;
ch->count = 0;
- restore_flags(flags);
ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED);
+ spin_unlock_irqrestore(&epca_lock, flags);
wake_up_interruptible(&ch->open_wait);
-
} /* End if ch != NULL */
} /* End pc_hangup */
@@ -672,18 +611,14 @@ static void pc_hangup(struct tty_struct *tty)
static int pc_write(struct tty_struct * tty,
const unsigned char *buf, int bytesAvailable)
{ /* Begin pc_write */
-
- register unsigned int head, tail;
- register int dataLen;
- register int size;
- register int amountCopied;
-
-
+ unsigned int head, tail;
+ int dataLen;
+ int size;
+ int amountCopied;
struct channel *ch;
unsigned long flags;
int remain;
- volatile struct board_chan *bc;
-
+ struct board_chan *bc;
/* ----------------------------------------------------------------
pc_write is primarily called directly by the kernel routine
@@ -706,24 +641,20 @@ static int pc_write(struct tty_struct * tty,
bc = ch->brdchan;
size = ch->txbufsize;
-
amountCopied = 0;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&epca_lock, flags);
globalwinon(ch);
- head = bc->tin & (size - 1);
- tail = bc->tout;
+ head = readw(&bc->tin) & (size - 1);
+ tail = readw(&bc->tout);
- if (tail != bc->tout)
- tail = bc->tout;
+ if (tail != readw(&bc->tout))
+ tail = readw(&bc->tout);
tail &= (size - 1);
/* If head >= tail, head has not wrapped around. */
- if (head >= tail)
- { /* Begin head has not wrapped */
-
+ if (head >= tail) { /* Begin head has not wrapped */
/* ---------------------------------------------------------------
remain (much like dataLen above) represents the total amount of
space available on the card for data. Here dataLen represents
@@ -731,26 +662,19 @@ static int pc_write(struct tty_struct * tty,
buffer. This is important because a memcpy cannot be told to
automatically wrap around when it hits the buffer end.
------------------------------------------------------------------ */
-
dataLen = size - head;
remain = size - (head - tail) - 1;
-
- } /* End head has not wrapped */
- else
- { /* Begin head has wrapped around */
+ } else { /* Begin head has wrapped around */
remain = tail - head - 1;
dataLen = remain;
} /* End head has wrapped around */
-
/* -------------------------------------------------------------------
Check the space on the card. If we have more data than
space; reduce the amount of data to fit the space.
---------------------------------------------------------------------- */
-
bytesAvailable = min(remain, bytesAvailable);
-
txwinon(ch);
while (bytesAvailable > 0)
{ /* Begin while there is data to copy onto card */
@@ -767,26 +691,21 @@ static int pc_write(struct tty_struct * tty,
amountCopied += dataLen;
bytesAvailable -= dataLen;
- if (head >= size)
- {
+ if (head >= size) {
head = 0;
dataLen = tail;
}
-
} /* End while there is data to copy onto card */
-
ch->statusflags |= TXBUSY;
globalwinon(ch);
- bc->tin = head;
+ writew(head, &bc->tin);
- if ((ch->statusflags & LOWWAIT) == 0)
- {
+ if ((ch->statusflags & LOWWAIT) == 0) {
ch->statusflags |= LOWWAIT;
- bc->ilow = 1;
+ writeb(1, &bc->ilow);
}
memoff(ch);
- restore_flags(flags);
-
+ spin_unlock_irqrestore(&epca_lock, flags);
return(amountCopied);
} /* End pc_write */
@@ -795,11 +714,7 @@ static int pc_write(struct tty_struct * tty,
static void pc_put_char(struct tty_struct *tty, unsigned char c)
{ /* Begin pc_put_char */
-
-
pc_write(tty, &c, 1);
- return;
-
} /* End pc_put_char */
/* ------------------ Begin pc_write_room ------------------------- */
@@ -811,7 +726,7 @@ static int pc_write_room(struct tty_struct *tty)
struct channel *ch;
unsigned long flags;
unsigned int head, tail;
- volatile struct board_chan *bc;
+ struct board_chan *bc;
remain = 0;
@@ -820,33 +735,29 @@ static int pc_write_room(struct tty_struct *tty)
if it is valid. This serves as a sanity check.
------------------------------------------------------------- */
- if ((ch = verifyChannel(tty)) != NULL)
- {
- save_flags(flags);
- cli();
+ if ((ch = verifyChannel(tty)) != NULL) {
+ spin_lock_irqsave(&epca_lock, flags);
globalwinon(ch);
bc = ch->brdchan;
- head = bc->tin & (ch->txbufsize - 1);
- tail = bc->tout;
+ head = readw(&bc->tin) & (ch->txbufsize - 1);
+ tail = readw(&bc->tout);
- if (tail != bc->tout)
- tail = bc->tout;
+ if (tail != readw(&bc->tout))
+ tail = readw(&bc->tout);
/* Wrap tail if necessary */
tail &= (ch->txbufsize - 1);
if ((remain = tail - head - 1) < 0 )
remain += ch->txbufsize;
- if (remain && (ch->statusflags & LOWWAIT) == 0)
- {
+ if (remain && (ch->statusflags & LOWWAIT) == 0) {
ch->statusflags |= LOWWAIT;
- bc->ilow = 1;
+ writeb(1, &bc->ilow);
}
memoff(ch);
- restore_flags(flags);
+ spin_unlock_irqrestore(&epca_lock, flags);
}
-
/* Return how much room is left on card */
return remain;
@@ -862,8 +773,7 @@ static int pc_chars_in_buffer(struct tty_struct *tty)
int remain;
unsigned long flags;
struct channel *ch;
- volatile struct board_chan *bc;
-
+ struct board_chan *bc;
/* ---------------------------------------------------------
verifyChannel returns the channel from the tty struct
@@ -873,34 +783,27 @@ static int pc_chars_in_buffer(struct tty_struct *tty)
if ((ch = verifyChannel(tty)) == NULL)
return(0);
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&epca_lock, flags);
globalwinon(ch);
bc = ch->brdchan;
- tail = bc->tout;
- head = bc->tin;
- ctail = ch->mailbox->cout;
+ tail = readw(&bc->tout);
+ head = readw(&bc->tin);
+ ctail = readw(&ch->mailbox->cout);
- if (tail == head && ch->mailbox->cin == ctail && bc->tbusy == 0)
+ if (tail == head && readw(&ch->mailbox->cin) == ctail && readb(&bc->tbusy) == 0)
chars = 0;
- else
- { /* Begin if some space on the card has been used */
-
- head = bc->tin & (ch->txbufsize - 1);
+ else { /* Begin if some space on the card has been used */
+ head = readw(&bc->tin) & (ch->txbufsize - 1);
tail &= (ch->txbufsize - 1);
-
/* --------------------------------------------------------------
The logic here is basically opposite of the above pc_write_room
here we are finding the amount of bytes in the buffer filled.
Not the amount of bytes empty.
------------------------------------------------------------------- */
-
if ((remain = tail - head - 1) < 0 )
remain += ch->txbufsize;
-
chars = (int)(ch->txbufsize - remain);
-
/* -------------------------------------------------------------
Make it possible to wakeup anything waiting for output
in tty_ioctl.c, etc.
@@ -908,15 +811,12 @@ static int pc_chars_in_buffer(struct tty_struct *tty)
If not already set. Setup an event to indicate when the
transmit buffer empties
----------------------------------------------------------------- */
-
if (!(ch->statusflags & EMPTYWAIT))
setup_empty_event(tty,ch);
} /* End if some space on the card has been used */
-
memoff(ch);
- restore_flags(flags);
-
+ spin_unlock_irqrestore(&epca_lock, flags);
/* Return number of characters residing on card. */
return(chars);
@@ -930,67 +830,46 @@ static void pc_flush_buffer(struct tty_struct *tty)
unsigned int tail;
unsigned long flags;
struct channel *ch;
- volatile struct board_chan *bc;
-
-
+ struct board_chan *bc;
/* ---------------------------------------------------------
verifyChannel returns the channel from the tty struct
if it is valid. This serves as a sanity check.
------------------------------------------------------------- */
-
if ((ch = verifyChannel(tty)) == NULL)
return;
- save_flags(flags);
- cli();
-
+ spin_lock_irqsave(&epca_lock, flags);
globalwinon(ch);
-
bc = ch->brdchan;
- tail = bc->tout;
-
+ tail = readw(&bc->tout);
/* Have FEP move tout pointer; effectively flushing transmit buffer */
-
fepcmd(ch, STOUT, (unsigned) tail, 0, 0, 0);
-
memoff(ch);
- restore_flags(flags);
-
+ spin_unlock_irqrestore(&epca_lock, flags);
wake_up_interruptible(&tty->write_wait);
tty_wakeup(tty);
-
} /* End pc_flush_buffer */
/* ------------------ Begin pc_flush_chars ---------------------- */
static void pc_flush_chars(struct tty_struct *tty)
{ /* Begin pc_flush_chars */
-
struct channel * ch;
-
/* ---------------------------------------------------------
verifyChannel returns the channel from the tty struct
if it is valid. This serves as a sanity check.
------------------------------------------------------------- */
-
- if ((ch = verifyChannel(tty)) != NULL)
- {
+ if ((ch = verifyChannel(tty)) != NULL) {
unsigned long flags;
-
- save_flags(flags);
- cli();
-
+ spin_lock_irqsave(&epca_lock, flags);
/* ----------------------------------------------------------------
If not already set and the transmitter is busy setup an event
to indicate when the transmit empties.
------------------------------------------------------------------- */
-
if ((ch->statusflags & TXBUSY) && !(ch->statusflags & EMPTYWAIT))
setup_empty_event(tty,ch);
-
- restore_flags(flags);
+ spin_unlock_irqrestore(&epca_lock, flags);
}
-
} /* End pc_flush_chars */
/* ------------------ Begin block_til_ready ---------------------- */
@@ -998,14 +877,11 @@ static void pc_flush_chars(struct tty_struct *tty)
static int block_til_ready(struct tty_struct *tty,
struct file *filp, struct channel *ch)
{ /* Begin block_til_ready */
-
DECLARE_WAITQUEUE(wait,current);
int retval, do_clocal = 0;
unsigned long flags;
-
- if (tty_hung_up_p(filp))
- {
+ if (tty_hung_up_p(filp)) {
if (ch->asyncflags & ASYNC_HUP_NOTIFY)
retval = -EAGAIN;
else
@@ -1017,8 +893,7 @@ static int block_til_ready(struct tty_struct *tty,
If the device is in the middle of being closed, then block
until it's done, and then try again.
-------------------------------------------------------------------- */
- if (ch->asyncflags & ASYNC_CLOSING)
- {
+ if (ch->asyncflags & ASYNC_CLOSING) {
interruptible_sleep_on(&ch->close_wait);
if (ch->asyncflags & ASYNC_HUP_NOTIFY)
@@ -1027,43 +902,29 @@ static int block_til_ready(struct tty_struct *tty,
return -ERESTARTSYS;
}
- if (filp->f_flags & O_NONBLOCK)
- {
+ if (filp->f_flags & O_NONBLOCK) {
/* -----------------------------------------------------------------
If non-blocking mode is set, then make the check up front
and then exit.
-------------------------------------------------------------------- */
-
ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
-
return 0;
}
-
-
if (tty->termios->c_cflag & CLOCAL)
do_clocal = 1;
-
- /* Block waiting for the carrier detect and the line to become free */
+ /* Block waiting for the carrier detect and the line to become free */
retval = 0;
add_wait_queue(&ch->open_wait, &wait);
- save_flags(flags);
- cli();
-
+ spin_lock_irqsave(&epca_lock, flags);
/* We dec count so that pc_close will know when to free things */
if (!tty_hung_up_p(filp))
ch->count--;
-
- restore_flags(flags);
-
ch->blocked_open++;
-
while(1)
{ /* Begin forever while */
-
set_current_state(TASK_INTERRUPTIBLE);
-
if (tty_hung_up_p(filp) ||
!(ch->asyncflags & ASYNC_INITIALIZED))
{
@@ -1073,17 +934,14 @@ static int block_til_ready(struct tty_struct *tty,
retval = -ERESTARTSYS;
break;
}
-
if (!(ch->asyncflags & ASYNC_CLOSING) &&
(do_clocal || (ch->imodem & ch->dcd)))
break;
-
- if (signal_pending(current))
- {
+ if (signal_pending(current)) {
retval = -ERESTARTSYS;
break;
}
-
+ spin_unlock_irqrestore(&epca_lock, flags);
/* ---------------------------------------------------------------
Allow someone else to be scheduled. We will occasionally go
through this loop until one of the above conditions change.
@@ -1091,25 +949,23 @@ static int block_til_ready(struct tty_struct *tty,
prevent this loop from hogging the cpu.
------------------------------------------------------------------ */
schedule();
+ spin_lock_irqsave(&epca_lock, flags);
} /* End forever while */
current->state = TASK_RUNNING;
remove_wait_queue(&ch->open_wait, &wait);
- cli();
if (!tty_hung_up_p(filp))
ch->count++;
- restore_flags(flags);
-
ch->blocked_open--;
+ spin_unlock_irqrestore(&epca_lock, flags);
+
if (retval)
return retval;
ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
-
return 0;
-
} /* End block_til_ready */
/* ------------------ Begin pc_open ---------------------- */
@@ -1120,17 +976,12 @@ static int pc_open(struct tty_struct *tty, struct file * filp)
struct channel *ch;
unsigned long flags;
int line, retval, boardnum;
- volatile struct board_chan *bc;
- volatile unsigned int head;
+ struct board_chan *bc;
+ unsigned int head;
line = tty->index;
- if (line < 0 || line >= nbdevs)
- {
- printk(KERN_ERR "<Error> - pc_open : line out of range in pc_open\n");
- tty->driver_data = NULL;
- return(-ENODEV);
- }
-
+ if (line < 0 || line >= nbdevs)
+ return -ENODEV;
ch = &digi_channels[line];
boardnum = ch->boardnum;
@@ -1143,66 +994,49 @@ static int pc_open(struct tty_struct *tty, struct file * filp)
goes here.
---------------------------------------------------------------------- */
- if (invalid_lilo_config)
- {
+ if (invalid_lilo_config) {
if (setup_error_code & INVALID_BOARD_TYPE)
- printk(KERN_ERR "<Error> - pc_open: Invalid board type specified in LILO command\n");
-
+ printk(KERN_ERR "epca: pc_open: Invalid board type specified in kernel options.\n");
if (setup_error_code & INVALID_NUM_PORTS)
- printk(KERN_ERR "<Error> - pc_open: Invalid number of ports specified in LILO command\n");
-
+ printk(KERN_ERR "epca: pc_open: Invalid number of ports specified in kernel options.\n");
if (setup_error_code & INVALID_MEM_BASE)
- printk(KERN_ERR "<Error> - pc_open: Invalid board memory address specified in LILO command\n");
-
+ printk(KERN_ERR "epca: pc_open: Invalid board memory address specified in kernel options.\n");
if (setup_error_code & INVALID_PORT_BASE)
- printk(KERN_ERR "<Error> - pc_open: Invalid board port address specified in LILO command\n");
-
+ printk(KERN_ERR "epca; pc_open: Invalid board port address specified in kernel options.\n");
if (setup_error_code & INVALID_BOARD_STATUS)
- printk(KERN_ERR "<Error> - pc_open: Invalid board status specified in LILO command\n");
-
+ printk(KERN_ERR "epca: pc_open: Invalid board status specified in kernel options.\n");
if (setup_error_code & INVALID_ALTPIN)
- printk(KERN_ERR "<Error> - pc_open: Invalid board altpin specified in LILO command\n");
-
+ printk(KERN_ERR "epca: pc_open: Invalid board altpin specified in kernel options;\n");
tty->driver_data = NULL; /* Mark this device as 'down' */
- return(-ENODEV);
+ return -ENODEV;
}
-
- if ((boardnum >= num_cards) || (boards[boardnum].status == DISABLED))
- {
+ if (boardnum >= num_cards || boards[boardnum].status == DISABLED) {
tty->driver_data = NULL; /* Mark this device as 'down' */
return(-ENODEV);
}
- if (( bc = ch->brdchan) == 0)
- {
+ if ((bc = ch->brdchan) == 0) {
tty->driver_data = NULL;
- return(-ENODEV);
+ return -ENODEV;
}
+ spin_lock_irqsave(&epca_lock, flags);
/* ------------------------------------------------------------------
Every time a channel is opened, increment a counter. This is
necessary because we do not wish to flush and shutdown the channel
until the last app holding the channel open, closes it.
--------------------------------------------------------------------- */
-
ch->count++;
-
/* ----------------------------------------------------------------
Set a kernel structures pointer to our local channel
structure. This way we can get to it when passed only
a tty struct.
------------------------------------------------------------------ */
-
tty->driver_data = ch;
-
/* ----------------------------------------------------------------
If this is the first time the channel has been opened, initialize
the tty->termios struct otherwise let pc_close handle it.
-------------------------------------------------------------------- */
-
- save_flags(flags);
- cli();
-
globalwinon(ch);
ch->statusflags = 0;
@@ -1213,8 +1047,8 @@ static int pc_open(struct tty_struct *tty, struct file * filp)
Set receive head and tail ptrs to each other. This indicates
no data available to read.
----------------------------------------------------------------- */
- head = bc->rin;
- bc->rout = head;
+ head = readw(&bc->rin);
+ writew(head, &bc->rout);
/* Set the channels associated tty structure */
ch->tty = tty;
@@ -1224,122 +1058,74 @@ static int pc_open(struct tty_struct *tty, struct file * filp)
issues, etc.... It effect both control flags and input flags.
-------------------------------------------------------------------- */
epcaparam(tty,ch);
-
ch->asyncflags |= ASYNC_INITIALIZED;
memoff(ch);
-
- restore_flags(flags);
+ spin_unlock_irqrestore(&epca_lock, flags);
retval = block_til_ready(tty, filp, ch);
if (retval)
- {
return retval;
- }
-
/* -------------------------------------------------------------
Set this again in case a hangup set it to zero while this
open() was waiting for the line...
--------------------------------------------------------------- */
+ spin_lock_irqsave(&epca_lock, flags);
ch->tty = tty;
-
- save_flags(flags);
- cli();
globalwinon(ch);
-
/* Enable Digi Data events */
- bc->idata = 1;
-
+ writeb(1, &bc->idata);
memoff(ch);
- restore_flags(flags);
-
+ spin_unlock_irqrestore(&epca_lock, flags);
return 0;
-
} /* End pc_open */
-#ifdef MODULE
static int __init epca_module_init(void)
{ /* Begin init_module */
-
- unsigned long flags;
-
- save_flags(flags);
- cli();
-
- pc_init();
-
- restore_flags(flags);
-
- return(0);
+ return pc_init();
}
module_init(epca_module_init);
-#endif
-#ifdef ENABLE_PCI
static struct pci_driver epca_driver;
-#endif
-
-#ifdef MODULE
-/* -------------------- Begin cleanup_module ---------------------- */
static void __exit epca_module_exit(void)
{
-
int count, crd;
struct board_info *bd;
struct channel *ch;
- unsigned long flags;
del_timer_sync(&epca_timer);
- save_flags(flags);
- cli();
-
if ((tty_unregister_driver(pc_driver)) ||
(tty_unregister_driver(pc_info)))
{
- printk(KERN_WARNING "<Error> - DIGI : cleanup_module failed to un-register tty driver\n");
- restore_flags(flags);
+ printk(KERN_WARNING "epca: cleanup_module failed to un-register tty driver\n");
return;
}
put_tty_driver(pc_driver);
put_tty_driver(pc_info);
- for (crd = 0; crd < num_cards; crd++)
- { /* Begin for each card */
-
+ for (crd = 0; crd < num_cards; crd++) { /* Begin for each card */
bd = &boards[crd];
-
if (!bd)
{ /* Begin sanity check */
printk(KERN_ERR "<Error> - Digi : cleanup_module failed\n");
return;
} /* End sanity check */
-
- ch = card_ptr[crd];
-
+ ch = card_ptr[crd];
for (count = 0; count < bd->numports; count++, ch++)
{ /* Begin for each port */
-
- if (ch)
- {
+ if (ch) {
if (ch->tty)
tty_hangup(ch->tty);
kfree(ch->tmp_buf);
}
-
} /* End for each port */
} /* End for each card */
-
-#ifdef ENABLE_PCI
pci_unregister_driver (&epca_driver);
-#endif
-
- restore_flags(flags);
-
}
+
module_exit(epca_module_exit);
-#endif /* MODULE */
static struct tty_operations pc_ops = {
.open = pc_open,
@@ -1371,34 +1157,15 @@ static struct tty_operations info_ops = {
/* ------------------ Begin pc_init ---------------------- */
-int __init pc_init(void)
+static int __init pc_init(void)
{ /* Begin pc_init */
-
- /* ----------------------------------------------------------------
- pc_init is called by the operating system during boot up prior to
- any open calls being made. In the older versions of Linux (Prior
- to 2.0.0) an entry is made into tty_io.c. A pointer to the last
- memory location (from kernel space) used (kmem_start) is passed
- to pc_init. It is pc_inits responsibility to modify this value
- for any memory that the Digi driver might need and then return
- this value to the operating system. For example if the driver
- wishes to allocate 1K of kernel memory, pc_init would return
- (kmem_start + 1024). This memory (Between kmem_start and kmem_start
- + 1024) would then be available for use exclusively by the driver.
- In this case our driver does not allocate any of this kernel
- memory.
- ------------------------------------------------------------------*/
-
- ulong flags;
int crd;
struct board_info *bd;
unsigned char board_id = 0;
-#ifdef ENABLE_PCI
int pci_boards_found, pci_count;
pci_count = 0;
-#endif /* ENABLE_PCI */
pc_driver = alloc_tty_driver(MAX_ALLOC);
if (!pc_driver)
@@ -1416,8 +1183,7 @@ int __init pc_init(void)
Note : If LILO has ran epca_setup then epca_setup will handle defining
num_cards as well as copying the data into the board structure.
-------------------------------------------------------------------------- */
- if (!liloconfig)
- { /* Begin driver has been configured via. epcaconfig */
+ if (!liloconfig) { /* Begin driver has been configured via. epcaconfig */
nbdevs = NBDEVS;
num_cards = NUMCARDS;
@@ -1440,8 +1206,6 @@ int __init pc_init(void)
printk(KERN_INFO "DIGI epca driver version %s loaded.\n",VERSION);
-#ifdef ENABLE_PCI
-
/* ------------------------------------------------------------------
NOTE : This code assumes that the number of ports found in
the boards array is correct. This could be wrong if
@@ -1467,8 +1231,6 @@ int __init pc_init(void)
pci_boards_found += init_PCI();
num_cards += pci_boards_found;
-#endif /* ENABLE_PCI */
-
pc_driver->owner = THIS_MODULE;
pc_driver->name = "ttyD";
pc_driver->devfs_name = "tts/D";
@@ -1499,9 +1261,6 @@ int __init pc_init(void)
tty_set_operations(pc_info, &info_ops);
- save_flags(flags);
- cli();
-
for (crd = 0; crd < num_cards; crd++)
{ /* Begin for each card */
@@ -1610,11 +1369,7 @@ int __init pc_init(void)
if ((board_id & 0x30) == 0x30)
bd->memory_seg = 0x8000;
- } /* End it is an XI card */
- else
- {
- printk(KERN_ERR "<Error> - Board at 0x%x doesn't appear to be an XI\n",(int)bd->port);
- }
+ } else printk(KERN_ERR "epca: Board at 0x%x doesn't appear to be an XI\n",(int)bd->port);
break;
} /* End switch on bd->type */
@@ -1634,9 +1389,6 @@ int __init pc_init(void)
init_timer(&epca_timer);
epca_timer.function = epcapoll;
mod_timer(&epca_timer, jiffies + HZ/25);
-
- restore_flags(flags);
-
return 0;
} /* End pc_init */
@@ -1647,10 +1399,10 @@ static void post_fep_init(unsigned int crd)
{ /* Begin post_fep_init */
int i;
- unchar *memaddr;
- volatile struct global_data *gd;
+ unsigned char *memaddr;
+ struct global_data *gd;
struct board_info *bd;
- volatile struct board_chan *bc;
+ struct board_chan *bc;
struct channel *ch;
int shrinkmem = 0, lowwater ;
@@ -1669,9 +1421,7 @@ static void post_fep_init(unsigned int crd)
after DIGI_INIT has been called will return the proper values.
------------------------------------------------------------------- */
- if (bd->type >= PCIXEM) /* If the board in question is PCI */
- { /* Begin get PCI number of ports */
-
+ if (bd->type >= PCIXEM) { /* Begin get PCI number of ports */
/* --------------------------------------------------------------------
Below we use XEMPORTS as a memory offset regardless of which PCI
card it is. This is because all of the supported PCI cards have
@@ -1685,15 +1435,15 @@ static void post_fep_init(unsigned int crd)
(FYI - The id should be located at 0x1ac (And may use up to 4 bytes
if the box in question is a XEM or CX)).
------------------------------------------------------------------------ */
-
- bd->numports = (unsigned short)*(unsigned char *)bus_to_virt((unsigned long)
- (bd->re_map_membase + XEMPORTS));
-
-
+ /* PCI cards are already remapped at this point ISA are not */
+ bd->numports = readw(bd->re_map_membase + XEMPORTS);
epcaassert(bd->numports <= 64,"PCI returned a invalid number of ports");
nbdevs += (bd->numports);
-
- } /* End get PCI number of ports */
+ } else {
+ /* Fix up the mappings for ISA/EISA etc */
+ /* FIXME: 64K - can we be smarter ? */
+ bd->re_map_membase = ioremap(bd->membase, 0x10000);
+ }
if (crd != 0)
card_ptr[crd] = card_ptr[crd-1] + boards[crd-1].numports;
@@ -1701,19 +1451,9 @@ static void post_fep_init(unsigned int crd)
card_ptr[crd] = &digi_channels[crd]; /* <- For card 0 only */
ch = card_ptr[crd];
-
-
epcaassert(ch <= &digi_channels[nbdevs - 1], "ch out of range");
- memaddr = (unchar *)bd->re_map_membase;
-
- /*
- The below command is necessary because newer kernels (2.1.x and
- up) do not have a 1:1 virtual to physical mapping. The below
- call adjust for that.
- */
-
- memaddr = (unsigned char *)bus_to_virt((unsigned long)memaddr);
+ memaddr = bd->re_map_membase;
/* -----------------------------------------------------------------
The below assignment will set bc to point at the BEGINING of
@@ -1721,7 +1461,7 @@ static void post_fep_init(unsigned int crd)
8 and 64 of these structures.
-------------------------------------------------------------------- */
- bc = (volatile struct board_chan *)((ulong)memaddr + CHANSTRUCT);
+ bc = (struct board_chan *)(memaddr + CHANSTRUCT);
/* -------------------------------------------------------------------
The below assignment will set gd to point at the BEGINING of
@@ -1730,20 +1470,18 @@ static void post_fep_init(unsigned int crd)
pointer begins at 0xd10.
---------------------------------------------------------------------- */
- gd = (volatile struct global_data *)((ulong)memaddr + GLOBAL);
+ gd = (struct global_data *)(memaddr + GLOBAL);
/* --------------------------------------------------------------------
XEPORTS (address 0xc22) points at the number of channels the
card supports. (For 64XE, XI, XEM, and XR use 0xc02)
----------------------------------------------------------------------- */
- if (((bd->type == PCXEVE) | (bd->type == PCXE)) &&
- (*(ushort *)((ulong)memaddr + XEPORTS) < 3))
+ if ((bd->type == PCXEVE || bd->type == PCXE) && (readw(memaddr + XEPORTS) < 3))
shrinkmem = 1;
if (bd->type < PCIXEM)
if (!request_region((int)bd->port, 4, board_desc[bd->type]))
return;
-
memwinon(bd, 0);
/* --------------------------------------------------------------------
@@ -1753,17 +1491,16 @@ static void post_fep_init(unsigned int crd)
/* For every port on the card do ..... */
- for (i = 0; i < bd->numports; i++, ch++, bc++)
- { /* Begin for each port */
+ for (i = 0; i < bd->numports; i++, ch++, bc++) { /* Begin for each port */
+ unsigned long flags;
ch->brdchan = bc;
ch->mailbox = gd;
INIT_WORK(&ch->tqueue, do_softint, ch);
ch->board = &boards[crd];
- switch (bd->type)
- { /* Begin switch bd->type */
-
+ spin_lock_irqsave(&epca_lock, flags);
+ switch (bd->type) {
/* ----------------------------------------------------------------
Since some of the boards use different bitmaps for their
control signals we cannot hard code these values and retain
@@ -1796,14 +1533,12 @@ static void post_fep_init(unsigned int crd)
} /* End switch bd->type */
- if (boards[crd].altpin)
- {
+ if (boards[crd].altpin) {
ch->dsr = ch->m_dcd;
ch->dcd = ch->m_dsr;
ch->digiext.digi_flags |= DIGI_ALTPIN;
}
- else
- {
+ else {
ch->dcd = ch->m_dcd;
ch->dsr = ch->m_dsr;
}
@@ -1813,14 +1548,12 @@ static void post_fep_init(unsigned int crd)
ch->magic = EPCA_MAGIC;
ch->tty = NULL;
- if (shrinkmem)
- {
+ if (shrinkmem) {
fepcmd(ch, SETBUFFER, 32, 0, 0, 0);
shrinkmem = 0;
}
- switch (bd->type)
- { /* Begin switch bd->type */
+ switch (bd->type) {
case PCIXEM:
case PCIXRJ:
@@ -1878,13 +1611,13 @@ static void post_fep_init(unsigned int crd)
fepcmd(ch, SRXHWATER, (3 * ch->rxbufsize / 4), 0, 10, 0);
- bc->edelay = 100;
- bc->idata = 1;
+ writew(100, &bc->edelay);
+ writeb(1, &bc->idata);
- ch->startc = bc->startc;
- ch->stopc = bc->stopc;
- ch->startca = bc->startca;
- ch->stopca = bc->stopca;
+ ch->startc = readb(&bc->startc);
+ ch->stopc = readb(&bc->stopc);
+ ch->startca = readb(&bc->startca);
+ ch->stopca = readb(&bc->stopca);
ch->fepcflag = 0;
ch->fepiflag = 0;
@@ -1899,27 +1632,23 @@ static void post_fep_init(unsigned int crd)
ch->blocked_open = 0;
init_waitqueue_head(&ch->open_wait);
init_waitqueue_head(&ch->close_wait);
+
+ spin_unlock_irqrestore(&epca_lock, flags);
+
ch->tmp_buf = kmalloc(ch->txbufsize,GFP_KERNEL);
- if (!(ch->tmp_buf))
- {
+ if (!ch->tmp_buf) {
printk(KERN_ERR "POST FEP INIT : kmalloc failed for port 0x%x\n",i);
release_region((int)bd->port, 4);
while(i-- > 0)
kfree((ch--)->tmp_buf);
return;
- }
- else
+ } else
memset((void *)ch->tmp_buf,0,ch->txbufsize);
} /* End for each port */
printk(KERN_INFO
"Digi PC/Xx Driver V%s: %s I/O = 0x%lx Mem = 0x%lx Ports = %d\n",
VERSION, board_desc[bd->type], (long)bd->port, (long)bd->membase, bd->numports);
- sprintf(mesg,
- "Digi PC/Xx Driver V%s: %s I/O = 0x%lx Mem = 0x%lx Ports = %d\n",
- VERSION, board_desc[bd->type], (long)bd->port, (long)bd->membase, bd->numports);
- console_print(mesg);
-
memwinoff(bd, 0);
} /* End post_fep_init */
@@ -1943,9 +1672,6 @@ static void epcapoll(unsigned long ignored)
buffer empty) and acts on those events.
----------------------------------------------------------------------- */
- save_flags(flags);
- cli();
-
for (crd = 0; crd < num_cards; crd++)
{ /* Begin for each card */
@@ -1961,6 +1687,8 @@ static void epcapoll(unsigned long ignored)
some legacy boards.
---------------------------------------------------------------- */
+ spin_lock_irqsave(&epca_lock, flags);
+
assertmemoff(ch);
globalwinon(ch);
@@ -1970,21 +1698,19 @@ static void epcapoll(unsigned long ignored)
the transmit or receive queue.
------------------------------------------------------------------- */
- head = ch->mailbox->ein;
- tail = ch->mailbox->eout;
+ head = readw(&ch->mailbox->ein);
+ tail = readw(&ch->mailbox->eout);
/* If head isn't equal to tail we have an event */
if (head != tail)
doevent(crd);
-
memoff(ch);
- } /* End for each card */
+ spin_unlock_irqrestore(&epca_lock, flags);
+ } /* End for each card */
mod_timer(&epca_timer, jiffies + (HZ / 25));
-
- restore_flags(flags);
} /* End epcapoll */
/* --------------------- Begin doevent ------------------------ */
@@ -1992,53 +1718,42 @@ static void epcapoll(unsigned long ignored)
static void doevent(int crd)
{ /* Begin doevent */
- volatile unchar *eventbuf;
+ void *eventbuf;
struct channel *ch, *chan0;
static struct tty_struct *tty;
- volatile struct board_info *bd;
- volatile struct board_chan *bc;
- register volatile unsigned int tail, head;
- register int event, channel;
- register int mstat, lstat;
+ struct board_info *bd;
+ struct board_chan *bc;
+ unsigned int tail, head;
+ int event, channel;
+ int mstat, lstat;
/* -------------------------------------------------------------------
This subroutine is called by epcapoll when an event is detected
in the event queue. This routine responds to those events.
--------------------------------------------------------------------- */
-
bd = &boards[crd];
chan0 = card_ptr[crd];
epcaassert(chan0 <= &digi_channels[nbdevs - 1], "ch out of range");
-
assertgwinon(chan0);
-
- while ((tail = chan0->mailbox->eout) != (head = chan0->mailbox->ein))
+ while ((tail = readw(&chan0->mailbox->eout)) != (head = readw(&chan0->mailbox->ein)))
{ /* Begin while something in event queue */
-
assertgwinon(chan0);
-
- eventbuf = (volatile unchar *)bus_to_virt((ulong)(bd->re_map_membase + tail + ISTART));
-
+ eventbuf = bd->re_map_membase + tail + ISTART;
/* Get the channel the event occurred on */
- channel = eventbuf[0];
-
+ channel = readb(eventbuf);
/* Get the actual event code that occurred */
- event = eventbuf[1];
-
+ event = readb(eventbuf + 1);
/* ----------------------------------------------------------------
The two assignments below get the current modem status (mstat)
and the previous modem status (lstat). These are useful becuase
an event could signal a change in modem signals itself.
------------------------------------------------------------------- */
-
- mstat = eventbuf[2];
- lstat = eventbuf[3];
+ mstat = readb(eventbuf + 2);
+ lstat = readb(eventbuf + 3);
ch = chan0 + channel;
-
- if ((unsigned)channel >= bd->numports || !ch)
- {
+ if ((unsigned)channel >= bd->numports || !ch) {
if (channel >= bd->numports)
ch = chan0;
bc = ch->brdchan;
@@ -2048,97 +1763,53 @@ static void doevent(int crd)
if ((bc = ch->brdchan) == NULL)
goto next;
- if (event & DATA_IND)
- { /* Begin DATA_IND */
-
+ if (event & DATA_IND) { /* Begin DATA_IND */
receive_data(ch);
assertgwinon(ch);
-
} /* End DATA_IND */
/* else *//* Fix for DCD transition missed bug */
- if (event & MODEMCHG_IND)
- { /* Begin MODEMCHG_IND */
-
+ if (event & MODEMCHG_IND) { /* Begin MODEMCHG_IND */
/* A modem signal change has been indicated */
-
ch->imodem = mstat;
-
- if (ch->asyncflags & ASYNC_CHECK_CD)
- {
+ if (ch->asyncflags & ASYNC_CHECK_CD) {
if (mstat & ch->dcd) /* We are now receiving dcd */
wake_up_interruptible(&ch->open_wait);
else
pc_sched_event(ch, EPCA_EVENT_HANGUP); /* No dcd; hangup */
}
-
} /* End MODEMCHG_IND */
-
tty = ch->tty;
- if (tty)
- { /* Begin if valid tty */
-
- if (event & BREAK_IND)
- { /* Begin if BREAK_IND */
-
+ if (tty) { /* Begin if valid tty */
+ if (event & BREAK_IND) { /* Begin if BREAK_IND */
/* A break has been indicated */
-
tty->flip.count++;
*tty->flip.flag_buf_ptr++ = TTY_BREAK;
-
*tty->flip.char_buf_ptr++ = 0;
-
tty_schedule_flip(tty);
-
- } /* End if BREAK_IND */
- else
- if (event & LOWTX_IND)
- { /* Begin LOWTX_IND */
-
+ } else if (event & LOWTX_IND) { /* Begin LOWTX_IND */
if (ch->statusflags & LOWWAIT)
{ /* Begin if LOWWAIT */
-
ch->statusflags &= ~LOWWAIT;
tty_wakeup(tty);
wake_up_interruptible(&tty->write_wait);
-
} /* End if LOWWAIT */
-
- } /* End LOWTX_IND */
- else
- if (event & EMPTYTX_IND)
- { /* Begin EMPTYTX_IND */
-
+ } else if (event & EMPTYTX_IND) { /* Begin EMPTYTX_IND */
/* This event is generated by setup_empty_event */
-
ch->statusflags &= ~TXBUSY;
- if (ch->statusflags & EMPTYWAIT)
- { /* Begin if EMPTYWAIT */
-
+ if (ch->statusflags & EMPTYWAIT) { /* Begin if EMPTYWAIT */
ch->statusflags &= ~EMPTYWAIT;
tty_wakeup(tty);
-
wake_up_interruptible(&tty->write_wait);
-
} /* End if EMPTYWAIT */
-
} /* End EMPTYTX_IND */
-
} /* End if valid tty */
-
-
next:
globalwinon(ch);
-
- if (!bc)
- printk(KERN_ERR "<Error> - bc == NULL in doevent!\n");
- else
- bc->idata = 1;
-
- chan0->mailbox->eout = (tail + 4) & (IMAX - ISTART - 4);
+ BUG_ON(!bc);
+ writew(1, &bc->idata);
+ writew((tail + 4) & (IMAX - ISTART - 4), &chan0->mailbox->eout);
globalwinon(chan0);
-
} /* End while something in event queue */
-
} /* End doevent */
/* --------------------- Begin fepcmd ------------------------ */
@@ -2146,7 +1817,6 @@ static void doevent(int crd)
static void fepcmd(struct channel *ch, int cmd, int word_or_byte,
int byte2, int ncmds, int bytecmd)
{ /* Begin fepcmd */
-
unchar *memaddr;
unsigned int head, cmdTail, cmdStart, cmdMax;
long count;
@@ -2155,93 +1825,57 @@ static void fepcmd(struct channel *ch, int cmd, int word_or_byte,
/* This is the routine in which commands may be passed to the card. */
if (ch->board->status == DISABLED)
- {
return;
- }
-
assertgwinon(ch);
-
/* Remember head (As well as max) is just an offset not a base addr */
- head = ch->mailbox->cin;
-
+ head = readw(&ch->mailbox->cin);
/* cmdStart is a base address */
- cmdStart = ch->mailbox->cstart;
-
+ cmdStart = readw(&ch->mailbox->cstart);
/* ------------------------------------------------------------------
We do the addition below because we do not want a max pointer
relative to cmdStart. We want a max pointer that points at the
physical end of the command queue.
-------------------------------------------------------------------- */
-
- cmdMax = (cmdStart + 4 + (ch->mailbox->cmax));
-
+ cmdMax = (cmdStart + 4 + readw(&ch->mailbox->cmax));
memaddr = ch->board->re_map_membase;
- /*
- The below command is necessary because newer kernels (2.1.x and
- up) do not have a 1:1 virtual to physical mapping. The below
- call adjust for that.
- */
-
- memaddr = (unsigned char *)bus_to_virt((unsigned long)memaddr);
-
- if (head >= (cmdMax - cmdStart) || (head & 03))
- {
- printk(KERN_ERR "line %d: Out of range, cmd = %x, head = %x\n", __LINE__,
- cmd, head);
- printk(KERN_ERR "line %d: Out of range, cmdMax = %x, cmdStart = %x\n", __LINE__,
- cmdMax, cmdStart);
+ if (head >= (cmdMax - cmdStart) || (head & 03)) {
+ printk(KERN_ERR "line %d: Out of range, cmd = %x, head = %x\n", __LINE__, cmd, head);
+ printk(KERN_ERR "line %d: Out of range, cmdMax = %x, cmdStart = %x\n", __LINE__, cmdMax, cmdStart);
return;
}
-
- if (bytecmd)
- {
- *(volatile unchar *)(memaddr + head + cmdStart + 0) = (unchar)cmd;
-
- *(volatile unchar *)(memaddr + head + cmdStart + 1) = (unchar)ch->channelnum;
+ if (bytecmd) {
+ writeb(cmd, memaddr + head + cmdStart + 0);
+ writeb(ch->channelnum, memaddr + head + cmdStart + 1);
/* Below word_or_byte is bits to set */
- *(volatile unchar *)(memaddr + head + cmdStart + 2) = (unchar)word_or_byte;
+ writeb(word_or_byte, memaddr + head + cmdStart + 2);
/* Below byte2 is bits to reset */
- *(volatile unchar *)(memaddr + head + cmdStart + 3) = (unchar)byte2;
-
- }
- else
- {
- *(volatile unchar *)(memaddr + head + cmdStart + 0) = (unchar)cmd;
- *(volatile unchar *)(memaddr + head + cmdStart + 1) = (unchar)ch->channelnum;
- *(volatile ushort*)(memaddr + head + cmdStart + 2) = (ushort)word_or_byte;
+ writeb(byte2, memaddr + head + cmdStart + 3);
+ } else {
+ writeb(cmd, memaddr + head + cmdStart + 0);
+ writeb(ch->channelnum, memaddr + head + cmdStart + 1);
+ writeb(word_or_byte, memaddr + head + cmdStart + 2);
}
-
head = (head + 4) & (cmdMax - cmdStart - 4);
- ch->mailbox->cin = head;
-
+ writew(head, &ch->mailbox->cin);
count = FEPTIMEOUT;
- for (;;)
- { /* Begin forever loop */
-
+ for (;;) { /* Begin forever loop */
count--;
- if (count == 0)
- {
+ if (count == 0) {
printk(KERN_ERR "<Error> - Fep not responding in fepcmd()\n");
return;
}
-
- head = ch->mailbox->cin;
- cmdTail = ch->mailbox->cout;
-
+ head = readw(&ch->mailbox->cin);
+ cmdTail = readw(&ch->mailbox->cout);
n = (head - cmdTail) & (cmdMax - cmdStart - 4);
-
/* ----------------------------------------------------------
Basically this will break when the FEP acknowledges the
command by incrementing cmdTail (Making it equal to head).
------------------------------------------------------------- */
-
if (n <= ncmds * (sizeof(short) * 4))
break; /* Well nearly forever :-) */
-
} /* End forever loop */
-
} /* End fepcmd */
/* ---------------------------------------------------------------------
@@ -2255,11 +1889,9 @@ static void fepcmd(struct channel *ch, int cmd, int word_or_byte,
static unsigned termios2digi_h(struct channel *ch, unsigned cflag)
{ /* Begin termios2digi_h */
-
unsigned res = 0;
- if (cflag & CRTSCTS)
- {
+ if (cflag & CRTSCTS) {
ch->digiext.digi_flags |= (RTSPACE | CTSPACE);
res |= ((ch->m_cts) | (ch->m_rts));
}
@@ -2295,7 +1927,6 @@ static unsigned termios2digi_i(struct channel *ch, unsigned iflag)
unsigned res = iflag & (IGNBRK | BRKINT | IGNPAR | PARMRK |
INPCK | ISTRIP|IXON|IXANY|IXOFF);
-
if (ch->digiext.digi_flags & DIGI_AIXON)
res |= IAIXON;
return res;
@@ -2308,28 +1939,15 @@ static unsigned termios2digi_c(struct channel *ch, unsigned cflag)
{ /* Begin termios2digi_c */
unsigned res = 0;
-
-#ifdef SPEED_HACK
- /* CL: HACK to force 115200 at 38400 and 57600 at 19200 Baud */
- if ((cflag & CBAUD)== B38400) cflag=cflag - B38400 + B115200;
- if ((cflag & CBAUD)== B19200) cflag=cflag - B19200 + B57600;
-#endif /* SPEED_HACK */
-
- if (cflag & CBAUDEX)
- { /* Begin detected CBAUDEX */
-
+ if (cflag & CBAUDEX) { /* Begin detected CBAUDEX */
ch->digiext.digi_flags |= DIGI_FAST;
-
/* -------------------------------------------------------------
HUPCL bit is used by FEP to indicate fast baud
table is to be used.
----------------------------------------------------------------- */
-
res |= FEP_HUPCL;
-
} /* End detected CBAUDEX */
else ch->digiext.digi_flags &= ~DIGI_FAST;
-
/* -------------------------------------------------------------------
CBAUD has bit position 0x1000 set these days to indicate Linux
baud rate remap. Digi hardware can't handle the bit assignment.
@@ -2337,7 +1955,6 @@ static unsigned termios2digi_c(struct channel *ch, unsigned cflag)
bit out.
---------------------------------------------------------------------- */
res |= cflag & ((CBAUD ^ CBAUDEX) | PARODD | PARENB | CSTOPB | CSIZE);
-
/* -------------------------------------------------------------
This gets a little confusing. The Digi cards have their own
representation of c_cflags controling baud rate. For the most
@@ -2357,10 +1974,8 @@ static unsigned termios2digi_c(struct channel *ch, unsigned cflag)
should be checked for a screened out prior to termios2digi_c
returning. Since CLOCAL isn't used by the board this can be
ignored as long as the returned value is used only by Digi hardware.
- ----------------------------------------------------------------- */
-
- if (cflag & CBAUDEX)
- {
+ ----------------------------------------------------------------- */
+ if (cflag & CBAUDEX) {
/* -------------------------------------------------------------
The below code is trying to guarantee that only baud rates
115200 and 230400 are remapped. We use exclusive or because
@@ -2371,138 +1986,96 @@ static unsigned termios2digi_c(struct channel *ch, unsigned cflag)
if ((!((cflag & 0x7) ^ (B115200 & ~CBAUDEX))) ||
(!((cflag & 0x7) ^ (B230400 & ~CBAUDEX))))
- {
res += 1;
- }
}
-
return res;
} /* End termios2digi_c */
/* --------------------- Begin epcaparam ----------------------- */
+/* Caller must hold the locks */
static void epcaparam(struct tty_struct *tty, struct channel *ch)
{ /* Begin epcaparam */
unsigned int cmdHead;
struct termios *ts;
- volatile struct board_chan *bc;
+ struct board_chan *bc;
unsigned mval, hflow, cflag, iflag;
bc = ch->brdchan;
epcaassert(bc !=0, "bc out of range");
assertgwinon(ch);
-
ts = tty->termios;
-
- if ((ts->c_cflag & CBAUD) == 0)
- { /* Begin CBAUD detected */
-
- cmdHead = bc->rin;
+ if ((ts->c_cflag & CBAUD) == 0) { /* Begin CBAUD detected */
+ cmdHead = readw(&bc->rin);
bc->rout = cmdHead;
- cmdHead = bc->tin;
-
+ cmdHead = readw(&bc->tin);
/* Changing baud in mid-stream transmission can be wonderful */
/* ---------------------------------------------------------------
Flush current transmit buffer by setting cmdTail pointer (tout)
to cmdHead pointer (tin). Hopefully the transmit buffer is empty.
----------------------------------------------------------------- */
-
fepcmd(ch, STOUT, (unsigned) cmdHead, 0, 0, 0);
mval = 0;
-
- } /* End CBAUD detected */
- else
- { /* Begin CBAUD not detected */
-
+ } else { /* Begin CBAUD not detected */
/* -------------------------------------------------------------------
c_cflags have changed but that change had nothing to do with BAUD.
Propagate the change to the card.
---------------------------------------------------------------------- */
-
cflag = termios2digi_c(ch, ts->c_cflag);
-
- if (cflag != ch->fepcflag)
- {
+ if (cflag != ch->fepcflag) {
ch->fepcflag = cflag;
/* Set baud rate, char size, stop bits, parity */
fepcmd(ch, SETCTRLFLAGS, (unsigned) cflag, 0, 0, 0);
}
-
-
/* ----------------------------------------------------------------
If the user has not forced CLOCAL and if the device is not a
CALLOUT device (Which is always CLOCAL) we set flags such that
the driver will wait on carrier detect.
------------------------------------------------------------------- */
-
if (ts->c_cflag & CLOCAL)
- { /* Begin it is a cud device or a ttyD device with CLOCAL on */
ch->asyncflags &= ~ASYNC_CHECK_CD;
- } /* End it is a cud device or a ttyD device with CLOCAL on */
else
- { /* Begin it is a ttyD device */
ch->asyncflags |= ASYNC_CHECK_CD;
- } /* End it is a ttyD device */
-
mval = ch->m_dtr | ch->m_rts;
-
} /* End CBAUD not detected */
-
iflag = termios2digi_i(ch, ts->c_iflag);
-
/* Check input mode flags */
-
- if (iflag != ch->fepiflag)
- {
+ if (iflag != ch->fepiflag) {
ch->fepiflag = iflag;
-
/* ---------------------------------------------------------------
Command sets channels iflag structure on the board. Such things
as input soft flow control, handling of parity errors, and
break handling are all set here.
------------------------------------------------------------------- */
-
/* break handling, parity handling, input stripping, flow control chars */
fepcmd(ch, SETIFLAGS, (unsigned int) ch->fepiflag, 0, 0, 0);
}
-
/* ---------------------------------------------------------------
Set the board mint value for this channel. This will cause hardware
events to be generated each time the DCD signal (Described in mint)
changes.
------------------------------------------------------------------- */
- bc->mint = ch->dcd;
-
+ writeb(ch->dcd, &bc->mint);
if ((ts->c_cflag & CLOCAL) || (ch->digiext.digi_flags & DIGI_FORCEDCD))
if (ch->digiext.digi_flags & DIGI_FORCEDCD)
- bc->mint = 0;
-
- ch->imodem = bc->mstat;
-
+ writeb(0, &bc->mint);
+ ch->imodem = readb(&bc->mstat);
hflow = termios2digi_h(ch, ts->c_cflag);
-
- if (hflow != ch->hflow)
- {
+ if (hflow != ch->hflow) {
ch->hflow = hflow;
-
/* --------------------------------------------------------------
Hard flow control has been selected but the board is not
using it. Activate hard flow control now.
----------------------------------------------------------------- */
-
fepcmd(ch, SETHFLOW, hflow, 0xff, 0, 1);
}
-
-
mval ^= ch->modemfake & (mval ^ ch->modem);
- if (ch->omodem ^ mval)
- {
+ if (ch->omodem ^ mval) {
ch->omodem = mval;
-
/* --------------------------------------------------------------
The below command sets the DTR and RTS mstat structure. If
hard flow control is NOT active these changes will drive the
@@ -2514,87 +2087,65 @@ static void epcaparam(struct tty_struct *tty, struct channel *ch)
/* First reset DTR & RTS; then set them */
fepcmd(ch, SETMODEM, 0, ((ch->m_dtr)|(ch->m_rts)), 0, 1);
fepcmd(ch, SETMODEM, mval, 0, 0, 1);
-
}
-
- if (ch->startc != ch->fepstartc || ch->stopc != ch->fepstopc)
- {
+ if (ch->startc != ch->fepstartc || ch->stopc != ch->fepstopc) {
ch->fepstartc = ch->startc;
ch->fepstopc = ch->stopc;
-
/* ------------------------------------------------------------
The XON / XOFF characters have changed; propagate these
changes to the card.
--------------------------------------------------------------- */
-
fepcmd(ch, SONOFFC, ch->fepstartc, ch->fepstopc, 0, 1);
}
-
- if (ch->startca != ch->fepstartca || ch->stopca != ch->fepstopca)
- {
+ if (ch->startca != ch->fepstartca || ch->stopca != ch->fepstopca) {
ch->fepstartca = ch->startca;
ch->fepstopca = ch->stopca;
-
/* ---------------------------------------------------------------
Similar to the above, this time the auxilarly XON / XOFF
characters have changed; propagate these changes to the card.
------------------------------------------------------------------ */
-
fepcmd(ch, SAUXONOFFC, ch->fepstartca, ch->fepstopca, 0, 1);
}
-
} /* End epcaparam */
/* --------------------- Begin receive_data ----------------------- */
-
+/* Caller holds lock */
static void receive_data(struct channel *ch)
{ /* Begin receive_data */
unchar *rptr;
struct termios *ts = NULL;
struct tty_struct *tty;
- volatile struct board_chan *bc;
- register int dataToRead, wrapgap, bytesAvailable;
- register unsigned int tail, head;
+ struct board_chan *bc;
+ int dataToRead, wrapgap, bytesAvailable;
+ unsigned int tail, head;
unsigned int wrapmask;
int rc;
-
/* ---------------------------------------------------------------
This routine is called by doint when a receive data event
has taken place.
------------------------------------------------------------------- */
globalwinon(ch);
-
if (ch->statusflags & RXSTOPPED)
return;
-
tty = ch->tty;
if (tty)
ts = tty->termios;
-
bc = ch->brdchan;
-
- if (!bc)
- {
- printk(KERN_ERR "<Error> - bc is NULL in receive_data!\n");
- return;
- }
-
+ BUG_ON(!bc);
wrapmask = ch->rxbufsize - 1;
/* ---------------------------------------------------------------------
Get the head and tail pointers to the receiver queue. Wrap the
head pointer if it has reached the end of the buffer.
------------------------------------------------------------------------ */
-
- head = bc->rin;
+ head = readw(&bc->rin);
head &= wrapmask;
- tail = bc->rout & wrapmask;
+ tail = readw(&bc->rout) & wrapmask;
bytesAvailable = (head - tail) & wrapmask;
-
if (bytesAvailable == 0)
return;
@@ -2602,8 +2153,7 @@ static void receive_data(struct channel *ch)
If CREAD bit is off or device not open, set TX tail to head
--------------------------------------------------------------------- */
- if (!tty || !ts || !(ts->c_cflag & CREAD))
- {
+ if (!tty || !ts || !(ts->c_cflag & CREAD)) {
bc->rout = head;
return;
}
@@ -2611,64 +2161,45 @@ static void receive_data(struct channel *ch)
if (tty->flip.count == TTY_FLIPBUF_SIZE)
return;
- if (bc->orun)
- {
- bc->orun = 0;
- printk(KERN_WARNING "overrun! DigiBoard device %s\n",tty->name);
+ if (readb(&bc->orun)) {
+ writeb(0, &bc->orun);
+ printk(KERN_WARNING "epca; overrun! DigiBoard device %s\n",tty->name);
}
-
rxwinon(ch);
rptr = tty->flip.char_buf_ptr;
rc = tty->flip.count;
-
- while (bytesAvailable > 0)
- { /* Begin while there is data on the card */
-
+ while (bytesAvailable > 0) { /* Begin while there is data on the card */
wrapgap = (head >= tail) ? head - tail : ch->rxbufsize - tail;
-
/* ---------------------------------------------------------------
Even if head has wrapped around only report the amount of
data to be equal to the size - tail. Remember memcpy can't
automaticly wrap around the receive buffer.
----------------------------------------------------------------- */
-
dataToRead = (wrapgap < bytesAvailable) ? wrapgap : bytesAvailable;
-
/* --------------------------------------------------------------
Make sure we don't overflow the buffer
----------------------------------------------------------------- */
-
if ((rc + dataToRead) > TTY_FLIPBUF_SIZE)
dataToRead = TTY_FLIPBUF_SIZE - rc;
-
if (dataToRead == 0)
break;
-
/* ---------------------------------------------------------------
Move data read from our card into the line disciplines buffer
for translation if necessary.
------------------------------------------------------------------ */
-
- if ((memcpy(rptr, ch->rxptr + tail, dataToRead)) != rptr)
- printk(KERN_ERR "<Error> - receive_data : memcpy failed\n");
-
+ memcpy_fromio(rptr, ch->rxptr + tail, dataToRead);
rc += dataToRead;
rptr += dataToRead;
tail = (tail + dataToRead) & wrapmask;
bytesAvailable -= dataToRead;
-
} /* End while there is data on the card */
-
-
tty->flip.count = rc;
tty->flip.char_buf_ptr = rptr;
globalwinon(ch);
- bc->rout = tail;
-
+ writew(tail, &bc->rout);
/* Must be called with global data */
tty_schedule_flip(ch->tty);
return;
-
} /* End receive_data */
static int info_ioctl(struct tty_struct *tty, struct file * file,
@@ -2676,17 +2207,15 @@ static int info_ioctl(struct tty_struct *tty, struct file * file,
{
switch (cmd)
{ /* Begin switch cmd */
-
case DIGI_GETINFO:
{ /* Begin case DIGI_GETINFO */
-
struct digi_info di ;
int brd;
- getUser(brd, (unsigned int __user *)arg);
-
- if ((brd < 0) || (brd >= num_cards) || (num_cards == 0))
- return (-ENODEV);
+ if(get_user(brd, (unsigned int __user *)arg))
+ return -EFAULT;
+ if (brd < 0 || brd >= num_cards || num_cards == 0)
+ return -ENODEV;
memset(&di, 0, sizeof(di));
@@ -2694,8 +2223,9 @@ static int info_ioctl(struct tty_struct *tty, struct file * file,
di.status = boards[brd].status;
di.type = boards[brd].type ;
di.numports = boards[brd].numports ;
- di.port = boards[brd].port ;
- di.membase = boards[brd].membase ;
+ /* Legacy fixups - just move along nothing to see */
+ di.port = (unsigned char *)boards[brd].port ;
+ di.membase = (unsigned char *)boards[brd].membase ;
if (copy_to_user((void __user *)arg, &di, sizeof (di)))
return -EFAULT;
@@ -2709,39 +2239,29 @@ static int info_ioctl(struct tty_struct *tty, struct file * file,
int brd = arg & 0xff000000 >> 16 ;
unsigned char state = arg & 0xff ;
- if ((brd < 0) || (brd >= num_cards))
- {
- printk(KERN_ERR "<Error> - DIGI POLLER : brd not valid!\n");
+ if (brd < 0 || brd >= num_cards) {
+ printk(KERN_ERR "epca: DIGI POLLER : brd not valid!\n");
return (-ENODEV);
}
-
digi_poller_inhibited = state ;
break ;
-
} /* End case DIGI_POLLER */
case DIGI_INIT:
{ /* Begin case DIGI_INIT */
-
/* ------------------------------------------------------------
This call is made by the apps to complete the initilization
of the board(s). This routine is responsible for setting
the card to its initial state and setting the drivers control
fields to the sutianle settings for the card in question.
---------------------------------------------------------------- */
-
int crd ;
for (crd = 0; crd < num_cards; crd++)
post_fep_init (crd);
-
break ;
-
} /* End case DIGI_INIT */
-
-
default:
- return -ENOIOCTLCMD;
-
+ return -ENOTTY;
} /* End switch cmd */
return (0) ;
}
@@ -2750,43 +2270,33 @@ static int info_ioctl(struct tty_struct *tty, struct file * file,
static int pc_tiocmget(struct tty_struct *tty, struct file *file)
{
struct channel *ch = (struct channel *) tty->driver_data;
- volatile struct board_chan *bc;
+ struct board_chan *bc;
unsigned int mstat, mflag = 0;
unsigned long flags;
if (ch)
bc = ch->brdchan;
else
- {
- printk(KERN_ERR "<Error> - ch is NULL in pc_tiocmget!\n");
- return(-EINVAL);
- }
+ return -EINVAL;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&epca_lock, flags);
globalwinon(ch);
- mstat = bc->mstat;
+ mstat = readb(&bc->mstat);
memoff(ch);
- restore_flags(flags);
+ spin_unlock_irqrestore(&epca_lock, flags);
if (mstat & ch->m_dtr)
mflag |= TIOCM_DTR;
-
if (mstat & ch->m_rts)
mflag |= TIOCM_RTS;
-
if (mstat & ch->m_cts)
mflag |= TIOCM_CTS;
-
if (mstat & ch->dsr)
mflag |= TIOCM_DSR;
-
if (mstat & ch->m_ri)
mflag |= TIOCM_RI;
-
if (mstat & ch->dcd)
mflag |= TIOCM_CD;
-
return mflag;
}
@@ -2796,13 +2306,10 @@ static int pc_tiocmset(struct tty_struct *tty, struct file *file,
struct channel *ch = (struct channel *) tty->driver_data;
unsigned long flags;
- if (!ch) {
- printk(KERN_ERR "<Error> - ch is NULL in pc_tiocmset!\n");
- return(-EINVAL);
- }
+ if (!ch)
+ return -EINVAL;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&epca_lock, flags);
/*
* I think this modemfake stuff is broken. It doesn't
* correctly reflect the behaviour desired by the TIOCM*
@@ -2824,17 +2331,14 @@ static int pc_tiocmset(struct tty_struct *tty, struct file *file,
ch->modemfake |= ch->m_dtr;
ch->modem &= ~ch->m_dtr;
}
-
globalwinon(ch);
-
/* --------------------------------------------------------------
The below routine generally sets up parity, baud, flow control
issues, etc.... It effect both control flags and input flags.
------------------------------------------------------------------ */
-
epcaparam(tty,ch);
memoff(ch);
- restore_flags(flags);
+ spin_unlock_irqrestore(&epca_lock, flags);
return 0;
}
@@ -2847,19 +2351,14 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file,
unsigned long flags;
unsigned int mflag, mstat;
unsigned char startc, stopc;
- volatile struct board_chan *bc;
+ struct board_chan *bc;
struct channel *ch = (struct channel *) tty->driver_data;
void __user *argp = (void __user *)arg;
if (ch)
bc = ch->brdchan;
else
- {
- printk(KERN_ERR "<Error> - ch is NULL in pc_ioctl!\n");
- return(-EINVAL);
- }
-
- save_flags(flags);
+ return -EINVAL;
/* -------------------------------------------------------------------
For POSIX compliance we need to add more ioctls. See tty_ioctl.c
@@ -2871,46 +2370,39 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file,
{ /* Begin switch cmd */
case TCGETS:
- if (copy_to_user(argp,
- tty->termios, sizeof(struct termios)))
+ if (copy_to_user(argp, tty->termios, sizeof(struct termios)))
return -EFAULT;
- return(0);
-
+ return 0;
case TCGETA:
return get_termio(tty, argp);
-
case TCSBRK: /* SVID version: non-zero arg --> no break */
-
retval = tty_check_change(tty);
if (retval)
return retval;
-
/* Setup an event to indicate when the transmit buffer empties */
-
+ spin_lock_irqsave(&epca_lock, flags);
setup_empty_event(tty,ch);
+ spin_unlock_irqrestore(&epca_lock, flags);
tty_wait_until_sent(tty, 0);
if (!arg)
digi_send_break(ch, HZ/4); /* 1/4 second */
return 0;
-
case TCSBRKP: /* support for POSIX tcsendbreak() */
-
retval = tty_check_change(tty);
if (retval)
return retval;
/* Setup an event to indicate when the transmit buffer empties */
-
+ spin_lock_irqsave(&epca_lock, flags);
setup_empty_event(tty,ch);
+ spin_unlock_irqrestore(&epca_lock, flags);
tty_wait_until_sent(tty, 0);
digi_send_break(ch, arg ? arg*(HZ/10) : HZ/4);
return 0;
-
case TIOCGSOFTCAR:
if (put_user(C_CLOCAL(tty)?1:0, (unsigned long __user *)arg))
return -EFAULT;
return 0;
-
case TIOCSSOFTCAR:
{
unsigned int value;
@@ -2922,75 +2414,63 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file,
(value ? CLOCAL : 0));
return 0;
}
-
case TIOCMODG:
mflag = pc_tiocmget(tty, file);
if (put_user(mflag, (unsigned long __user *)argp))
return -EFAULT;
break;
-
case TIOCMODS:
if (get_user(mstat, (unsigned __user *)argp))
return -EFAULT;
return pc_tiocmset(tty, file, mstat, ~mstat);
-
case TIOCSDTR:
+ spin_lock_irqsave(&epca_lock, flags);
ch->omodem |= ch->m_dtr;
- cli();
globalwinon(ch);
fepcmd(ch, SETMODEM, ch->m_dtr, 0, 10, 1);
memoff(ch);
- restore_flags(flags);
+ spin_unlock_irqrestore(&epca_lock, flags);
break;
case TIOCCDTR:
+ spin_lock_irqsave(&epca_lock, flags);
ch->omodem &= ~ch->m_dtr;
- cli();
globalwinon(ch);
fepcmd(ch, SETMODEM, 0, ch->m_dtr, 10, 1);
memoff(ch);
- restore_flags(flags);
+ spin_unlock_irqrestore(&epca_lock, flags);
break;
-
case DIGI_GETA:
if (copy_to_user(argp, &ch->digiext, sizeof(digi_t)))
return -EFAULT;
break;
-
case DIGI_SETAW:
case DIGI_SETAF:
- if ((cmd) == (DIGI_SETAW))
- {
+ if (cmd == DIGI_SETAW) {
/* Setup an event to indicate when the transmit buffer empties */
-
+ spin_lock_irqsave(&epca_lock, flags);
setup_empty_event(tty,ch);
+ spin_unlock_irqrestore(&epca_lock, flags);
tty_wait_until_sent(tty, 0);
- }
- else
- {
+ } else {
/* ldisc lock already held in ioctl */
if (tty->ldisc.flush_buffer)
tty->ldisc.flush_buffer(tty);
}
-
/* Fall Thru */
-
case DIGI_SETA:
if (copy_from_user(&ch->digiext, argp, sizeof(digi_t)))
return -EFAULT;
- if (ch->digiext.digi_flags & DIGI_ALTPIN)
- {
+ if (ch->digiext.digi_flags & DIGI_ALTPIN) {
ch->dcd = ch->m_dsr;
ch->dsr = ch->m_dcd;
- }
- else
- {
+ } else {
ch->dcd = ch->m_dcd;
ch->dsr = ch->m_dsr;
}
- cli();
+ spin_lock_irqsave(&epca_lock, flags);
globalwinon(ch);
/* -----------------------------------------------------------------
@@ -3000,25 +2480,22 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file,
epcaparam(tty,ch);
memoff(ch);
- restore_flags(flags);
+ spin_unlock_irqrestore(&epca_lock, flags);
break;
case DIGI_GETFLOW:
case DIGI_GETAFLOW:
- cli();
+ spin_lock_irqsave(&epca_lock, flags);
globalwinon(ch);
- if ((cmd) == (DIGI_GETFLOW))
- {
- dflow.startc = bc->startc;
- dflow.stopc = bc->stopc;
- }
- else
- {
- dflow.startc = bc->startca;
- dflow.stopc = bc->stopca;
+ if (cmd == DIGI_GETFLOW) {
+ dflow.startc = readb(&bc->startc);
+ dflow.stopc = readb(&bc->stopc);
+ } else {
+ dflow.startc = readb(&bc->startca);
+ dflow.stopc = readb(&bc->stopca);
}
memoff(ch);
- restore_flags(flags);
+ spin_unlock_irqrestore(&epca_lock, flags);
if (copy_to_user(argp, &dflow, sizeof(dflow)))
return -EFAULT;
@@ -3026,13 +2503,10 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file,
case DIGI_SETAFLOW:
case DIGI_SETFLOW:
- if ((cmd) == (DIGI_SETFLOW))
- {
+ if (cmd == DIGI_SETFLOW) {
startc = ch->startc;
stopc = ch->stopc;
- }
- else
- {
+ } else {
startc = ch->startca;
stopc = ch->stopca;
}
@@ -3040,40 +2514,31 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file,
if (copy_from_user(&dflow, argp, sizeof(dflow)))
return -EFAULT;
- if (dflow.startc != startc || dflow.stopc != stopc)
- { /* Begin if setflow toggled */
- cli();
+ if (dflow.startc != startc || dflow.stopc != stopc) { /* Begin if setflow toggled */
+ spin_lock_irqsave(&epca_lock, flags);
globalwinon(ch);
- if ((cmd) == (DIGI_SETFLOW))
- {
+ if (cmd == DIGI_SETFLOW) {
ch->fepstartc = ch->startc = dflow.startc;
ch->fepstopc = ch->stopc = dflow.stopc;
fepcmd(ch, SONOFFC, ch->fepstartc, ch->fepstopc, 0, 1);
- }
- else
- {
+ } else {
ch->fepstartca = ch->startca = dflow.startc;
ch->fepstopca = ch->stopca = dflow.stopc;
fepcmd(ch, SAUXONOFFC, ch->fepstartca, ch->fepstopca, 0, 1);
}
- if (ch->statusflags & TXSTOPPED)
+ if (ch->statusflags & TXSTOPPED)
pc_start(tty);
memoff(ch);
- restore_flags(flags);
-
+ spin_unlock_irqrestore(&epca_lock, flags);
} /* End if setflow toggled */
break;
-
default:
return -ENOIOCTLCMD;
-
} /* End switch cmd */
-
return 0;
-
} /* End pc_ioctl */
/* --------------------- Begin pc_set_termios ----------------------- */
@@ -3083,20 +2548,16 @@ static void pc_set_termios(struct tty_struct *tty, struct termios *old_termios)
struct channel *ch;
unsigned long flags;
-
/* ---------------------------------------------------------
verifyChannel returns the channel from the tty struct
if it is valid. This serves as a sanity check.
------------------------------------------------------------- */
-
- if ((ch = verifyChannel(tty)) != NULL)
- { /* Begin if channel valid */
-
- save_flags(flags);
- cli();
+ if ((ch = verifyChannel(tty)) != NULL) { /* Begin if channel valid */
+ spin_lock_irqsave(&epca_lock, flags);
globalwinon(ch);
epcaparam(tty, ch);
memoff(ch);
+ spin_unlock_irqrestore(&epca_lock, flags);
if ((old_termios->c_cflag & CRTSCTS) &&
((tty->termios->c_cflag & CRTSCTS) == 0))
@@ -3106,8 +2567,6 @@ static void pc_set_termios(struct tty_struct *tty, struct termios *old_termios)
(tty->termios->c_cflag & CLOCAL))
wake_up_interruptible(&ch->open_wait);
- restore_flags(flags);
-
} /* End if channel valid */
} /* End pc_set_termios */
@@ -3116,29 +2575,18 @@ static void pc_set_termios(struct tty_struct *tty, struct termios *old_termios)
static void do_softint(void *private_)
{ /* Begin do_softint */
-
struct channel *ch = (struct channel *) private_;
-
-
/* Called in response to a modem change event */
-
- if (ch && ch->magic == EPCA_MAGIC)
- { /* Begin EPCA_MAGIC */
-
+ if (ch && ch->magic == EPCA_MAGIC) { /* Begin EPCA_MAGIC */
struct tty_struct *tty = ch->tty;
- if (tty && tty->driver_data)
- {
- if (test_and_clear_bit(EPCA_EVENT_HANGUP, &ch->event))
- { /* Begin if clear_bit */
-
+ if (tty && tty->driver_data) {
+ if (test_and_clear_bit(EPCA_EVENT_HANGUP, &ch->event)) { /* Begin if clear_bit */
tty_hangup(tty); /* FIXME: module removal race here - AKPM */
wake_up_interruptible(&ch->open_wait);
ch->asyncflags &= ~ASYNC_NORMAL_ACTIVE;
-
} /* End if clear_bit */
}
-
} /* End EPCA_MAGIC */
} /* End do_softint */
@@ -3154,82 +2602,49 @@ static void pc_stop(struct tty_struct *tty)
struct channel *ch;
unsigned long flags;
-
/* ---------------------------------------------------------
verifyChannel returns the channel from the tty struct
if it is valid. This serves as a sanity check.
------------------------------------------------------------- */
-
- if ((ch = verifyChannel(tty)) != NULL)
- { /* Begin if valid channel */
-
- save_flags(flags);
- cli();
-
- if ((ch->statusflags & TXSTOPPED) == 0)
- { /* Begin if transmit stop requested */
-
+ if ((ch = verifyChannel(tty)) != NULL) { /* Begin if valid channel */
+ spin_lock_irqsave(&epca_lock, flags);
+ if ((ch->statusflags & TXSTOPPED) == 0) { /* Begin if transmit stop requested */
globalwinon(ch);
-
/* STOP transmitting now !! */
-
fepcmd(ch, PAUSETX, 0, 0, 0, 0);
-
ch->statusflags |= TXSTOPPED;
memoff(ch);
-
} /* End if transmit stop requested */
-
- restore_flags(flags);
-
+ spin_unlock_irqrestore(&epca_lock, flags);
} /* End if valid channel */
-
} /* End pc_stop */
/* --------------------- Begin pc_start ----------------------- */
static void pc_start(struct tty_struct *tty)
{ /* Begin pc_start */
-
struct channel *ch;
-
/* ---------------------------------------------------------
verifyChannel returns the channel from the tty struct
if it is valid. This serves as a sanity check.
------------------------------------------------------------- */
-
- if ((ch = verifyChannel(tty)) != NULL)
- { /* Begin if channel valid */
-
+ if ((ch = verifyChannel(tty)) != NULL) { /* Begin if channel valid */
unsigned long flags;
-
- save_flags(flags);
- cli();
-
+ spin_lock_irqsave(&epca_lock, flags);
/* Just in case output was resumed because of a change in Digi-flow */
- if (ch->statusflags & TXSTOPPED)
- { /* Begin transmit resume requested */
-
- volatile struct board_chan *bc;
-
+ if (ch->statusflags & TXSTOPPED) { /* Begin transmit resume requested */
+ struct board_chan *bc;
globalwinon(ch);
bc = ch->brdchan;
if (ch->statusflags & LOWWAIT)
- bc->ilow = 1;
-
+ writeb(1, &bc->ilow);
/* Okay, you can start transmitting again... */
-
fepcmd(ch, RESUMETX, 0, 0, 0, 0);
-
ch->statusflags &= ~TXSTOPPED;
memoff(ch);
-
} /* End transmit resume requested */
-
- restore_flags(flags);
-
+ spin_unlock_irqrestore(&epca_lock, flags);
} /* End if channel valid */
-
} /* End pc_start */
/* ------------------------------------------------------------------
@@ -3244,86 +2659,55 @@ ______________________________________________________________________ */
static void pc_throttle(struct tty_struct * tty)
{ /* Begin pc_throttle */
-
struct channel *ch;
unsigned long flags;
-
/* ---------------------------------------------------------
verifyChannel returns the channel from the tty struct
if it is valid. This serves as a sanity check.
------------------------------------------------------------- */
-
- if ((ch = verifyChannel(tty)) != NULL)
- { /* Begin if channel valid */
-
-
- save_flags(flags);
- cli();
-
- if ((ch->statusflags & RXSTOPPED) == 0)
- {
+ if ((ch = verifyChannel(tty)) != NULL) { /* Begin if channel valid */
+ spin_lock_irqsave(&epca_lock, flags);
+ if ((ch->statusflags & RXSTOPPED) == 0) {
globalwinon(ch);
fepcmd(ch, PAUSERX, 0, 0, 0, 0);
-
ch->statusflags |= RXSTOPPED;
memoff(ch);
}
- restore_flags(flags);
-
+ spin_unlock_irqrestore(&epca_lock, flags);
} /* End if channel valid */
-
} /* End pc_throttle */
/* --------------------- Begin unthrottle ----------------------- */
static void pc_unthrottle(struct tty_struct *tty)
{ /* Begin pc_unthrottle */
-
struct channel *ch;
unsigned long flags;
- volatile struct board_chan *bc;
-
-
/* ---------------------------------------------------------
verifyChannel returns the channel from the tty struct
if it is valid. This serves as a sanity check.
------------------------------------------------------------- */
-
- if ((ch = verifyChannel(tty)) != NULL)
- { /* Begin if channel valid */
-
-
+ if ((ch = verifyChannel(tty)) != NULL) { /* Begin if channel valid */
/* Just in case output was resumed because of a change in Digi-flow */
- save_flags(flags);
- cli();
-
- if (ch->statusflags & RXSTOPPED)
- {
-
+ spin_lock_irqsave(&epca_lock, flags);
+ if (ch->statusflags & RXSTOPPED) {
globalwinon(ch);
- bc = ch->brdchan;
fepcmd(ch, RESUMERX, 0, 0, 0, 0);
-
ch->statusflags &= ~RXSTOPPED;
memoff(ch);
}
- restore_flags(flags);
-
+ spin_unlock_irqrestore(&epca_lock, flags);
} /* End if channel valid */
-
} /* End pc_unthrottle */
/* --------------------- Begin digi_send_break ----------------------- */
void digi_send_break(struct channel *ch, int msec)
{ /* Begin digi_send_break */
-
unsigned long flags;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&epca_lock, flags);
globalwinon(ch);
-
/* --------------------------------------------------------------------
Maybe I should send an infinite break here, schedule() for
msec amount of time, and then stop the break. This way,
@@ -3331,36 +2715,28 @@ void digi_send_break(struct channel *ch, int msec)
to be called (i.e. via an ioctl()) more than once in msec amount
of time. Try this for now...
------------------------------------------------------------------------ */
-
fepcmd(ch, SENDBREAK, msec, 0, 10, 0);
memoff(ch);
-
- restore_flags(flags);
-
+ spin_unlock_irqrestore(&epca_lock, flags);
} /* End digi_send_break */
/* --------------------- Begin setup_empty_event ----------------------- */
+/* Caller MUST hold the lock */
+
static void setup_empty_event(struct tty_struct *tty, struct channel *ch)
{ /* Begin setup_empty_event */
- volatile struct board_chan *bc = ch->brdchan;
- unsigned long int flags;
+ struct board_chan *bc = ch->brdchan;
- save_flags(flags);
- cli();
globalwinon(ch);
ch->statusflags |= EMPTYWAIT;
-
/* ------------------------------------------------------------------
When set the iempty flag request a event to be generated when the
transmit buffer is empty (If there is no BREAK in progress).
--------------------------------------------------------------------- */
-
- bc->iempty = 1;
+ writeb(1, &bc->iempty);
memoff(ch);
- restore_flags(flags);
-
} /* End setup_empty_event */
/* --------------------- Begin get_termio ----------------------- */
@@ -3369,10 +2745,10 @@ static int get_termio(struct tty_struct * tty, struct termio __user * termio)
{ /* Begin get_termio */
return kernel_termios_to_user_termio(termio, tty->termios);
} /* End get_termio */
+
/* ---------------------- Begin epca_setup -------------------------- */
void epca_setup(char *str, int *ints)
{ /* Begin epca_setup */
-
struct board_info board;
int index, loop, last;
char *temp, *t2;
@@ -3394,49 +2770,41 @@ void epca_setup(char *str, int *ints)
for (last = 0, index = 1; index <= ints[0]; index++)
switch(index)
{ /* Begin parse switch */
-
case 1:
board.status = ints[index];
-
/* ---------------------------------------------------------
We check for 2 (As opposed to 1; because 2 is a flag
instructing the driver to ignore epcaconfig.) For this
reason we check for 2.
------------------------------------------------------------ */
- if (board.status == 2)
- { /* Begin ignore epcaconfig as well as lilo cmd line */
+ if (board.status == 2) { /* Begin ignore epcaconfig as well as lilo cmd line */
nbdevs = 0;
num_cards = 0;
return;
} /* End ignore epcaconfig as well as lilo cmd line */
- if (board.status > 2)
- {
- printk(KERN_ERR "<Error> - epca_setup: Invalid board status 0x%x\n", board.status);
+ if (board.status > 2) {
+ printk(KERN_ERR "epca_setup: Invalid board status 0x%x\n", board.status);
invalid_lilo_config = 1;
setup_error_code |= INVALID_BOARD_STATUS;
return;
}
last = index;
break;
-
case 2:
board.type = ints[index];
- if (board.type >= PCIXEM)
- {
- printk(KERN_ERR "<Error> - epca_setup: Invalid board type 0x%x\n", board.type);
+ if (board.type >= PCIXEM) {
+ printk(KERN_ERR "epca_setup: Invalid board type 0x%x\n", board.type);
invalid_lilo_config = 1;
setup_error_code |= INVALID_BOARD_TYPE;
return;
}
last = index;
break;
-
case 3:
board.altpin = ints[index];
- if (board.altpin > 1)
- {
- printk(KERN_ERR "<Error> - epca_setup: Invalid board altpin 0x%x\n", board.altpin);
+ if (board.altpin > 1) {
+ printk(KERN_ERR "epca_setup: Invalid board altpin 0x%x\n", board.altpin);
invalid_lilo_config = 1;
setup_error_code |= INVALID_ALTPIN;
return;
@@ -3446,9 +2814,8 @@ void epca_setup(char *str, int *ints)
case 4:
board.numports = ints[index];
- if ((board.numports < 2) || (board.numports > 256))
- {
- printk(KERN_ERR "<Error> - epca_setup: Invalid board numports 0x%x\n", board.numports);
+ if (board.numports < 2 || board.numports > 256) {
+ printk(KERN_ERR "epca_setup: Invalid board numports 0x%x\n", board.numports);
invalid_lilo_config = 1;
setup_error_code |= INVALID_NUM_PORTS;
return;
@@ -3458,10 +2825,9 @@ void epca_setup(char *str, int *ints)
break;
case 5:
- board.port = (unsigned char *)ints[index];
- if (ints[index] <= 0)
- {
- printk(KERN_ERR "<Error> - epca_setup: Invalid io port 0x%x\n", (unsigned int)board.port);
+ board.port = ints[index];
+ if (ints[index] <= 0) {
+ printk(KERN_ERR "epca_setup: Invalid io port 0x%x\n", (unsigned int)board.port);
invalid_lilo_config = 1;
setup_error_code |= INVALID_PORT_BASE;
return;
@@ -3470,10 +2836,9 @@ void epca_setup(char *str, int *ints)
break;
case 6:
- board.membase = (unsigned char *)ints[index];
- if (ints[index] <= 0)
- {
- printk(KERN_ERR "<Error> - epca_setup: Invalid memory base 0x%x\n",(unsigned int)board.membase);
+ board.membase = ints[index];
+ if (ints[index] <= 0) {
+ printk(KERN_ERR "epca_setup: Invalid memory base 0x%x\n",(unsigned int)board.membase);
invalid_lilo_config = 1;
setup_error_code |= INVALID_MEM_BASE;
return;
@@ -3487,21 +2852,16 @@ void epca_setup(char *str, int *ints)
} /* End parse switch */
- while (str && *str)
- { /* Begin while there is a string arg */
-
+ while (str && *str) { /* Begin while there is a string arg */
/* find the next comma or terminator */
temp = str;
-
/* While string is not null, and a comma hasn't been found */
while (*temp && (*temp != ','))
temp++;
-
if (!*temp)
temp = NULL;
else
*temp++ = 0;
-
/* Set index to the number of args + 1 */
index = last + 1;
@@ -3511,12 +2871,10 @@ void epca_setup(char *str, int *ints)
len = strlen(str);
if (strncmp("Disable", str, len) == 0)
board.status = 0;
- else
- if (strncmp("Enable", str, len) == 0)
+ else if (strncmp("Enable", str, len) == 0)
board.status = 1;
- else
- {
- printk(KERN_ERR "<Error> - epca_setup: Invalid status %s\n", str);
+ else {
+ printk(KERN_ERR "epca_setup: Invalid status %s\n", str);
invalid_lilo_config = 1;
setup_error_code |= INVALID_BOARD_STATUS;
return;
@@ -3525,22 +2883,17 @@ void epca_setup(char *str, int *ints)
break;
case 2:
-
for(loop = 0; loop < EPCA_NUM_TYPES; loop++)
if (strcmp(board_desc[loop], str) == 0)
break;
-
-
/* ---------------------------------------------------------------
If the index incremented above refers to a legitamate board
type set it here.
------------------------------------------------------------------*/
-
if (index < EPCA_NUM_TYPES)
board.type = loop;
- else
- {
- printk(KERN_ERR "<Error> - epca_setup: Invalid board type: %s\n", str);
+ else {
+ printk(KERN_ERR "epca_setup: Invalid board type: %s\n", str);
invalid_lilo_config = 1;
setup_error_code |= INVALID_BOARD_TYPE;
return;
@@ -3552,12 +2905,10 @@ void epca_setup(char *str, int *ints)
len = strlen(str);
if (strncmp("Disable", str, len) == 0)
board.altpin = 0;
- else
- if (strncmp("Enable", str, len) == 0)
+ else if (strncmp("Enable", str, len) == 0)
board.altpin = 1;
- else
- {
- printk(KERN_ERR "<Error> - epca_setup: Invalid altpin %s\n", str);
+ else {
+ printk(KERN_ERR "epca_setup: Invalid altpin %s\n", str);
invalid_lilo_config = 1;
setup_error_code |= INVALID_ALTPIN;
return;
@@ -3570,9 +2921,8 @@ void epca_setup(char *str, int *ints)
while (isdigit(*t2))
t2++;
- if (*t2)
- {
- printk(KERN_ERR "<Error> - epca_setup: Invalid port count %s\n", str);
+ if (*t2) {
+ printk(KERN_ERR "epca_setup: Invalid port count %s\n", str);
invalid_lilo_config = 1;
setup_error_code |= INVALID_NUM_PORTS;
return;
@@ -3601,15 +2951,14 @@ void epca_setup(char *str, int *ints)
while (isxdigit(*t2))
t2++;
- if (*t2)
- {
- printk(KERN_ERR "<Error> - epca_setup: Invalid i/o address %s\n", str);
+ if (*t2) {
+ printk(KERN_ERR "epca_setup: Invalid i/o address %s\n", str);
invalid_lilo_config = 1;
setup_error_code |= INVALID_PORT_BASE;
return;
}
- board.port = (unsigned char *)simple_strtoul(str, NULL, 16);
+ board.port = simple_strtoul(str, NULL, 16);
last = index;
break;
@@ -3618,52 +2967,38 @@ void epca_setup(char *str, int *ints)
while (isxdigit(*t2))
t2++;
- if (*t2)
- {
- printk(KERN_ERR "<Error> - epca_setup: Invalid memory base %s\n",str);
+ if (*t2) {
+ printk(KERN_ERR "epca_setup: Invalid memory base %s\n",str);
invalid_lilo_config = 1;
setup_error_code |= INVALID_MEM_BASE;
return;
}
-
- board.membase = (unsigned char *)simple_strtoul(str, NULL, 16);
+ board.membase = simple_strtoul(str, NULL, 16);
last = index;
break;
-
default:
- printk(KERN_ERR "PC/Xx: Too many string parms\n");
+ printk(KERN_ERR "epca: Too many string parms\n");
return;
}
str = temp;
-
} /* End while there is a string arg */
-
- if (last < 6)
- {
- printk(KERN_ERR "PC/Xx: Insufficient parms specified\n");
+ if (last < 6) {
+ printk(KERN_ERR "epca: Insufficient parms specified\n");
return;
}
/* I should REALLY validate the stuff here */
-
/* Copies our local copy of board into boards */
memcpy((void *)&boards[num_cards],(void *)&board, sizeof(board));
-
-
/* Does this get called once per lilo arg are what ? */
-
printk(KERN_INFO "PC/Xx: Added board %i, %s %i ports at 0x%4.4X base 0x%6.6X\n",
num_cards, board_desc[board.type],
board.numports, (int)board.port, (unsigned int) board.membase);
-
num_cards++;
-
} /* End epca_setup */
-
-#ifdef ENABLE_PCI
/* ------------------------ Begin init_PCI --------------------------- */
enum epic_board_types {
@@ -3685,7 +3020,6 @@ static struct {
{ PCIXRJ, 2, },
};
-
static int __devinit epca_init_one (struct pci_dev *pdev,
const struct pci_device_id *ent)
{
@@ -3711,10 +3045,8 @@ static int __devinit epca_init_one (struct pci_dev *pdev,
boards[board_idx].status = ENABLED;
boards[board_idx].type = epca_info_tbl[info_idx].board_type;
boards[board_idx].numports = 0x0;
- boards[board_idx].port =
- (unsigned char *)((char *) addr + PCI_IO_OFFSET);
- boards[board_idx].membase =
- (unsigned char *)((char *) addr);
+ boards[board_idx].port = addr + PCI_IO_OFFSET;
+ boards[board_idx].membase = addr;
if (!request_mem_region (addr + PCI_IO_OFFSET, 0x200000, "epca")) {
printk (KERN_ERR PFX "resource 0x%x @ 0x%lx unavailable\n",
@@ -3775,15 +3107,13 @@ static struct pci_device_id epca_pci_tbl[] = {
MODULE_DEVICE_TABLE(pci, epca_pci_tbl);
int __init init_PCI (void)
-{ /* Begin init_PCI */
+{ /* Begin init_PCI */
memset (&epca_driver, 0, sizeof (epca_driver));
epca_driver.name = "epca";
epca_driver.id_table = epca_pci_tbl;
epca_driver.probe = epca_init_one;
return pci_register_driver(&epca_driver);
-} /* End init_PCI */
-
-#endif /* ENABLE_PCI */
+}
MODULE_LICENSE("GPL");
diff --git a/drivers/char/epca.h b/drivers/char/epca.h
index 52205ef71314..20eeb5a70e1a 100644
--- a/drivers/char/epca.h
+++ b/drivers/char/epca.h
@@ -85,73 +85,73 @@ static char *board_desc[] =
struct channel
{
long magic;
- unchar boardnum;
- unchar channelnum;
- unchar omodem; /* FEP output modem status */
- unchar imodem; /* FEP input modem status */
- unchar modemfake; /* Modem values to be forced */
- unchar modem; /* Force values */
- unchar hflow;
- unchar dsr;
- unchar dcd;
- unchar m_rts ; /* The bits used in whatever FEP */
- unchar m_dcd ; /* is indiginous to this board to */
- unchar m_dsr ; /* represent each of the physical */
- unchar m_cts ; /* handshake lines */
- unchar m_ri ;
- unchar m_dtr ;
- unchar stopc;
- unchar startc;
- unchar stopca;
- unchar startca;
- unchar fepstopc;
- unchar fepstartc;
- unchar fepstopca;
- unchar fepstartca;
- unchar txwin;
- unchar rxwin;
- ushort fepiflag;
- ushort fepcflag;
- ushort fepoflag;
- ushort txbufhead;
- ushort txbufsize;
- ushort rxbufhead;
- ushort rxbufsize;
+ unsigned char boardnum;
+ unsigned char channelnum;
+ unsigned char omodem; /* FEP output modem status */
+ unsigned char imodem; /* FEP input modem status */
+ unsigned char modemfake; /* Modem values to be forced */
+ unsigned char modem; /* Force values */
+ unsigned char hflow;
+ unsigned char dsr;
+ unsigned char dcd;
+ unsigned char m_rts ; /* The bits used in whatever FEP */
+ unsigned char m_dcd ; /* is indiginous to this board to */
+ unsigned char m_dsr ; /* represent each of the physical */
+ unsigned char m_cts ; /* handshake lines */
+ unsigned char m_ri ;
+ unsigned char m_dtr ;
+ unsigned char stopc;
+ unsigned char startc;
+ unsigned char stopca;
+ unsigned char startca;
+ unsigned char fepstopc;
+ unsigned char fepstartc;
+ unsigned char fepstopca;
+ unsigned char fepstartca;
+ unsigned char txwin;
+ unsigned char rxwin;
+ unsigned short fepiflag;
+ unsigned short fepcflag;
+ unsigned short fepoflag;
+ unsigned short txbufhead;
+ unsigned short txbufsize;
+ unsigned short rxbufhead;
+ unsigned short rxbufsize;
int close_delay;
int count;
int blocked_open;
- ulong event;
+ unsigned long event;
int asyncflags;
uint dev;
- ulong statusflags;
- ulong c_iflag;
- ulong c_cflag;
- ulong c_lflag;
- ulong c_oflag;
- unchar *txptr;
- unchar *rxptr;
- unchar *tmp_buf;
+ unsigned long statusflags;
+ unsigned long c_iflag;
+ unsigned long c_cflag;
+ unsigned long c_lflag;
+ unsigned long c_oflag;
+ unsigned char *txptr;
+ unsigned char *rxptr;
+ unsigned char *tmp_buf;
struct board_info *board;
- volatile struct board_chan *brdchan;
+ struct board_chan *brdchan;
struct digi_struct digiext;
struct tty_struct *tty;
wait_queue_head_t open_wait;
wait_queue_head_t close_wait;
- struct work_struct tqueue;
- volatile struct global_data *mailbox;
+ struct work_struct tqueue;
+ struct global_data *mailbox;
};
struct board_info
{
- unchar status;
- unchar type;
- unchar altpin;
- ushort numports;
- unchar *port;
- unchar *membase;
- unchar __iomem *re_map_port;
- unchar *re_map_membase;
- ulong memory_seg;
+ unsigned char status;
+ unsigned char type;
+ unsigned char altpin;
+ unsigned short numports;
+ unsigned long port;
+ unsigned long membase;
+ unsigned char __iomem *re_map_port;
+ unsigned char *re_map_membase;
+ unsigned long memory_seg;
void ( * memwinon ) (struct board_info *, unsigned int) ;
void ( * memwinoff ) (struct board_info *, unsigned int) ;
void ( * globalwinon ) (struct channel *) ;
@@ -160,6 +160,6 @@ struct board_info
void ( * memoff ) (struct channel *) ;
void ( * assertgwinon ) (struct channel *) ;
void ( * assertmemoff ) (struct channel *) ;
- unchar poller_inhibited ;
+ unsigned char poller_inhibited ;
};
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c
index 762fa430fb5b..a695f25e4497 100644
--- a/drivers/char/hpet.c
+++ b/drivers/char/hpet.c
@@ -44,7 +44,7 @@
/*
* The High Precision Event Timer driver.
* This driver is closely modelled after the rtc.c driver.
- * http://www.intel.com/labs/platcomp/hpet/hpetspec.htm
+ * http://www.intel.com/hardwaredesign/hpetspec.htm
*/
#define HPET_USER_FREQ (64)
#define HPET_DRIFT (500)
@@ -712,7 +712,7 @@ static void hpet_register_interpolator(struct hpets *hpetp)
ti->shift = 10;
ti->addr = &hpetp->hp_hpet->hpet_mc;
ti->frequency = hpet_time_div(hpets->hp_period);
- ti->drift = ti->frequency * HPET_DRIFT / 1000000;
+ ti->drift = HPET_DRIFT;
ti->mask = -1;
hpetp->hp_interpolator = ti;
diff --git a/drivers/char/ipmi/ipmi_bt_sm.c b/drivers/char/ipmi/ipmi_bt_sm.c
index 5ce9c6269033..33862670e285 100644
--- a/drivers/char/ipmi/ipmi_bt_sm.c
+++ b/drivers/char/ipmi/ipmi_bt_sm.c
@@ -31,8 +31,6 @@
#include <linux/ipmi_msgdefs.h> /* for completion codes */
#include "ipmi_si_sm.h"
-#define IPMI_BT_VERSION "v33"
-
static int bt_debug = 0x00; /* Production value 0, see following flags */
#define BT_DEBUG_ENABLE 1
@@ -163,7 +161,8 @@ static int bt_start_transaction(struct si_sm_data *bt,
{
unsigned int i;
- if ((size < 2) || (size > IPMI_MAX_MSG_LENGTH)) return -1;
+ if ((size < 2) || (size > IPMI_MAX_MSG_LENGTH))
+ return -1;
if ((bt->state != BT_STATE_IDLE) && (bt->state != BT_STATE_HOSED))
return -2;
@@ -171,7 +170,8 @@ static int bt_start_transaction(struct si_sm_data *bt,
if (bt_debug & BT_DEBUG_MSG) {
printk(KERN_WARNING "+++++++++++++++++++++++++++++++++++++\n");
printk(KERN_WARNING "BT: write seq=0x%02X:", bt->seq);
- for (i = 0; i < size; i ++) printk (" %02x", data[i]);
+ for (i = 0; i < size; i ++)
+ printk (" %02x", data[i]);
printk("\n");
}
bt->write_data[0] = size + 1; /* all data plus seq byte */
@@ -210,15 +210,18 @@ static int bt_get_result(struct si_sm_data *bt,
} else {
data[0] = bt->read_data[1];
data[1] = bt->read_data[3];
- if (length < msg_len) bt->truncated = 1;
+ if (length < msg_len)
+ bt->truncated = 1;
if (bt->truncated) { /* can be set in read_all_bytes() */
data[2] = IPMI_ERR_MSG_TRUNCATED;
msg_len = 3;
- } else memcpy(data + 2, bt->read_data + 4, msg_len - 2);
+ } else
+ memcpy(data + 2, bt->read_data + 4, msg_len - 2);
if (bt_debug & BT_DEBUG_MSG) {
printk (KERN_WARNING "BT: res (raw)");
- for (i = 0; i < msg_len; i++) printk(" %02x", data[i]);
+ for (i = 0; i < msg_len; i++)
+ printk(" %02x", data[i]);
printk ("\n");
}
}
@@ -231,8 +234,10 @@ static int bt_get_result(struct si_sm_data *bt,
static void reset_flags(struct si_sm_data *bt)
{
- if (BT_STATUS & BT_H_BUSY) BT_CONTROL(BT_H_BUSY);
- if (BT_STATUS & BT_B_BUSY) BT_CONTROL(BT_B_BUSY);
+ if (BT_STATUS & BT_H_BUSY)
+ BT_CONTROL(BT_H_BUSY);
+ if (BT_STATUS & BT_B_BUSY)
+ BT_CONTROL(BT_B_BUSY);
BT_CONTROL(BT_CLR_WR_PTR);
BT_CONTROL(BT_SMS_ATN);
#ifdef DEVELOPMENT_ONLY_NOT_FOR_PRODUCTION
@@ -241,7 +246,8 @@ static void reset_flags(struct si_sm_data *bt)
BT_CONTROL(BT_H_BUSY);
BT_CONTROL(BT_B2H_ATN);
BT_CONTROL(BT_CLR_RD_PTR);
- for (i = 0; i < IPMI_MAX_MSG_LENGTH + 2; i++) BMC2HOST;
+ for (i = 0; i < IPMI_MAX_MSG_LENGTH + 2; i++)
+ BMC2HOST;
BT_CONTROL(BT_H_BUSY);
}
#endif
@@ -258,7 +264,8 @@ static inline void write_all_bytes(struct si_sm_data *bt)
printk (" %02x", bt->write_data[i]);
printk ("\n");
}
- for (i = 0; i < bt->write_count; i++) HOST2BMC(bt->write_data[i]);
+ for (i = 0; i < bt->write_count; i++)
+ HOST2BMC(bt->write_data[i]);
}
static inline int read_all_bytes(struct si_sm_data *bt)
@@ -278,7 +285,8 @@ static inline int read_all_bytes(struct si_sm_data *bt)
bt->truncated = 1;
return 1; /* let next XACTION START clean it up */
}
- for (i = 1; i <= bt->read_count; i++) bt->read_data[i] = BMC2HOST;
+ for (i = 1; i <= bt->read_count; i++)
+ bt->read_data[i] = BMC2HOST;
bt->read_count++; /* account for the length byte */
if (bt_debug & BT_DEBUG_MSG) {
@@ -295,7 +303,8 @@ static inline int read_all_bytes(struct si_sm_data *bt)
((bt->read_data[1] & 0xF8) == (bt->write_data[1] & 0xF8)))
return 1;
- if (bt_debug & BT_DEBUG_MSG) printk(KERN_WARNING "BT: bad packet: "
+ if (bt_debug & BT_DEBUG_MSG)
+ printk(KERN_WARNING "BT: bad packet: "
"want 0x(%02X, %02X, %02X) got (%02X, %02X, %02X)\n",
bt->write_data[1], bt->write_data[2], bt->write_data[3],
bt->read_data[1], bt->read_data[2], bt->read_data[3]);
@@ -359,7 +368,8 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time)
time);
bt->last_state = bt->state;
- if (bt->state == BT_STATE_HOSED) return SI_SM_HOSED;
+ if (bt->state == BT_STATE_HOSED)
+ return SI_SM_HOSED;
if (bt->state != BT_STATE_IDLE) { /* do timeout test */
@@ -371,7 +381,8 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time)
/* FIXME: bt_event is sometimes called with time > BT_NORMAL_TIMEOUT
(noticed in ipmi_smic_sm.c January 2004) */
- if ((time <= 0) || (time >= BT_NORMAL_TIMEOUT)) time = 100;
+ if ((time <= 0) || (time >= BT_NORMAL_TIMEOUT))
+ time = 100;
bt->timeout -= time;
if ((bt->timeout < 0) && (bt->state < BT_STATE_RESET1)) {
error_recovery(bt, "timed out");
@@ -393,12 +404,14 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time)
BT_CONTROL(BT_H_BUSY);
break;
}
- if (status & BT_B2H_ATN) break;
+ if (status & BT_B2H_ATN)
+ break;
bt->state = BT_STATE_WRITE_BYTES;
return SI_SM_CALL_WITHOUT_DELAY; /* for logging */
case BT_STATE_WRITE_BYTES:
- if (status & (BT_B_BUSY | BT_H2B_ATN)) break;
+ if (status & (BT_B_BUSY | BT_H2B_ATN))
+ break;
BT_CONTROL(BT_CLR_WR_PTR);
write_all_bytes(bt);
BT_CONTROL(BT_H2B_ATN); /* clears too fast to catch? */
@@ -406,7 +419,8 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time)
return SI_SM_CALL_WITHOUT_DELAY; /* it MIGHT sail through */
case BT_STATE_WRITE_CONSUME: /* BMCs usually blow right thru here */
- if (status & (BT_H2B_ATN | BT_B_BUSY)) break;
+ if (status & (BT_H2B_ATN | BT_B_BUSY))
+ break;
bt->state = BT_STATE_B2H_WAIT;
/* fall through with status */
@@ -415,15 +429,18 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time)
generation of B2H_ATN so ALWAYS return CALL_WITH_DELAY. */
case BT_STATE_B2H_WAIT:
- if (!(status & BT_B2H_ATN)) break;
+ if (!(status & BT_B2H_ATN))
+ break;
/* Assume ordered, uncached writes: no need to wait */
- if (!(status & BT_H_BUSY)) BT_CONTROL(BT_H_BUSY); /* set */
+ if (!(status & BT_H_BUSY))
+ BT_CONTROL(BT_H_BUSY); /* set */
BT_CONTROL(BT_B2H_ATN); /* clear it, ACK to the BMC */
BT_CONTROL(BT_CLR_RD_PTR); /* reset the queue */
i = read_all_bytes(bt);
BT_CONTROL(BT_H_BUSY); /* clear */
- if (!i) break; /* Try this state again */
+ if (!i) /* Try this state again */
+ break;
bt->state = BT_STATE_READ_END;
return SI_SM_CALL_WITHOUT_DELAY; /* for logging */
@@ -436,7 +453,8 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time)
#ifdef MAKE_THIS_TRUE_IF_NECESSARY
- if (status & BT_H_BUSY) break;
+ if (status & BT_H_BUSY)
+ break;
#endif
bt->seq++;
bt->state = BT_STATE_IDLE;
@@ -459,7 +477,8 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time)
break;
case BT_STATE_RESET3:
- if (bt->timeout > 0) return SI_SM_CALL_WITH_DELAY;
+ if (bt->timeout > 0)
+ return SI_SM_CALL_WITH_DELAY;
bt->state = BT_STATE_RESTART; /* printk in debug modes */
break;
@@ -485,7 +504,8 @@ static int bt_detect(struct si_sm_data *bt)
but that's what you get from reading a bogus address, so we
test that first. The calling routine uses negative logic. */
- if ((BT_STATUS == 0xFF) && (BT_INTMASK_R == 0xFF)) return 1;
+ if ((BT_STATUS == 0xFF) && (BT_INTMASK_R == 0xFF))
+ return 1;
reset_flags(bt);
return 0;
}
@@ -501,7 +521,6 @@ static int bt_size(void)
struct si_sm_handlers bt_smi_handlers =
{
- .version = IPMI_BT_VERSION,
.init_data = bt_init_data,
.start_transaction = bt_start_transaction,
.get_result = bt_get_result,
diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c
index e0a53570fea1..883ac4352be4 100644
--- a/drivers/char/ipmi/ipmi_devintf.c
+++ b/drivers/char/ipmi/ipmi_devintf.c
@@ -47,8 +47,6 @@
#include <linux/device.h>
#include <linux/compat.h>
-#define IPMI_DEVINTF_VERSION "v33"
-
struct ipmi_file_private
{
ipmi_user_t user;
@@ -411,6 +409,7 @@ static int ipmi_ioctl(struct inode *inode,
break;
}
+ /* The next four are legacy, not per-channel. */
case IPMICTL_SET_MY_ADDRESS_CMD:
{
unsigned int val;
@@ -420,22 +419,25 @@ static int ipmi_ioctl(struct inode *inode,
break;
}
- ipmi_set_my_address(priv->user, val);
- rv = 0;
+ rv = ipmi_set_my_address(priv->user, 0, val);
break;
}
case IPMICTL_GET_MY_ADDRESS_CMD:
{
- unsigned int val;
+ unsigned int val;
+ unsigned char rval;
+
+ rv = ipmi_get_my_address(priv->user, 0, &rval);
+ if (rv)
+ break;
- val = ipmi_get_my_address(priv->user);
+ val = rval;
if (copy_to_user(arg, &val, sizeof(val))) {
rv = -EFAULT;
break;
}
- rv = 0;
break;
}
@@ -448,24 +450,94 @@ static int ipmi_ioctl(struct inode *inode,
break;
}
- ipmi_set_my_LUN(priv->user, val);
- rv = 0;
+ rv = ipmi_set_my_LUN(priv->user, 0, val);
break;
}
case IPMICTL_GET_MY_LUN_CMD:
{
- unsigned int val;
+ unsigned int val;
+ unsigned char rval;
- val = ipmi_get_my_LUN(priv->user);
+ rv = ipmi_get_my_LUN(priv->user, 0, &rval);
+ if (rv)
+ break;
+
+ val = rval;
+
+ if (copy_to_user(arg, &val, sizeof(val))) {
+ rv = -EFAULT;
+ break;
+ }
+ break;
+ }
+
+ case IPMICTL_SET_MY_CHANNEL_ADDRESS_CMD:
+ {
+ struct ipmi_channel_lun_address_set val;
+
+ if (copy_from_user(&val, arg, sizeof(val))) {
+ rv = -EFAULT;
+ break;
+ }
+
+ return ipmi_set_my_address(priv->user, val.channel, val.value);
+ break;
+ }
+
+ case IPMICTL_GET_MY_CHANNEL_ADDRESS_CMD:
+ {
+ struct ipmi_channel_lun_address_set val;
+
+ if (copy_from_user(&val, arg, sizeof(val))) {
+ rv = -EFAULT;
+ break;
+ }
+
+ rv = ipmi_get_my_address(priv->user, val.channel, &val.value);
+ if (rv)
+ break;
+
+ if (copy_to_user(arg, &val, sizeof(val))) {
+ rv = -EFAULT;
+ break;
+ }
+ break;
+ }
+
+ case IPMICTL_SET_MY_CHANNEL_LUN_CMD:
+ {
+ struct ipmi_channel_lun_address_set val;
+
+ if (copy_from_user(&val, arg, sizeof(val))) {
+ rv = -EFAULT;
+ break;
+ }
+
+ rv = ipmi_set_my_LUN(priv->user, val.channel, val.value);
+ break;
+ }
+
+ case IPMICTL_GET_MY_CHANNEL_LUN_CMD:
+ {
+ struct ipmi_channel_lun_address_set val;
+
+ if (copy_from_user(&val, arg, sizeof(val))) {
+ rv = -EFAULT;
+ break;
+ }
+
+ rv = ipmi_get_my_LUN(priv->user, val.channel, &val.value);
+ if (rv)
+ break;
if (copy_to_user(arg, &val, sizeof(val))) {
rv = -EFAULT;
break;
}
- rv = 0;
break;
}
+
case IPMICTL_SET_TIMING_PARMS_CMD:
{
struct ipmi_timing_parms parms;
@@ -748,8 +820,7 @@ static __init int init_ipmi_devintf(void)
if (ipmi_major < 0)
return -EINVAL;
- printk(KERN_INFO "ipmi device interface version "
- IPMI_DEVINTF_VERSION "\n");
+ printk(KERN_INFO "ipmi device interface\n");
ipmi_class = class_create(THIS_MODULE, "ipmi");
if (IS_ERR(ipmi_class)) {
@@ -792,3 +863,5 @@ static __exit void cleanup_ipmi(void)
module_exit(cleanup_ipmi);
MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>");
+MODULE_DESCRIPTION("Linux device interface for the IPMI message handler.");
diff --git a/drivers/char/ipmi/ipmi_kcs_sm.c b/drivers/char/ipmi/ipmi_kcs_sm.c
index 48cce24329be..d21853a594a3 100644
--- a/drivers/char/ipmi/ipmi_kcs_sm.c
+++ b/drivers/char/ipmi/ipmi_kcs_sm.c
@@ -42,8 +42,6 @@
#include <linux/ipmi_msgdefs.h> /* for completion codes */
#include "ipmi_si_sm.h"
-#define IPMI_KCS_VERSION "v33"
-
/* Set this if you want a printout of why the state machine was hosed
when it gets hosed. */
#define DEBUG_HOSED_REASON
@@ -489,7 +487,6 @@ static void kcs_cleanup(struct si_sm_data *kcs)
struct si_sm_handlers kcs_smi_handlers =
{
- .version = IPMI_KCS_VERSION,
.init_data = init_kcs_data,
.start_transaction = start_kcs_transaction,
.get_result = get_kcs_result,
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
index e16c13fe698d..463351d4f942 100644
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -47,7 +47,8 @@
#include <linux/proc_fs.h>
#define PFX "IPMI message handler: "
-#define IPMI_MSGHANDLER_VERSION "v33"
+
+#define IPMI_DRIVER_VERSION "36.0"
static struct ipmi_recv_msg *ipmi_alloc_recv_msg(void);
static int ipmi_init_msghandler(void);
@@ -116,7 +117,7 @@ struct seq_table
do { \
seq = ((msgid >> 26) & 0x3f); \
seqid = (msgid & 0x3fffff); \
- } while(0)
+ } while (0)
#define NEXT_SEQID(seqid) (((seqid) + 1) & 0x3fffff)
@@ -124,6 +125,14 @@ struct ipmi_channel
{
unsigned char medium;
unsigned char protocol;
+
+ /* My slave address. This is initialized to IPMI_BMC_SLAVE_ADDR,
+ but may be changed by the user. */
+ unsigned char address;
+
+ /* My LUN. This should generally stay the SMS LUN, but just in
+ case... */
+ unsigned char lun;
};
#ifdef CONFIG_PROC_FS
@@ -135,7 +144,7 @@ struct ipmi_proc_entry
#endif
#define IPMI_IPMB_NUM_SEQ 64
-#define IPMI_MAX_CHANNELS 8
+#define IPMI_MAX_CHANNELS 16
struct ipmi_smi
{
/* What interface number are we? */
@@ -193,20 +202,6 @@ struct ipmi_smi
struct list_head waiting_events;
unsigned int waiting_events_count; /* How many events in queue? */
- /* This will be non-null if someone registers to receive all
- IPMI commands (this is for interface emulation). There
- may not be any things in the cmd_rcvrs list above when
- this is registered. */
- ipmi_user_t all_cmd_rcvr;
-
- /* My slave address. This is initialized to IPMI_BMC_SLAVE_ADDR,
- but may be changed by the user. */
- unsigned char my_address;
-
- /* My LUN. This should generally stay the SMS LUN, but just in
- case... */
- unsigned char my_lun;
-
/* The event receiver for my BMC, only really used at panic
shutdown as a place to store this. */
unsigned char event_receiver;
@@ -218,7 +213,7 @@ struct ipmi_smi
interface comes in with a NULL user, call this routine with
it. Note that the message will still be freed by the
caller. This only works on the system interface. */
- void (*null_user_handler)(ipmi_smi_t intf, struct ipmi_smi_msg *msg);
+ void (*null_user_handler)(ipmi_smi_t intf, struct ipmi_recv_msg *msg);
/* When we are scanning the channels for an SMI, this will
tell which channel we are scanning. */
@@ -325,7 +320,7 @@ int ipmi_smi_watcher_register(struct ipmi_smi_watcher *watcher)
down_read(&interfaces_sem);
down_write(&smi_watchers_sem);
list_add(&(watcher->link), &smi_watchers);
- for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+ for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
if (ipmi_interfaces[i] != NULL) {
watcher->new_smi(i);
}
@@ -458,7 +453,27 @@ unsigned int ipmi_addr_length(int addr_type)
static void deliver_response(struct ipmi_recv_msg *msg)
{
- msg->user->handler->ipmi_recv_hndl(msg, msg->user->handler_data);
+ if (! msg->user) {
+ ipmi_smi_t intf = msg->user_msg_data;
+ unsigned long flags;
+
+ /* Special handling for NULL users. */
+ if (intf->null_user_handler) {
+ intf->null_user_handler(intf, msg);
+ spin_lock_irqsave(&intf->counter_lock, flags);
+ intf->handled_local_responses++;
+ spin_unlock_irqrestore(&intf->counter_lock, flags);
+ } else {
+ /* No handler, so give up. */
+ spin_lock_irqsave(&intf->counter_lock, flags);
+ intf->unhandled_local_responses++;
+ spin_unlock_irqrestore(&intf->counter_lock, flags);
+ }
+ ipmi_free_recv_msg(msg);
+ } else {
+ msg->user->handler->ipmi_recv_hndl(msg,
+ msg->user->handler_data);
+ }
}
/* Find the next sequence number not being used and add the given
@@ -475,9 +490,9 @@ static int intf_next_seq(ipmi_smi_t intf,
int rv = 0;
unsigned int i;
- for (i=intf->curr_seq;
+ for (i = intf->curr_seq;
(i+1)%IPMI_IPMB_NUM_SEQ != intf->curr_seq;
- i=(i+1)%IPMI_IPMB_NUM_SEQ)
+ i = (i+1)%IPMI_IPMB_NUM_SEQ)
{
if (! intf->seq_table[i].inuse)
break;
@@ -712,7 +727,7 @@ static int ipmi_destroy_user_nolock(ipmi_user_t user)
/* Remove the user from the interfaces sequence table. */
spin_lock_irqsave(&(user->intf->seq_lock), flags);
- for (i=0; i<IPMI_IPMB_NUM_SEQ; i++) {
+ for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) {
if (user->intf->seq_table[i].inuse
&& (user->intf->seq_table[i].recv_msg->user == user))
{
@@ -766,26 +781,44 @@ void ipmi_get_version(ipmi_user_t user,
*minor = user->intf->version_minor;
}
-void ipmi_set_my_address(ipmi_user_t user,
- unsigned char address)
+int ipmi_set_my_address(ipmi_user_t user,
+ unsigned int channel,
+ unsigned char address)
{
- user->intf->my_address = address;
+ if (channel >= IPMI_MAX_CHANNELS)
+ return -EINVAL;
+ user->intf->channels[channel].address = address;
+ return 0;
}
-unsigned char ipmi_get_my_address(ipmi_user_t user)
+int ipmi_get_my_address(ipmi_user_t user,
+ unsigned int channel,
+ unsigned char *address)
{
- return user->intf->my_address;
+ if (channel >= IPMI_MAX_CHANNELS)
+ return -EINVAL;
+ *address = user->intf->channels[channel].address;
+ return 0;
}
-void ipmi_set_my_LUN(ipmi_user_t user,
- unsigned char LUN)
+int ipmi_set_my_LUN(ipmi_user_t user,
+ unsigned int channel,
+ unsigned char LUN)
{
- user->intf->my_lun = LUN & 0x3;
+ if (channel >= IPMI_MAX_CHANNELS)
+ return -EINVAL;
+ user->intf->channels[channel].lun = LUN & 0x3;
+ return 0;
}
-unsigned char ipmi_get_my_LUN(ipmi_user_t user)
+int ipmi_get_my_LUN(ipmi_user_t user,
+ unsigned int channel,
+ unsigned char *address)
{
- return user->intf->my_lun;
+ if (channel >= IPMI_MAX_CHANNELS)
+ return -EINVAL;
+ *address = user->intf->channels[channel].lun;
+ return 0;
}
int ipmi_set_gets_events(ipmi_user_t user, int val)
@@ -828,11 +861,6 @@ int ipmi_register_for_cmd(ipmi_user_t user,
read_lock(&(user->intf->users_lock));
write_lock_irqsave(&(user->intf->cmd_rcvr_lock), flags);
- if (user->intf->all_cmd_rcvr != NULL) {
- rv = -EBUSY;
- goto out_unlock;
- }
-
/* Make sure the command/netfn is not already registered. */
list_for_each_entry(cmp, &(user->intf->cmd_rcvrs), link) {
if ((cmp->netfn == netfn) && (cmp->cmd == cmd)) {
@@ -847,7 +875,7 @@ int ipmi_register_for_cmd(ipmi_user_t user,
rcvr->user = user;
list_add_tail(&(rcvr->link), &(user->intf->cmd_rcvrs));
}
- out_unlock:
+
write_unlock_irqrestore(&(user->intf->cmd_rcvr_lock), flags);
read_unlock(&(user->intf->users_lock));
@@ -1213,7 +1241,7 @@ static inline int i_ipmi_request(ipmi_user_t user,
unsigned char ipmb_seq;
long seqid;
- if (addr->channel > IPMI_NUM_CHANNELS) {
+ if (addr->channel >= IPMI_NUM_CHANNELS) {
spin_lock_irqsave(&intf->counter_lock, flags);
intf->sent_invalid_commands++;
spin_unlock_irqrestore(&intf->counter_lock, flags);
@@ -1331,7 +1359,7 @@ static inline int i_ipmi_request(ipmi_user_t user,
#ifdef DEBUG_MSGING
{
int m;
- for (m=0; m<smi_msg->data_size; m++)
+ for (m = 0; m < smi_msg->data_size; m++)
printk(" %2.2x", smi_msg->data[m]);
printk("\n");
}
@@ -1346,6 +1374,18 @@ static inline int i_ipmi_request(ipmi_user_t user,
return rv;
}
+static int check_addr(ipmi_smi_t intf,
+ struct ipmi_addr *addr,
+ unsigned char *saddr,
+ unsigned char *lun)
+{
+ if (addr->channel >= IPMI_MAX_CHANNELS)
+ return -EINVAL;
+ *lun = intf->channels[addr->channel].lun;
+ *saddr = intf->channels[addr->channel].address;
+ return 0;
+}
+
int ipmi_request_settime(ipmi_user_t user,
struct ipmi_addr *addr,
long msgid,
@@ -1355,6 +1395,14 @@ int ipmi_request_settime(ipmi_user_t user,
int retries,
unsigned int retry_time_ms)
{
+ unsigned char saddr, lun;
+ int rv;
+
+ if (! user)
+ return -EINVAL;
+ rv = check_addr(user->intf, addr, &saddr, &lun);
+ if (rv)
+ return rv;
return i_ipmi_request(user,
user->intf,
addr,
@@ -1363,8 +1411,8 @@ int ipmi_request_settime(ipmi_user_t user,
user_msg_data,
NULL, NULL,
priority,
- user->intf->my_address,
- user->intf->my_lun,
+ saddr,
+ lun,
retries,
retry_time_ms);
}
@@ -1378,6 +1426,14 @@ int ipmi_request_supply_msgs(ipmi_user_t user,
struct ipmi_recv_msg *supplied_recv,
int priority)
{
+ unsigned char saddr, lun;
+ int rv;
+
+ if (! user)
+ return -EINVAL;
+ rv = check_addr(user->intf, addr, &saddr, &lun);
+ if (rv)
+ return rv;
return i_ipmi_request(user,
user->intf,
addr,
@@ -1387,8 +1443,8 @@ int ipmi_request_supply_msgs(ipmi_user_t user,
supplied_smi,
supplied_recv,
priority,
- user->intf->my_address,
- user->intf->my_lun,
+ saddr,
+ lun,
-1, 0);
}
@@ -1397,8 +1453,15 @@ static int ipmb_file_read_proc(char *page, char **start, off_t off,
{
char *out = (char *) page;
ipmi_smi_t intf = data;
+ int i;
+ int rv= 0;
- return sprintf(out, "%x\n", intf->my_address);
+ for (i = 0; i < IPMI_MAX_CHANNELS; i++)
+ rv += sprintf(out+rv, "%x ", intf->channels[i].address);
+ out[rv-1] = '\n'; /* Replace the final space with a newline */
+ out[rv] = '\0';
+ rv++;
+ return rv;
}
static int version_file_read_proc(char *page, char **start, off_t off,
@@ -1588,29 +1651,30 @@ send_channel_info_cmd(ipmi_smi_t intf, int chan)
(struct ipmi_addr *) &si,
0,
&msg,
- NULL,
+ intf,
NULL,
NULL,
0,
- intf->my_address,
- intf->my_lun,
+ intf->channels[0].address,
+ intf->channels[0].lun,
-1, 0);
}
static void
-channel_handler(ipmi_smi_t intf, struct ipmi_smi_msg *msg)
+channel_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
{
int rv = 0;
int chan;
- if ((msg->rsp[0] == (IPMI_NETFN_APP_RESPONSE << 2))
- && (msg->rsp[1] == IPMI_GET_CHANNEL_INFO_CMD))
+ if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
+ && (msg->msg.netfn == IPMI_NETFN_APP_RESPONSE)
+ && (msg->msg.cmd == IPMI_GET_CHANNEL_INFO_CMD))
{
/* It's the one we want */
- if (msg->rsp[2] != 0) {
+ if (msg->msg.data[0] != 0) {
/* Got an error from the channel, just go on. */
- if (msg->rsp[2] == IPMI_INVALID_COMMAND_ERR) {
+ if (msg->msg.data[0] == IPMI_INVALID_COMMAND_ERR) {
/* If the MC does not support this
command, that is legal. We just
assume it has one IPMB at channel
@@ -1627,13 +1691,13 @@ channel_handler(ipmi_smi_t intf, struct ipmi_smi_msg *msg)
}
goto next_channel;
}
- if (msg->rsp_size < 6) {
+ if (msg->msg.data_len < 4) {
/* Message not big enough, just go on. */
goto next_channel;
}
chan = intf->curr_channel;
- intf->channels[chan].medium = msg->rsp[4] & 0x7f;
- intf->channels[chan].protocol = msg->rsp[5] & 0x1f;
+ intf->channels[chan].medium = msg->msg.data[2] & 0x7f;
+ intf->channels[chan].protocol = msg->msg.data[3] & 0x1f;
next_channel:
intf->curr_channel++;
@@ -1691,22 +1755,24 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
rv = -ENOMEM;
down_write(&interfaces_sem);
- for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+ for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
if (ipmi_interfaces[i] == NULL) {
new_intf->intf_num = i;
new_intf->version_major = version_major;
new_intf->version_minor = version_minor;
- if (slave_addr == 0)
- new_intf->my_address = IPMI_BMC_SLAVE_ADDR;
- else
- new_intf->my_address = slave_addr;
- new_intf->my_lun = 2; /* the SMS LUN. */
+ for (j = 0; j < IPMI_MAX_CHANNELS; j++) {
+ new_intf->channels[j].address
+ = IPMI_BMC_SLAVE_ADDR;
+ new_intf->channels[j].lun = 2;
+ }
+ if (slave_addr != 0)
+ new_intf->channels[0].address = slave_addr;
rwlock_init(&(new_intf->users_lock));
INIT_LIST_HEAD(&(new_intf->users));
new_intf->handlers = handlers;
new_intf->send_info = send_info;
spin_lock_init(&(new_intf->seq_lock));
- for (j=0; j<IPMI_IPMB_NUM_SEQ; j++) {
+ for (j = 0; j < IPMI_IPMB_NUM_SEQ; j++) {
new_intf->seq_table[j].inuse = 0;
new_intf->seq_table[j].seqid = 0;
}
@@ -1722,7 +1788,6 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
rwlock_init(&(new_intf->cmd_rcvr_lock));
init_waitqueue_head(&new_intf->waitq);
INIT_LIST_HEAD(&(new_intf->cmd_rcvrs));
- new_intf->all_cmd_rcvr = NULL;
spin_lock_init(&(new_intf->counter_lock));
@@ -1814,7 +1879,7 @@ static void clean_up_interface_data(ipmi_smi_t intf)
free_recv_msg_list(&(intf->waiting_events));
free_cmd_rcvr_list(&(intf->cmd_rcvrs));
- for (i=0; i<IPMI_IPMB_NUM_SEQ; i++) {
+ for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) {
if ((intf->seq_table[i].inuse)
&& (intf->seq_table[i].recv_msg))
{
@@ -1833,7 +1898,7 @@ int ipmi_unregister_smi(ipmi_smi_t intf)
down_write(&interfaces_sem);
if (list_empty(&(intf->users)))
{
- for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+ for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
if (ipmi_interfaces[i] == intf) {
remove_proc_entries(intf);
spin_lock_irqsave(&interfaces_lock, flags);
@@ -1960,15 +2025,11 @@ static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf,
read_lock(&(intf->cmd_rcvr_lock));
- if (intf->all_cmd_rcvr) {
- user = intf->all_cmd_rcvr;
- } else {
- /* Find the command/netfn. */
- list_for_each_entry(rcvr, &(intf->cmd_rcvrs), link) {
- if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)) {
- user = rcvr->user;
- break;
- }
+ /* Find the command/netfn. */
+ list_for_each_entry(rcvr, &(intf->cmd_rcvrs), link) {
+ if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)) {
+ user = rcvr->user;
+ break;
}
}
read_unlock(&(intf->cmd_rcvr_lock));
@@ -1985,7 +2046,7 @@ static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf,
msg->data[3] = msg->rsp[6];
msg->data[4] = ((netfn + 1) << 2) | (msg->rsp[7] & 0x3);
msg->data[5] = ipmb_checksum(&(msg->data[3]), 2);
- msg->data[6] = intf->my_address;
+ msg->data[6] = intf->channels[msg->rsp[3] & 0xf].address;
/* rqseq/lun */
msg->data[7] = (msg->rsp[7] & 0xfc) | (msg->rsp[4] & 0x3);
msg->data[8] = msg->rsp[8]; /* cmd */
@@ -1997,7 +2058,7 @@ static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf,
{
int m;
printk("Invalid command:");
- for (m=0; m<msg->data_size; m++)
+ for (m = 0; m < msg->data_size; m++)
printk(" %2.2x", msg->data[m]);
printk("\n");
}
@@ -2145,15 +2206,11 @@ static int handle_lan_get_msg_cmd(ipmi_smi_t intf,
read_lock(&(intf->cmd_rcvr_lock));
- if (intf->all_cmd_rcvr) {
- user = intf->all_cmd_rcvr;
- } else {
- /* Find the command/netfn. */
- list_for_each_entry(rcvr, &(intf->cmd_rcvrs), link) {
- if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)) {
- user = rcvr->user;
- break;
- }
+ /* Find the command/netfn. */
+ list_for_each_entry(rcvr, &(intf->cmd_rcvrs), link) {
+ if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)) {
+ user = rcvr->user;
+ break;
}
}
read_unlock(&(intf->cmd_rcvr_lock));
@@ -2330,6 +2387,14 @@ static int handle_bmc_rsp(ipmi_smi_t intf,
unsigned long flags;
recv_msg = (struct ipmi_recv_msg *) msg->user_data;
+ if (recv_msg == NULL)
+ {
+ printk(KERN_WARNING"IPMI message received with no owner. This\n"
+ "could be because of a malformed message, or\n"
+ "because of a hardware error. Contact your\n"
+ "hardware vender for assistance\n");
+ return 0;
+ }
/* Make sure the user still exists. */
list_for_each_entry(user, &(intf->users), link) {
@@ -2340,19 +2405,11 @@ static int handle_bmc_rsp(ipmi_smi_t intf,
}
}
- if (!found) {
- /* Special handling for NULL users. */
- if (!recv_msg->user && intf->null_user_handler){
- intf->null_user_handler(intf, msg);
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->handled_local_responses++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
- }else{
- /* The user for the message went away, so give up. */
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->unhandled_local_responses++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
- }
+ if ((! found) && recv_msg->user) {
+ /* The user for the message went away, so give up. */
+ spin_lock_irqsave(&intf->counter_lock, flags);
+ intf->unhandled_local_responses++;
+ spin_unlock_irqrestore(&intf->counter_lock, flags);
ipmi_free_recv_msg(recv_msg);
} else {
struct ipmi_system_interface_addr *smi_addr;
@@ -2392,7 +2449,7 @@ static int handle_new_recv_msg(ipmi_smi_t intf,
#ifdef DEBUG_MSGING
int m;
printk("Recv:");
- for (m=0; m<msg->rsp_size; m++)
+ for (m = 0; m < msg->rsp_size; m++)
printk(" %2.2x", msg->rsp[m]);
printk("\n");
#endif
@@ -2626,7 +2683,7 @@ smi_from_recv_msg(ipmi_smi_t intf, struct ipmi_recv_msg *recv_msg,
{
int m;
printk("Resend: ");
- for (m=0; m<smi_msg->data_size; m++)
+ for (m = 0; m < smi_msg->data_size; m++)
printk(" %2.2x", smi_msg->data[m]);
printk("\n");
}
@@ -2647,7 +2704,7 @@ ipmi_timeout_handler(long timeout_period)
INIT_LIST_HEAD(&timeouts);
spin_lock(&interfaces_lock);
- for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+ for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
intf = ipmi_interfaces[i];
if (intf == NULL)
continue;
@@ -2672,7 +2729,7 @@ ipmi_timeout_handler(long timeout_period)
have timed out, putting them in the timeouts
list. */
spin_lock_irqsave(&(intf->seq_lock), flags);
- for (j=0; j<IPMI_IPMB_NUM_SEQ; j++) {
+ for (j = 0; j < IPMI_IPMB_NUM_SEQ; j++) {
struct seq_table *ent = &(intf->seq_table[j]);
if (!ent->inuse)
continue;
@@ -2712,7 +2769,7 @@ ipmi_timeout_handler(long timeout_period)
spin_unlock(&intf->counter_lock);
smi_msg = smi_from_recv_msg(intf,
ent->recv_msg, j, ent->seqid);
- if(!smi_msg)
+ if (! smi_msg)
continue;
spin_unlock_irqrestore(&(intf->seq_lock),flags);
@@ -2743,7 +2800,7 @@ static void ipmi_request_event(void)
int i;
spin_lock(&interfaces_lock);
- for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+ for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
intf = ipmi_interfaces[i];
if (intf == NULL)
continue;
@@ -2838,28 +2895,30 @@ static void dummy_recv_done_handler(struct ipmi_recv_msg *msg)
}
#ifdef CONFIG_IPMI_PANIC_STRING
-static void event_receiver_fetcher(ipmi_smi_t intf, struct ipmi_smi_msg *msg)
+static void event_receiver_fetcher(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
{
- if ((msg->rsp[0] == (IPMI_NETFN_SENSOR_EVENT_RESPONSE << 2))
- && (msg->rsp[1] == IPMI_GET_EVENT_RECEIVER_CMD)
- && (msg->rsp[2] == IPMI_CC_NO_ERROR))
+ if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
+ && (msg->msg.netfn == IPMI_NETFN_SENSOR_EVENT_RESPONSE)
+ && (msg->msg.cmd == IPMI_GET_EVENT_RECEIVER_CMD)
+ && (msg->msg.data[0] == IPMI_CC_NO_ERROR))
{
/* A get event receiver command, save it. */
- intf->event_receiver = msg->rsp[3];
- intf->event_receiver_lun = msg->rsp[4] & 0x3;
+ intf->event_receiver = msg->msg.data[1];
+ intf->event_receiver_lun = msg->msg.data[2] & 0x3;
}
}
-static void device_id_fetcher(ipmi_smi_t intf, struct ipmi_smi_msg *msg)
+static void device_id_fetcher(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
{
- if ((msg->rsp[0] == (IPMI_NETFN_APP_RESPONSE << 2))
- && (msg->rsp[1] == IPMI_GET_DEVICE_ID_CMD)
- && (msg->rsp[2] == IPMI_CC_NO_ERROR))
+ if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
+ && (msg->msg.netfn == IPMI_NETFN_APP_RESPONSE)
+ && (msg->msg.cmd == IPMI_GET_DEVICE_ID_CMD)
+ && (msg->msg.data[0] == IPMI_CC_NO_ERROR))
{
/* A get device id command, save if we are an event
receiver or generator. */
- intf->local_sel_device = (msg->rsp[8] >> 2) & 1;
- intf->local_event_generator = (msg->rsp[8] >> 5) & 1;
+ intf->local_sel_device = (msg->msg.data[6] >> 2) & 1;
+ intf->local_event_generator = (msg->msg.data[6] >> 5) & 1;
}
}
#endif
@@ -2903,7 +2962,7 @@ static void send_panic_events(char *str)
recv_msg.done = dummy_recv_done_handler;
/* For every registered interface, send the event. */
- for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+ for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
intf = ipmi_interfaces[i];
if (intf == NULL)
continue;
@@ -2915,12 +2974,12 @@ static void send_panic_events(char *str)
&addr,
0,
&msg,
- NULL,
+ intf,
&smi_msg,
&recv_msg,
0,
- intf->my_address,
- intf->my_lun,
+ intf->channels[0].address,
+ intf->channels[0].lun,
0, 1); /* Don't retry, and don't wait. */
}
@@ -2930,7 +2989,7 @@ static void send_panic_events(char *str)
if (!str)
return;
- for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+ for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
char *p = str;
struct ipmi_ipmb_addr *ipmb;
int j;
@@ -2961,12 +3020,12 @@ static void send_panic_events(char *str)
&addr,
0,
&msg,
- NULL,
+ intf,
&smi_msg,
&recv_msg,
0,
- intf->my_address,
- intf->my_lun,
+ intf->channels[0].address,
+ intf->channels[0].lun,
0, 1); /* Don't retry, and don't wait. */
if (intf->local_event_generator) {
@@ -2981,12 +3040,12 @@ static void send_panic_events(char *str)
&addr,
0,
&msg,
- NULL,
+ intf,
&smi_msg,
&recv_msg,
0,
- intf->my_address,
- intf->my_lun,
+ intf->channels[0].address,
+ intf->channels[0].lun,
0, 1); /* no retry, and no wait. */
}
intf->null_user_handler = NULL;
@@ -2996,7 +3055,7 @@ static void send_panic_events(char *str)
be zero, and it must not be my address. */
if (((intf->event_receiver & 1) == 0)
&& (intf->event_receiver != 0)
- && (intf->event_receiver != intf->my_address))
+ && (intf->event_receiver != intf->channels[0].address))
{
/* The event receiver is valid, send an IPMB
message. */
@@ -3031,7 +3090,7 @@ static void send_panic_events(char *str)
data[0] = 0;
data[1] = 0;
data[2] = 0xf0; /* OEM event without timestamp. */
- data[3] = intf->my_address;
+ data[3] = intf->channels[0].address;
data[4] = j++; /* sequence # */
/* Always give 11 bytes, so strncpy will fill
it with zeroes for me. */
@@ -3043,12 +3102,12 @@ static void send_panic_events(char *str)
&addr,
0,
&msg,
- NULL,
+ intf,
&smi_msg,
&recv_msg,
0,
- intf->my_address,
- intf->my_lun,
+ intf->channels[0].address,
+ intf->channels[0].lun,
0, 1); /* no retry, and no wait. */
}
}
@@ -3070,7 +3129,7 @@ static int panic_event(struct notifier_block *this,
has_paniced = 1;
/* For every registered interface, set it to run to completion. */
- for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+ for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
intf = ipmi_interfaces[i];
if (intf == NULL)
continue;
@@ -3099,9 +3158,9 @@ static int ipmi_init_msghandler(void)
return 0;
printk(KERN_INFO "ipmi message handler version "
- IPMI_MSGHANDLER_VERSION "\n");
+ IPMI_DRIVER_VERSION "\n");
- for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+ for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
ipmi_interfaces[i] = NULL;
}
@@ -3171,6 +3230,9 @@ module_exit(cleanup_ipmi);
module_init(ipmi_init_msghandler_mod);
MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>");
+MODULE_DESCRIPTION("Incoming and outgoing message routing for an IPMI interface.");
+MODULE_VERSION(IPMI_DRIVER_VERSION);
EXPORT_SYMBOL(ipmi_create_user);
EXPORT_SYMBOL(ipmi_destroy_user);
diff --git a/drivers/char/ipmi/ipmi_poweroff.c b/drivers/char/ipmi/ipmi_poweroff.c
index f951c30236c9..e82a96ba396b 100644
--- a/drivers/char/ipmi/ipmi_poweroff.c
+++ b/drivers/char/ipmi/ipmi_poweroff.c
@@ -42,7 +42,6 @@
#include <linux/ipmi_smi.h>
#define PFX "IPMI poweroff: "
-#define IPMI_POWEROFF_VERSION "v33"
/* Where to we insert our poweroff function? */
extern void (*pm_power_off)(void);
@@ -53,16 +52,17 @@ extern void (*pm_power_off)(void);
#define IPMI_CHASSIS_POWER_CYCLE 0x02 /* power cycle */
/* the IPMI data command */
-static int poweroff_control = IPMI_CHASSIS_POWER_DOWN;
+static int poweroff_powercycle;
/* parameter definition to allow user to flag power cycle */
-module_param(poweroff_control, int, IPMI_CHASSIS_POWER_DOWN);
-MODULE_PARM_DESC(poweroff_control, " Set to 2 to enable power cycle instead of power down. Power cycle is contingent on hardware support, otherwise it defaults back to power down.");
+module_param(poweroff_powercycle, int, 0);
+MODULE_PARM_DESC(poweroff_powercycles, " Set to non-zero to enable power cycle instead of power down. Power cycle is contingent on hardware support, otherwise it defaults back to power down.");
/* Stuff from the get device id command. */
static unsigned int mfg_id;
static unsigned int prod_id;
static unsigned char capabilities;
+static unsigned char ipmi_version;
/* We use our own messages for this operation, we don't let the system
allocate them, since we may be in a panic situation. The whole
@@ -338,6 +338,25 @@ static void ipmi_poweroff_cpi1 (ipmi_user_t user)
}
/*
+ * ipmi_dell_chassis_detect()
+ * Dell systems with IPMI < 1.5 don't set the chassis capability bit
+ * but they can handle a chassis poweroff or powercycle command.
+ */
+
+#define DELL_IANA_MFR_ID {0xA2, 0x02, 0x00}
+static int ipmi_dell_chassis_detect (ipmi_user_t user)
+{
+ const char ipmi_version_major = ipmi_version & 0xF;
+ const char ipmi_version_minor = (ipmi_version >> 4) & 0xF;
+ const char mfr[3]=DELL_IANA_MFR_ID;
+ if (!memcmp(mfr, &mfg_id, sizeof(mfr)) &&
+ ipmi_version_major <= 1 &&
+ ipmi_version_minor < 5)
+ return 1;
+ return 0;
+}
+
+/*
* Standard chassis support
*/
@@ -366,37 +385,34 @@ static void ipmi_poweroff_chassis (ipmi_user_t user)
powercyclefailed:
printk(KERN_INFO PFX "Powering %s via IPMI chassis control command\n",
- ((poweroff_control != IPMI_CHASSIS_POWER_CYCLE) ? "down" : "cycle"));
+ (poweroff_powercycle ? "cycle" : "down"));
/*
* Power down
*/
send_msg.netfn = IPMI_NETFN_CHASSIS_REQUEST;
send_msg.cmd = IPMI_CHASSIS_CONTROL_CMD;
- data[0] = poweroff_control;
+ if (poweroff_powercycle)
+ data[0] = IPMI_CHASSIS_POWER_CYCLE;
+ else
+ data[0] = IPMI_CHASSIS_POWER_DOWN;
send_msg.data = data;
send_msg.data_len = sizeof(data);
rv = ipmi_request_in_rc_mode(user,
(struct ipmi_addr *) &smi_addr,
&send_msg);
if (rv) {
- switch (poweroff_control) {
- case IPMI_CHASSIS_POWER_CYCLE:
- /* power cycle failed, default to power down */
- printk(KERN_ERR PFX "Unable to send chassis power " \
- "cycle message, IPMI error 0x%x\n", rv);
- poweroff_control = IPMI_CHASSIS_POWER_DOWN;
- goto powercyclefailed;
-
- case IPMI_CHASSIS_POWER_DOWN:
- default:
- printk(KERN_ERR PFX "Unable to send chassis power " \
- "down message, IPMI error 0x%x\n", rv);
- break;
+ if (poweroff_powercycle) {
+ /* power cycle failed, default to power down */
+ printk(KERN_ERR PFX "Unable to send chassis power " \
+ "cycle message, IPMI error 0x%x\n", rv);
+ poweroff_powercycle = 0;
+ goto powercyclefailed;
}
- }
- return;
+ printk(KERN_ERR PFX "Unable to send chassis power " \
+ "down message, IPMI error 0x%x\n", rv);
+ }
}
@@ -414,6 +430,9 @@ static struct poweroff_function poweroff_functions[] = {
{ .platform_type = "CPI1",
.detect = ipmi_cpi1_detect,
.poweroff_func = ipmi_poweroff_cpi1 },
+ { .platform_type = "chassis",
+ .detect = ipmi_dell_chassis_detect,
+ .poweroff_func = ipmi_poweroff_chassis },
/* Chassis should generally be last, other things should override
it. */
{ .platform_type = "chassis",
@@ -499,10 +518,11 @@ static void ipmi_po_new_smi(int if_num)
prod_id = (halt_recv_msg.msg.data[10]
| (halt_recv_msg.msg.data[11] << 8));
capabilities = halt_recv_msg.msg.data[6];
+ ipmi_version = halt_recv_msg.msg.data[5];
/* Scan for a poweroff method */
- for (i=0; i<NUM_PO_FUNCS; i++) {
+ for (i = 0; i < NUM_PO_FUNCS; i++) {
if (poweroff_functions[i].detect(ipmi_user))
goto found;
}
@@ -538,39 +558,35 @@ static struct ipmi_smi_watcher smi_watcher =
#ifdef CONFIG_PROC_FS
-/* displays properties to proc */
-static int proc_read_chassctrl(char *page, char **start, off_t off, int count,
- int *eof, void *data)
-{
- return sprintf(page, "%d\t[ 0=powerdown 2=powercycle ]\n",
- poweroff_control);
-}
+#include <linux/sysctl.h>
+
+static ctl_table ipmi_table[] = {
+ { .ctl_name = DEV_IPMI_POWEROFF_POWERCYCLE,
+ .procname = "poweroff_powercycle",
+ .data = &poweroff_powercycle,
+ .maxlen = sizeof(poweroff_powercycle),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec },
+ { }
+};
-/* process property writes from proc */
-static int proc_write_chassctrl(struct file *file, const char *buffer,
- unsigned long count, void *data)
-{
- int rv = count;
- unsigned int newval = 0;
-
- sscanf(buffer, "%d", &newval);
- switch (newval) {
- case IPMI_CHASSIS_POWER_CYCLE:
- printk(KERN_INFO PFX "power cycle is now enabled\n");
- poweroff_control = newval;
- break;
-
- case IPMI_CHASSIS_POWER_DOWN:
- poweroff_control = IPMI_CHASSIS_POWER_DOWN;
- break;
-
- default:
- rv = -EINVAL;
- break;
- }
+static ctl_table ipmi_dir_table[] = {
+ { .ctl_name = DEV_IPMI,
+ .procname = "ipmi",
+ .mode = 0555,
+ .child = ipmi_table },
+ { }
+};
- return rv;
-}
+static ctl_table ipmi_root_table[] = {
+ { .ctl_name = CTL_DEV,
+ .procname = "dev",
+ .mode = 0555,
+ .child = ipmi_dir_table },
+ { }
+};
+
+static struct ctl_table_header *ipmi_table_header;
#endif /* CONFIG_PROC_FS */
/*
@@ -578,42 +594,32 @@ static int proc_write_chassctrl(struct file *file, const char *buffer,
*/
static int ipmi_poweroff_init (void)
{
- int rv;
- struct proc_dir_entry *file;
+ int rv;
printk ("Copyright (C) 2004 MontaVista Software -"
- " IPMI Powerdown via sys_reboot version "
- IPMI_POWEROFF_VERSION ".\n");
-
- switch (poweroff_control) {
- case IPMI_CHASSIS_POWER_CYCLE:
- printk(KERN_INFO PFX "Power cycle is enabled.\n");
- break;
-
- case IPMI_CHASSIS_POWER_DOWN:
- default:
- poweroff_control = IPMI_CHASSIS_POWER_DOWN;
- break;
+ " IPMI Powerdown via sys_reboot.\n");
+
+ if (poweroff_powercycle)
+ printk(KERN_INFO PFX "Power cycle is enabled.\n");
+
+#ifdef CONFIG_PROC_FS
+ ipmi_table_header = register_sysctl_table(ipmi_root_table, 1);
+ if (!ipmi_table_header) {
+ printk(KERN_ERR PFX "Unable to register powercycle sysctl\n");
+ rv = -ENOMEM;
+ goto out_err;
}
+#endif
+#ifdef CONFIG_PROC_FS
rv = ipmi_smi_watcher_register(&smi_watcher);
+#endif
if (rv) {
+ unregister_sysctl_table(ipmi_table_header);
printk(KERN_ERR PFX "Unable to register SMI watcher: %d\n", rv);
goto out_err;
}
-#ifdef CONFIG_PROC_FS
- file = create_proc_entry("poweroff_control", 0, proc_ipmi_root);
- if (!file) {
- printk(KERN_ERR PFX "Unable to create proc power control\n");
- } else {
- file->nlink = 1;
- file->read_proc = proc_read_chassctrl;
- file->write_proc = proc_write_chassctrl;
- file->owner = THIS_MODULE;
- }
-#endif
-
out_err:
return rv;
}
@@ -624,7 +630,7 @@ static __exit void ipmi_poweroff_cleanup(void)
int rv;
#ifdef CONFIG_PROC_FS
- remove_proc_entry("poweroff_control", proc_ipmi_root);
+ unregister_sysctl_table(ipmi_table_header);
#endif
ipmi_smi_watcher_unregister(&smi_watcher);
@@ -642,3 +648,5 @@ module_exit(ipmi_poweroff_cleanup);
module_init(ipmi_poweroff_init);
MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>");
+MODULE_DESCRIPTION("IPMI Poweroff extension to sys_reboot");
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index a44b97304e95..1abec687865c 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -61,11 +61,11 @@
# endif
static inline void add_usec_to_timer(struct timer_list *t, long v)
{
- t->sub_expires += nsec_to_arch_cycle(v * 1000);
- while (t->sub_expires >= arch_cycles_per_jiffy)
+ t->arch_cycle_expires += nsec_to_arch_cycle(v * 1000);
+ while (t->arch_cycle_expires >= arch_cycles_per_jiffy)
{
t->expires++;
- t->sub_expires -= arch_cycles_per_jiffy;
+ t->arch_cycle_expires -= arch_cycles_per_jiffy;
}
}
#endif
@@ -75,8 +75,7 @@ static inline void add_usec_to_timer(struct timer_list *t, long v)
#include <asm/io.h>
#include "ipmi_si_sm.h"
#include <linux/init.h>
-
-#define IPMI_SI_VERSION "v33"
+#include <linux/dmi.h>
/* Measure times between events in the driver. */
#undef DEBUG_TIMING
@@ -109,6 +108,21 @@ enum si_type {
SI_KCS, SI_SMIC, SI_BT
};
+struct ipmi_device_id {
+ unsigned char device_id;
+ unsigned char device_revision;
+ unsigned char firmware_revision_1;
+ unsigned char firmware_revision_2;
+ unsigned char ipmi_version;
+ unsigned char additional_device_support;
+ unsigned char manufacturer_id[3];
+ unsigned char product_id[2];
+ unsigned char aux_firmware_revision[4];
+} __attribute__((packed));
+
+#define ipmi_version_major(v) ((v)->ipmi_version & 0xf)
+#define ipmi_version_minor(v) ((v)->ipmi_version >> 4)
+
struct smi_info
{
ipmi_smi_t intf;
@@ -131,12 +145,24 @@ struct smi_info
void (*irq_cleanup)(struct smi_info *info);
unsigned int io_size;
+ /* Per-OEM handler, called from handle_flags().
+ Returns 1 when handle_flags() needs to be re-run
+ or 0 indicating it set si_state itself.
+ */
+ int (*oem_data_avail_handler)(struct smi_info *smi_info);
+
/* Flags from the last GET_MSG_FLAGS command, used when an ATTN
is set to hold the flags until we are done handling everything
from the flags. */
#define RECEIVE_MSG_AVAIL 0x01
#define EVENT_MSG_BUFFER_FULL 0x02
#define WDT_PRE_TIMEOUT_INT 0x08
+#define OEM0_DATA_AVAIL 0x20
+#define OEM1_DATA_AVAIL 0x40
+#define OEM2_DATA_AVAIL 0x80
+#define OEM_DATA_AVAIL (OEM0_DATA_AVAIL | \
+ OEM1_DATA_AVAIL | \
+ OEM2_DATA_AVAIL)
unsigned char msg_flags;
/* If set to true, this will request events the next time the
@@ -175,11 +201,7 @@ struct smi_info
interrupts. */
int interrupt_disabled;
- unsigned char ipmi_si_dev_rev;
- unsigned char ipmi_si_fw_rev_major;
- unsigned char ipmi_si_fw_rev_minor;
- unsigned char ipmi_version_major;
- unsigned char ipmi_version_minor;
+ struct ipmi_device_id device_id;
/* Slave address, could be reported from DMI. */
unsigned char slave_addr;
@@ -245,7 +267,7 @@ static enum si_sm_result start_next_msg(struct smi_info *smi_info)
entry = smi_info->xmit_msgs.next;
}
- if (!entry) {
+ if (! entry) {
smi_info->curr_msg = NULL;
rv = SI_SM_IDLE;
} else {
@@ -306,7 +328,7 @@ static void start_clear_flags(struct smi_info *smi_info)
memory, we will re-enable the interrupt. */
static inline void disable_si_irq(struct smi_info *smi_info)
{
- if ((smi_info->irq) && (!smi_info->interrupt_disabled)) {
+ if ((smi_info->irq) && (! smi_info->interrupt_disabled)) {
disable_irq_nosync(smi_info->irq);
smi_info->interrupt_disabled = 1;
}
@@ -322,6 +344,7 @@ static inline void enable_si_irq(struct smi_info *smi_info)
static void handle_flags(struct smi_info *smi_info)
{
+ retry:
if (smi_info->msg_flags & WDT_PRE_TIMEOUT_INT) {
/* Watchdog pre-timeout */
spin_lock(&smi_info->count_lock);
@@ -336,7 +359,7 @@ static void handle_flags(struct smi_info *smi_info)
} else if (smi_info->msg_flags & RECEIVE_MSG_AVAIL) {
/* Messages available. */
smi_info->curr_msg = ipmi_alloc_smi_msg();
- if (!smi_info->curr_msg) {
+ if (! smi_info->curr_msg) {
disable_si_irq(smi_info);
smi_info->si_state = SI_NORMAL;
return;
@@ -355,7 +378,7 @@ static void handle_flags(struct smi_info *smi_info)
} else if (smi_info->msg_flags & EVENT_MSG_BUFFER_FULL) {
/* Events available. */
smi_info->curr_msg = ipmi_alloc_smi_msg();
- if (!smi_info->curr_msg) {
+ if (! smi_info->curr_msg) {
disable_si_irq(smi_info);
smi_info->si_state = SI_NORMAL;
return;
@@ -371,6 +394,10 @@ static void handle_flags(struct smi_info *smi_info)
smi_info->curr_msg->data,
smi_info->curr_msg->data_size);
smi_info->si_state = SI_GETTING_EVENTS;
+ } else if (smi_info->msg_flags & OEM_DATA_AVAIL) {
+ if (smi_info->oem_data_avail_handler)
+ if (smi_info->oem_data_avail_handler(smi_info))
+ goto retry;
} else {
smi_info->si_state = SI_NORMAL;
}
@@ -387,7 +414,7 @@ static void handle_transaction_done(struct smi_info *smi_info)
#endif
switch (smi_info->si_state) {
case SI_NORMAL:
- if (!smi_info->curr_msg)
+ if (! smi_info->curr_msg)
break;
smi_info->curr_msg->rsp_size
@@ -761,18 +788,20 @@ static void si_restart_short_timer(struct smi_info *smi_info)
#if defined(CONFIG_HIGH_RES_TIMERS)
unsigned long flags;
unsigned long jiffies_now;
+ unsigned long seq;
if (del_timer(&(smi_info->si_timer))) {
/* If we don't delete the timer, then it will go off
immediately, anyway. So we only process if we
actually delete the timer. */
- /* We already have irqsave on, so no need for it
- here. */
- read_lock(&xtime_lock);
- jiffies_now = jiffies;
- smi_info->si_timer.expires = jiffies_now;
- smi_info->si_timer.sub_expires = get_arch_cycles(jiffies_now);
+ do {
+ seq = read_seqbegin_irqsave(&xtime_lock, flags);
+ jiffies_now = jiffies;
+ smi_info->si_timer.expires = jiffies_now;
+ smi_info->si_timer.arch_cycle_expires
+ = get_arch_cycles(jiffies_now);
+ } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
add_usec_to_timer(&smi_info->si_timer, SI_SHORT_TIMEOUT_USEC);
@@ -826,15 +855,19 @@ static void smi_timeout(unsigned long data)
/* If the state machine asks for a short delay, then shorten
the timer timeout. */
if (smi_result == SI_SM_CALL_WITH_DELAY) {
+#if defined(CONFIG_HIGH_RES_TIMERS)
+ unsigned long seq;
+#endif
spin_lock_irqsave(&smi_info->count_lock, flags);
smi_info->short_timeouts++;
spin_unlock_irqrestore(&smi_info->count_lock, flags);
#if defined(CONFIG_HIGH_RES_TIMERS)
- read_lock(&xtime_lock);
- smi_info->si_timer.expires = jiffies;
- smi_info->si_timer.sub_expires
- = get_arch_cycles(smi_info->si_timer.expires);
- read_unlock(&xtime_lock);
+ do {
+ seq = read_seqbegin_irqsave(&xtime_lock, flags);
+ smi_info->si_timer.expires = jiffies;
+ smi_info->si_timer.arch_cycle_expires
+ = get_arch_cycles(smi_info->si_timer.expires);
+ } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
add_usec_to_timer(&smi_info->si_timer, SI_SHORT_TIMEOUT_USEC);
#else
smi_info->si_timer.expires = jiffies + 1;
@@ -845,7 +878,7 @@ static void smi_timeout(unsigned long data)
spin_unlock_irqrestore(&smi_info->count_lock, flags);
smi_info->si_timer.expires = jiffies + SI_TIMEOUT_JIFFIES;
#if defined(CONFIG_HIGH_RES_TIMERS)
- smi_info->si_timer.sub_expires = 0;
+ smi_info->si_timer.arch_cycle_expires = 0;
#endif
}
@@ -1014,7 +1047,7 @@ static int std_irq_setup(struct smi_info *info)
{
int rv;
- if (!info->irq)
+ if (! info->irq)
return 0;
if (info->si_type == SI_BT) {
@@ -1023,7 +1056,7 @@ static int std_irq_setup(struct smi_info *info)
SA_INTERRUPT,
DEVICE_NAME,
info);
- if (!rv)
+ if (! rv)
/* Enable the interrupt in the BT interface. */
info->io.outputb(&info->io, IPMI_BT_INTMASK_REG,
IPMI_BT_INTMASK_ENABLE_IRQ_BIT);
@@ -1048,7 +1081,7 @@ static int std_irq_setup(struct smi_info *info)
static void std_irq_cleanup(struct smi_info *info)
{
- if (!info->irq)
+ if (! info->irq)
return;
if (info->si_type == SI_BT)
@@ -1121,7 +1154,7 @@ static int port_setup(struct smi_info *info)
unsigned int *addr = info->io.info;
int mapsize;
- if (!addr || (!*addr))
+ if (! addr || (! *addr))
return -ENODEV;
info->io_cleanup = port_cleanup;
@@ -1164,15 +1197,15 @@ static int try_init_port(int intf_num, struct smi_info **new_info)
{
struct smi_info *info;
- if (!ports[intf_num])
+ if (! ports[intf_num])
return -ENODEV;
- if (!is_new_interface(intf_num, IPMI_IO_ADDR_SPACE,
+ if (! is_new_interface(intf_num, IPMI_IO_ADDR_SPACE,
ports[intf_num]))
return -ENODEV;
info = kmalloc(sizeof(*info), GFP_KERNEL);
- if (!info) {
+ if (! info) {
printk(KERN_ERR "ipmi_si: Could not allocate SI data (1)\n");
return -ENOMEM;
}
@@ -1182,10 +1215,10 @@ static int try_init_port(int intf_num, struct smi_info **new_info)
info->io.info = &(ports[intf_num]);
info->io.addr = NULL;
info->io.regspacing = regspacings[intf_num];
- if (!info->io.regspacing)
+ if (! info->io.regspacing)
info->io.regspacing = DEFAULT_REGSPACING;
info->io.regsize = regsizes[intf_num];
- if (!info->io.regsize)
+ if (! info->io.regsize)
info->io.regsize = DEFAULT_REGSPACING;
info->io.regshift = regshifts[intf_num];
info->irq = 0;
@@ -1270,7 +1303,7 @@ static int mem_setup(struct smi_info *info)
unsigned long *addr = info->io.info;
int mapsize;
- if (!addr || (!*addr))
+ if (! addr || (! *addr))
return -ENODEV;
info->io_cleanup = mem_cleanup;
@@ -1325,15 +1358,15 @@ static int try_init_mem(int intf_num, struct smi_info **new_info)
{
struct smi_info *info;
- if (!addrs[intf_num])
+ if (! addrs[intf_num])
return -ENODEV;
- if (!is_new_interface(intf_num, IPMI_MEM_ADDR_SPACE,
+ if (! is_new_interface(intf_num, IPMI_MEM_ADDR_SPACE,
addrs[intf_num]))
return -ENODEV;
info = kmalloc(sizeof(*info), GFP_KERNEL);
- if (!info) {
+ if (! info) {
printk(KERN_ERR "ipmi_si: Could not allocate SI data (2)\n");
return -ENOMEM;
}
@@ -1343,10 +1376,10 @@ static int try_init_mem(int intf_num, struct smi_info **new_info)
info->io.info = &addrs[intf_num];
info->io.addr = NULL;
info->io.regspacing = regspacings[intf_num];
- if (!info->io.regspacing)
+ if (! info->io.regspacing)
info->io.regspacing = DEFAULT_REGSPACING;
info->io.regsize = regsizes[intf_num];
- if (!info->io.regsize)
+ if (! info->io.regsize)
info->io.regsize = DEFAULT_REGSPACING;
info->io.regshift = regshifts[intf_num];
info->irq = 0;
@@ -1404,7 +1437,7 @@ static int acpi_gpe_irq_setup(struct smi_info *info)
{
acpi_status status;
- if (!info->irq)
+ if (! info->irq)
return 0;
/* FIXME - is level triggered right? */
@@ -1428,7 +1461,7 @@ static int acpi_gpe_irq_setup(struct smi_info *info)
static void acpi_gpe_irq_cleanup(struct smi_info *info)
{
- if (!info->irq)
+ if (! info->irq)
return;
acpi_remove_gpe_handler(NULL, info->irq, &ipmi_acpi_gpe);
@@ -1504,10 +1537,10 @@ static int try_init_acpi(int intf_num, struct smi_info **new_info)
addr_space = IPMI_MEM_ADDR_SPACE;
else
addr_space = IPMI_IO_ADDR_SPACE;
- if (!is_new_interface(-1, addr_space, spmi->addr.address))
+ if (! is_new_interface(-1, addr_space, spmi->addr.address))
return -ENODEV;
- if (!spmi->addr.register_bit_width) {
+ if (! spmi->addr.register_bit_width) {
acpi_failure = 1;
return -ENODEV;
}
@@ -1534,7 +1567,7 @@ static int try_init_acpi(int intf_num, struct smi_info **new_info)
}
info = kmalloc(sizeof(*info), GFP_KERNEL);
- if (!info) {
+ if (! info) {
printk(KERN_ERR "ipmi_si: Could not allocate SI data (3)\n");
return -ENOMEM;
}
@@ -1610,22 +1643,15 @@ typedef struct dmi_ipmi_data
static dmi_ipmi_data_t dmi_data[SI_MAX_DRIVERS];
static int dmi_data_entries;
-typedef struct dmi_header
-{
- u8 type;
- u8 length;
- u16 handle;
-} dmi_header_t;
-
-static int decode_dmi(dmi_header_t __iomem *dm, int intf_num)
+static int __init decode_dmi(struct dmi_header *dm, int intf_num)
{
- u8 __iomem *data = (u8 __iomem *)dm;
+ u8 *data = (u8 *)dm;
unsigned long base_addr;
u8 reg_spacing;
- u8 len = readb(&dm->length);
+ u8 len = dm->length;
dmi_ipmi_data_t *ipmi_data = dmi_data+intf_num;
- ipmi_data->type = readb(&data[4]);
+ ipmi_data->type = data[4];
memcpy(&base_addr, data+8, sizeof(unsigned long));
if (len >= 0x11) {
@@ -1640,12 +1666,12 @@ static int decode_dmi(dmi_header_t __iomem *dm, int intf_num)
}
/* If bit 4 of byte 0x10 is set, then the lsb for the address
is odd. */
- ipmi_data->base_addr = base_addr | ((readb(&data[0x10]) & 0x10) >> 4);
+ ipmi_data->base_addr = base_addr | ((data[0x10] & 0x10) >> 4);
- ipmi_data->irq = readb(&data[0x11]);
+ ipmi_data->irq = data[0x11];
/* The top two bits of byte 0x10 hold the register spacing. */
- reg_spacing = (readb(&data[0x10]) & 0xC0) >> 6;
+ reg_spacing = (data[0x10] & 0xC0) >> 6;
switch(reg_spacing){
case 0x00: /* Byte boundaries */
ipmi_data->offset = 1;
@@ -1673,7 +1699,7 @@ static int decode_dmi(dmi_header_t __iomem *dm, int intf_num)
ipmi_data->offset = 1;
}
- ipmi_data->slave_addr = readb(&data[6]);
+ ipmi_data->slave_addr = data[6];
if (is_new_interface(-1, ipmi_data->addr_space,ipmi_data->base_addr)) {
dmi_data_entries++;
@@ -1685,94 +1711,29 @@ static int decode_dmi(dmi_header_t __iomem *dm, int intf_num)
return -1;
}
-static int dmi_table(u32 base, int len, int num)
+static void __init dmi_find_bmc(void)
{
- u8 __iomem *buf;
- struct dmi_header __iomem *dm;
- u8 __iomem *data;
- int i=1;
- int status=-1;
+ struct dmi_device *dev = NULL;
int intf_num = 0;
- buf = ioremap(base, len);
- if(buf==NULL)
- return -1;
-
- data = buf;
-
- while(i<num && (data - buf) < len)
- {
- dm=(dmi_header_t __iomem *)data;
-
- if((data-buf+readb(&dm->length)) >= len)
- break;
-
- if (readb(&dm->type) == 38) {
- if (decode_dmi(dm, intf_num) == 0) {
- intf_num++;
- if (intf_num >= SI_MAX_DRIVERS)
- break;
- }
- }
-
- data+=readb(&dm->length);
- while((data-buf) < len && (readb(data)||readb(data+1)))
- data++;
- data+=2;
- i++;
- }
- iounmap(buf);
-
- return status;
-}
-
-static inline int dmi_checksum(u8 *buf)
-{
- u8 sum=0;
- int a;
-
- for(a=0; a<15; a++)
- sum+=buf[a];
- return (sum==0);
-}
-
-static int dmi_decode(void)
-{
- u8 buf[15];
- u32 fp=0xF0000;
-
-#ifdef CONFIG_SIMNOW
- return -1;
-#endif
-
- while(fp < 0xFFFFF)
- {
- isa_memcpy_fromio(buf, fp, 15);
- if(memcmp(buf, "_DMI_", 5)==0 && dmi_checksum(buf))
- {
- u16 num=buf[13]<<8|buf[12];
- u16 len=buf[7]<<8|buf[6];
- u32 base=buf[11]<<24|buf[10]<<16|buf[9]<<8|buf[8];
+ while ((dev = dmi_find_device(DMI_DEV_TYPE_IPMI, NULL, dev))) {
+ if (intf_num >= SI_MAX_DRIVERS)
+ break;
- if(dmi_table(base, len, num) == 0)
- return 0;
- }
- fp+=16;
+ decode_dmi((struct dmi_header *) dev->device_data, intf_num++);
}
-
- return -1;
}
static int try_init_smbios(int intf_num, struct smi_info **new_info)
{
- struct smi_info *info;
- dmi_ipmi_data_t *ipmi_data = dmi_data+intf_num;
- char *io_type;
+ struct smi_info *info;
+ dmi_ipmi_data_t *ipmi_data = dmi_data+intf_num;
+ char *io_type;
if (intf_num >= dmi_data_entries)
return -ENODEV;
- switch(ipmi_data->type) {
+ switch (ipmi_data->type) {
case 0x01: /* KCS */
si_type[intf_num] = "kcs";
break;
@@ -1787,7 +1748,7 @@ static int try_init_smbios(int intf_num, struct smi_info **new_info)
}
info = kmalloc(sizeof(*info), GFP_KERNEL);
- if (!info) {
+ if (! info) {
printk(KERN_ERR "ipmi_si: Could not allocate SI data (4)\n");
return -ENOMEM;
}
@@ -1811,7 +1772,7 @@ static int try_init_smbios(int intf_num, struct smi_info **new_info)
regspacings[intf_num] = ipmi_data->offset;
info->io.regspacing = regspacings[intf_num];
- if (!info->io.regspacing)
+ if (! info->io.regspacing)
info->io.regspacing = DEFAULT_REGSPACING;
info->io.regsize = DEFAULT_REGSPACING;
info->io.regshift = regshifts[intf_num];
@@ -1853,14 +1814,14 @@ static int find_pci_smic(int intf_num, struct smi_info **new_info)
pci_smic_checked = 1;
- if ((pci_dev = pci_get_device(PCI_HP_VENDOR_ID, PCI_MMC_DEVICE_ID,
- NULL)))
- ;
- else if ((pci_dev = pci_get_class(PCI_ERMC_CLASSCODE, NULL)) &&
- pci_dev->subsystem_vendor == PCI_HP_VENDOR_ID)
- fe_rmc = 1;
- else
- return -ENODEV;
+ pci_dev = pci_get_device(PCI_HP_VENDOR_ID, PCI_MMC_DEVICE_ID, NULL);
+ if (! pci_dev) {
+ pci_dev = pci_get_class(PCI_ERMC_CLASSCODE, NULL);
+ if (pci_dev && (pci_dev->subsystem_vendor == PCI_HP_VENDOR_ID))
+ fe_rmc = 1;
+ else
+ return -ENODEV;
+ }
error = pci_read_config_word(pci_dev, PCI_MMC_ADDR_CW, &base_addr);
if (error)
@@ -1873,7 +1834,7 @@ static int find_pci_smic(int intf_num, struct smi_info **new_info)
}
/* Bit 0: 1 specifies programmed I/O, 0 specifies memory mapped I/O */
- if (!(base_addr & 0x0001))
+ if (! (base_addr & 0x0001))
{
pci_dev_put(pci_dev);
printk(KERN_ERR
@@ -1883,17 +1844,17 @@ static int find_pci_smic(int intf_num, struct smi_info **new_info)
}
base_addr &= 0xFFFE;
- if (!fe_rmc)
+ if (! fe_rmc)
/* Data register starts at base address + 1 in eRMC */
++base_addr;
- if (!is_new_interface(-1, IPMI_IO_ADDR_SPACE, base_addr)) {
+ if (! is_new_interface(-1, IPMI_IO_ADDR_SPACE, base_addr)) {
pci_dev_put(pci_dev);
return -ENODEV;
}
info = kmalloc(sizeof(*info), GFP_KERNEL);
- if (!info) {
+ if (! info) {
pci_dev_put(pci_dev);
printk(KERN_ERR "ipmi_si: Could not allocate SI data (5)\n");
return -ENOMEM;
@@ -1904,7 +1865,7 @@ static int find_pci_smic(int intf_num, struct smi_info **new_info)
ports[intf_num] = base_addr;
info->io.info = &(ports[intf_num]);
info->io.regspacing = regspacings[intf_num];
- if (!info->io.regspacing)
+ if (! info->io.regspacing)
info->io.regspacing = DEFAULT_REGSPACING;
info->io.regsize = DEFAULT_REGSPACING;
info->io.regshift = regshifts[intf_num];
@@ -1925,7 +1886,7 @@ static int find_pci_smic(int intf_num, struct smi_info **new_info)
static int try_init_plug_and_play(int intf_num, struct smi_info **new_info)
{
#ifdef CONFIG_PCI
- if (find_pci_smic(intf_num, new_info)==0)
+ if (find_pci_smic(intf_num, new_info) == 0)
return 0;
#endif
/* Include other methods here. */
@@ -1943,7 +1904,7 @@ static int try_get_dev_id(struct smi_info *smi_info)
int rv = 0;
resp = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL);
- if (!resp)
+ if (! resp)
return -ENOMEM;
/* Do a Get Device ID command, since it comes back with some
@@ -1992,11 +1953,8 @@ static int try_get_dev_id(struct smi_info *smi_info)
}
/* Record info from the get device id, in case we need it. */
- smi_info->ipmi_si_dev_rev = resp[4] & 0xf;
- smi_info->ipmi_si_fw_rev_major = resp[5] & 0x7f;
- smi_info->ipmi_si_fw_rev_minor = resp[6];
- smi_info->ipmi_version_major = resp[7] & 0xf;
- smi_info->ipmi_version_minor = resp[7] >> 4;
+ memcpy(&smi_info->device_id, &resp[3],
+ min_t(unsigned long, resp_len-3, sizeof(smi_info->device_id)));
out:
kfree(resp);
@@ -2028,7 +1986,7 @@ static int stat_file_read_proc(char *page, char **start, off_t off,
struct smi_info *smi = data;
out += sprintf(out, "interrupts_enabled: %d\n",
- smi->irq && !smi->interrupt_disabled);
+ smi->irq && ! smi->interrupt_disabled);
out += sprintf(out, "short_timeouts: %ld\n",
smi->short_timeouts);
out += sprintf(out, "long_timeouts: %ld\n",
@@ -2057,6 +2015,73 @@ static int stat_file_read_proc(char *page, char **start, off_t off,
return (out - ((char *) page));
}
+/*
+ * oem_data_avail_to_receive_msg_avail
+ * @info - smi_info structure with msg_flags set
+ *
+ * Converts flags from OEM_DATA_AVAIL to RECEIVE_MSG_AVAIL
+ * Returns 1 indicating need to re-run handle_flags().
+ */
+static int oem_data_avail_to_receive_msg_avail(struct smi_info *smi_info)
+{
+ smi_info->msg_flags = ((smi_info->msg_flags & ~OEM_DATA_AVAIL) |
+ RECEIVE_MSG_AVAIL);
+ return 1;
+}
+
+/*
+ * setup_dell_poweredge_oem_data_handler
+ * @info - smi_info.device_id must be populated
+ *
+ * Systems that match, but have firmware version < 1.40 may assert
+ * OEM0_DATA_AVAIL on their own, without being told via Set Flags that
+ * it's safe to do so. Such systems will de-assert OEM1_DATA_AVAIL
+ * upon receipt of IPMI_GET_MSG_CMD, so we should treat these flags
+ * as RECEIVE_MSG_AVAIL instead.
+ *
+ * As Dell has no plans to release IPMI 1.5 firmware that *ever*
+ * assert the OEM[012] bits, and if it did, the driver would have to
+ * change to handle that properly, we don't actually check for the
+ * firmware version.
+ * Device ID = 0x20 BMC on PowerEdge 8G servers
+ * Device Revision = 0x80
+ * Firmware Revision1 = 0x01 BMC version 1.40
+ * Firmware Revision2 = 0x40 BCD encoded
+ * IPMI Version = 0x51 IPMI 1.5
+ * Manufacturer ID = A2 02 00 Dell IANA
+ *
+ */
+#define DELL_POWEREDGE_8G_BMC_DEVICE_ID 0x20
+#define DELL_POWEREDGE_8G_BMC_DEVICE_REV 0x80
+#define DELL_POWEREDGE_8G_BMC_IPMI_VERSION 0x51
+#define DELL_IANA_MFR_ID {0xA2, 0x02, 0x00}
+static void setup_dell_poweredge_oem_data_handler(struct smi_info *smi_info)
+{
+ struct ipmi_device_id *id = &smi_info->device_id;
+ const char mfr[3]=DELL_IANA_MFR_ID;
+ if (! memcmp(mfr, id->manufacturer_id, sizeof(mfr))
+ && (id->device_id == DELL_POWEREDGE_8G_BMC_DEVICE_ID)
+ && (id->device_revision == DELL_POWEREDGE_8G_BMC_DEVICE_REV)
+ && (id->ipmi_version == DELL_POWEREDGE_8G_BMC_IPMI_VERSION))
+ {
+ smi_info->oem_data_avail_handler =
+ oem_data_avail_to_receive_msg_avail;
+ }
+}
+
+/*
+ * setup_oem_data_handler
+ * @info - smi_info.device_id must be filled in already
+ *
+ * Fills in smi_info.device_id.oem_data_available_handler
+ * when we know what function to use there.
+ */
+
+static void setup_oem_data_handler(struct smi_info *smi_info)
+{
+ setup_dell_poweredge_oem_data_handler(smi_info);
+}
+
/* Returns 0 if initialized, or negative on an error. */
static int init_one_smi(int intf_num, struct smi_info **smi)
{
@@ -2068,19 +2093,15 @@ static int init_one_smi(int intf_num, struct smi_info **smi)
if (rv)
rv = try_init_port(intf_num, &new_smi);
#ifdef CONFIG_ACPI_INTERPRETER
- if ((rv) && (si_trydefaults)) {
+ if (rv && si_trydefaults)
rv = try_init_acpi(intf_num, &new_smi);
- }
#endif
#ifdef CONFIG_X86
- if ((rv) && (si_trydefaults)) {
+ if (rv && si_trydefaults)
rv = try_init_smbios(intf_num, &new_smi);
- }
#endif
- if ((rv) && (si_trydefaults)) {
+ if (rv && si_trydefaults)
rv = try_init_plug_and_play(intf_num, &new_smi);
- }
-
if (rv)
return rv;
@@ -2090,7 +2111,7 @@ static int init_one_smi(int intf_num, struct smi_info **smi)
new_smi->si_sm = NULL;
new_smi->handlers = NULL;
- if (!new_smi->irq_setup) {
+ if (! new_smi->irq_setup) {
new_smi->irq = irqs[intf_num];
new_smi->irq_setup = std_irq_setup;
new_smi->irq_cleanup = std_irq_cleanup;
@@ -2124,7 +2145,7 @@ static int init_one_smi(int intf_num, struct smi_info **smi)
/* Allocate the state machine's data and initialize it. */
new_smi->si_sm = kmalloc(new_smi->handlers->size(), GFP_KERNEL);
- if (!new_smi->si_sm) {
+ if (! new_smi->si_sm) {
printk(" Could not allocate state machine memory\n");
rv = -ENOMEM;
goto out_err;
@@ -2155,6 +2176,8 @@ static int init_one_smi(int intf_num, struct smi_info **smi)
if (rv)
goto out_err;
+ setup_oem_data_handler(new_smi);
+
/* Try to claim any interrupts. */
new_smi->irq_setup(new_smi);
@@ -2188,8 +2211,8 @@ static int init_one_smi(int intf_num, struct smi_info **smi)
rv = ipmi_register_smi(&handlers,
new_smi,
- new_smi->ipmi_version_major,
- new_smi->ipmi_version_minor,
+ ipmi_version_major(&new_smi->device_id),
+ ipmi_version_minor(&new_smi->device_id),
new_smi->slave_addr,
&(new_smi->intf));
if (rv) {
@@ -2230,7 +2253,7 @@ static int init_one_smi(int intf_num, struct smi_info **smi)
/* Wait for the timer to stop. This avoids problems with race
conditions removing the timer here. */
- while (!new_smi->timer_stopped) {
+ while (! new_smi->timer_stopped) {
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
}
@@ -2270,7 +2293,7 @@ static __init int init_ipmi_si(void)
/* Parse out the si_type string into its components. */
str = si_type_str;
if (*str != '\0') {
- for (i=0; (i<SI_MAX_PARMS) && (*str != '\0'); i++) {
+ for (i = 0; (i < SI_MAX_PARMS) && (*str != '\0'); i++) {
si_type[i] = str;
str = strchr(str, ',');
if (str) {
@@ -2282,22 +2305,14 @@ static __init int init_ipmi_si(void)
}
}
- printk(KERN_INFO "IPMI System Interface driver version "
- IPMI_SI_VERSION);
- if (kcs_smi_handlers.version)
- printk(", KCS version %s", kcs_smi_handlers.version);
- if (smic_smi_handlers.version)
- printk(", SMIC version %s", smic_smi_handlers.version);
- if (bt_smi_handlers.version)
- printk(", BT version %s", bt_smi_handlers.version);
- printk("\n");
+ printk(KERN_INFO "IPMI System Interface driver.\n");
#ifdef CONFIG_X86
- dmi_decode();
+ dmi_find_bmc();
#endif
rv = init_one_smi(0, &(smi_infos[pos]));
- if (rv && !ports[0] && si_trydefaults) {
+ if (rv && ! ports[0] && si_trydefaults) {
/* If we are trying defaults and the initial port is
not set, then set it. */
si_type[0] = "kcs";
@@ -2319,7 +2334,7 @@ static __init int init_ipmi_si(void)
if (rv == 0)
pos++;
- for (i=1; i < SI_MAX_PARMS; i++) {
+ for (i = 1; i < SI_MAX_PARMS; i++) {
rv = init_one_smi(i, &(smi_infos[pos]));
if (rv == 0)
pos++;
@@ -2361,14 +2376,14 @@ static void __exit cleanup_one_si(struct smi_info *to_clean)
/* Wait for the timer to stop. This avoids problems with race
conditions removing the timer here. */
- while (!to_clean->timer_stopped) {
+ while (! to_clean->timer_stopped) {
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
}
/* Interrupts and timeouts are stopped, now make sure the
interface is in a clean state. */
- while ((to_clean->curr_msg) || (to_clean->si_state != SI_NORMAL)) {
+ while (to_clean->curr_msg || (to_clean->si_state != SI_NORMAL)) {
poll(to_clean);
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
@@ -2392,13 +2407,15 @@ static __exit void cleanup_ipmi_si(void)
{
int i;
- if (!initialized)
+ if (! initialized)
return;
- for (i=0; i<SI_MAX_DRIVERS; i++) {
+ for (i = 0; i < SI_MAX_DRIVERS; i++) {
cleanup_one_si(smi_infos[i]);
}
}
module_exit(cleanup_ipmi_si);
MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>");
+MODULE_DESCRIPTION("Interface to the IPMI driver for the KCS, SMIC, and BT system interfaces.");
diff --git a/drivers/char/ipmi/ipmi_smic_sm.c b/drivers/char/ipmi/ipmi_smic_sm.c
index ae18747e670b..add2aa2732f0 100644
--- a/drivers/char/ipmi/ipmi_smic_sm.c
+++ b/drivers/char/ipmi/ipmi_smic_sm.c
@@ -46,8 +46,6 @@
#include <linux/ipmi_msgdefs.h> /* for completion codes */
#include "ipmi_si_sm.h"
-#define IPMI_SMIC_VERSION "v33"
-
/* smic_debug is a bit-field
* SMIC_DEBUG_ENABLE - turned on for now
* SMIC_DEBUG_MSG - commands and their responses
@@ -588,7 +586,6 @@ static int smic_size(void)
struct si_sm_handlers smic_smi_handlers =
{
- .version = IPMI_SMIC_VERSION,
.init_data = init_smic_data,
.start_transaction = start_smic_transaction,
.get_result = smic_get_result,
diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c
index d35a953961cb..e71aaae855ad 100644
--- a/drivers/char/ipmi/ipmi_watchdog.c
+++ b/drivers/char/ipmi/ipmi_watchdog.c
@@ -53,8 +53,6 @@
#define PFX "IPMI Watchdog: "
-#define IPMI_WATCHDOG_VERSION "v33"
-
/*
* The IPMI command/response information for the watchdog timer.
*/
@@ -259,7 +257,7 @@ static int i_ipmi_set_timeout(struct ipmi_smi_msg *smi_msg,
data[1] = 0;
WDOG_SET_TIMEOUT_ACT(data[1], ipmi_watchdog_state);
- if (pretimeout > 0) {
+ if ((pretimeout > 0) && (ipmi_watchdog_state != WDOG_TIMEOUT_NONE)) {
WDOG_SET_PRETIMEOUT_ACT(data[1], preaction_val);
data[2] = pretimeout;
} else {
@@ -659,19 +657,18 @@ static ssize_t ipmi_read(struct file *file,
static int ipmi_open(struct inode *ino, struct file *filep)
{
- switch (iminor(ino))
- {
- case WATCHDOG_MINOR:
- if(test_and_set_bit(0, &ipmi_wdog_open))
+ switch (iminor(ino)) {
+ case WATCHDOG_MINOR:
+ if (test_and_set_bit(0, &ipmi_wdog_open))
return -EBUSY;
- /* Don't start the timer now, let it start on the
- first heartbeat. */
- ipmi_start_timer_on_heartbeat = 1;
- return nonseekable_open(ino, filep);
+ /* Don't start the timer now, let it start on the
+ first heartbeat. */
+ ipmi_start_timer_on_heartbeat = 1;
+ return nonseekable_open(ino, filep);
- default:
- return (-ENODEV);
+ default:
+ return (-ENODEV);
}
}
@@ -817,15 +814,19 @@ static void ipmi_register_watchdog(int ipmi_intf)
static int
ipmi_nmi(void *dev_id, struct pt_regs *regs, int cpu, int handled)
{
+ /* If we are not expecting a timeout, ignore it. */
+ if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE)
+ return NOTIFY_DONE;
+
/* If no one else handled the NMI, we assume it was the IPMI
watchdog. */
- if ((!handled) && (preop_val == WDOG_PREOP_PANIC))
+ if ((!handled) && (preop_val == WDOG_PREOP_PANIC)) {
+ /* On some machines, the heartbeat will give
+ an error and not work unless we re-enable
+ the timer. So do so. */
+ pretimeout_since_last_heartbeat = 1;
panic(PFX "pre-timeout");
-
- /* On some machines, the heartbeat will give
- an error and not work unless we re-enable
- the timer. So do so. */
- pretimeout_since_last_heartbeat = 1;
+ }
return NOTIFY_DONE;
}
@@ -924,9 +925,6 @@ static int __init ipmi_wdog_init(void)
{
int rv;
- printk(KERN_INFO PFX "driver version "
- IPMI_WATCHDOG_VERSION "\n");
-
if (strcmp(action, "reset") == 0) {
action_val = WDOG_TIMEOUT_RESET;
} else if (strcmp(action, "none") == 0) {
@@ -1011,6 +1009,8 @@ static int __init ipmi_wdog_init(void)
register_reboot_notifier(&wdog_reboot_notifier);
notifier_chain_register(&panic_notifier_list, &wdog_panic_notifier);
+ printk(KERN_INFO PFX "driver initialized\n");
+
return 0;
}
@@ -1062,3 +1062,5 @@ static void __exit ipmi_wdog_exit(void)
module_exit(ipmi_wdog_exit);
module_init(ipmi_wdog_init);
MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>");
+MODULE_DESCRIPTION("watchdog timer based upon the IPMI interface.");
diff --git a/drivers/char/mbcs.c b/drivers/char/mbcs.c
index 115dbb35334b..3fa64c631108 100644
--- a/drivers/char/mbcs.c
+++ b/drivers/char/mbcs.c
@@ -750,7 +750,7 @@ static int mbcs_probe(struct cx_dev *dev, const struct cx_device_id *id)
dev->soft = NULL;
- soft = kcalloc(1, sizeof(struct mbcs_soft), GFP_KERNEL);
+ soft = kzalloc(sizeof(struct mbcs_soft), GFP_KERNEL);
if (soft == NULL)
return -ENOMEM;
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 850a78c9c4bc..f182752fe918 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -35,10 +35,6 @@
# include <linux/efi.h>
#endif
-#if defined(CONFIG_S390_TAPE) && defined(CONFIG_S390_TAPE_CHAR)
-extern void tapechar_init(void);
-#endif
-
/*
* Architectures vary in how they handle caching for addresses
* outside of main memory.
diff --git a/drivers/char/misc.c b/drivers/char/misc.c
index 931efd58f87a..0c8375165e29 100644
--- a/drivers/char/misc.c
+++ b/drivers/char/misc.c
@@ -63,8 +63,6 @@ static DECLARE_MUTEX(misc_sem);
#define DYNAMIC_MINORS 64 /* like dynamic majors */
static unsigned char misc_minors[DYNAMIC_MINORS / 8];
-extern int rtc_DP8570A_init(void);
-extern int rtc_MK48T08_init(void);
extern int pmu_device_init(void);
#ifdef CONFIG_PROC_FS
@@ -303,12 +301,7 @@ static int __init misc_init(void)
misc_class = class_create(THIS_MODULE, "misc");
if (IS_ERR(misc_class))
return PTR_ERR(misc_class);
-#ifdef CONFIG_MVME16x
- rtc_MK48T08_init();
-#endif
-#ifdef CONFIG_BVME6000
- rtc_DP8570A_init();
-#endif
+
if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) {
printk("unable to get major %d for misc devices\n",
MISC_MAJOR);
diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c
index cefbe985e55c..36ae9ad2598c 100644
--- a/drivers/char/sonypi.c
+++ b/drivers/char/sonypi.c
@@ -98,12 +98,13 @@ MODULE_PARM_DESC(useinput,
#define SONYPI_DEVICE_MODEL_TYPE1 1
#define SONYPI_DEVICE_MODEL_TYPE2 2
+#define SONYPI_DEVICE_MODEL_TYPE3 3
/* type1 models use those */
#define SONYPI_IRQ_PORT 0x8034
#define SONYPI_IRQ_SHIFT 22
-#define SONYPI_BASE 0x50
-#define SONYPI_G10A (SONYPI_BASE+0x14)
+#define SONYPI_TYPE1_BASE 0x50
+#define SONYPI_G10A (SONYPI_TYPE1_BASE+0x14)
#define SONYPI_TYPE1_REGION_SIZE 0x08
#define SONYPI_TYPE1_EVTYPE_OFFSET 0x04
@@ -114,6 +115,13 @@ MODULE_PARM_DESC(useinput,
#define SONYPI_TYPE2_REGION_SIZE 0x20
#define SONYPI_TYPE2_EVTYPE_OFFSET 0x12
+/* type3 series specifics */
+#define SONYPI_TYPE3_BASE 0x40
+#define SONYPI_TYPE3_GID2 (SONYPI_TYPE3_BASE+0x48) /* 16 bits */
+#define SONYPI_TYPE3_MISC (SONYPI_TYPE3_BASE+0x6d) /* 8 bits */
+#define SONYPI_TYPE3_REGION_SIZE 0x20
+#define SONYPI_TYPE3_EVTYPE_OFFSET 0x12
+
/* battery / brightness addresses */
#define SONYPI_BAT_FLAGS 0x81
#define SONYPI_LCD_LIGHT 0x96
@@ -159,6 +167,10 @@ static struct sonypi_ioport_list sonypi_type2_ioport_list[] = {
{ 0x0, 0x0 }
};
+/* same as in type 2 models */
+static struct sonypi_ioport_list *sonypi_type3_ioport_list =
+ sonypi_type2_ioport_list;
+
/* The set of possible interrupts */
struct sonypi_irq_list {
u16 irq;
@@ -180,6 +192,9 @@ static struct sonypi_irq_list sonypi_type2_irq_list[] = {
{ 0, 0x00 } /* no IRQ, 0x00 in SIRQ in AML */
};
+/* same as in type2 models */
+static struct sonypi_irq_list *sonypi_type3_irq_list = sonypi_type2_irq_list;
+
#define SONYPI_CAMERA_BRIGHTNESS 0
#define SONYPI_CAMERA_CONTRAST 1
#define SONYPI_CAMERA_HUE 2
@@ -223,6 +238,7 @@ static struct sonypi_irq_list sonypi_type2_irq_list[] = {
#define SONYPI_MEYE_MASK 0x00000400
#define SONYPI_MEMORYSTICK_MASK 0x00000800
#define SONYPI_BATTERY_MASK 0x00001000
+#define SONYPI_WIRELESS_MASK 0x00002000
struct sonypi_event {
u8 data;
@@ -305,6 +321,13 @@ static struct sonypi_event sonypi_blueev[] = {
{ 0, 0 }
};
+/* The set of possible wireless events */
+static struct sonypi_event sonypi_wlessev[] = {
+ { 0x59, SONYPI_EVENT_WIRELESS_ON },
+ { 0x5a, SONYPI_EVENT_WIRELESS_OFF },
+ { 0, 0 }
+};
+
/* The set of possible back button events */
static struct sonypi_event sonypi_backev[] = {
{ 0x20, SONYPI_EVENT_BACK_PRESSED },
@@ -383,7 +406,6 @@ static struct sonypi_eventtypes {
{ SONYPI_DEVICE_MODEL_TYPE2, 0x31, SONYPI_BLUETOOTH_MASK, sonypi_blueev },
{ SONYPI_DEVICE_MODEL_TYPE2, 0x08, SONYPI_PKEY_MASK, sonypi_pkeyev },
{ SONYPI_DEVICE_MODEL_TYPE2, 0x11, SONYPI_BACK_MASK, sonypi_backev },
- { SONYPI_DEVICE_MODEL_TYPE2, 0x08, SONYPI_HELP_MASK, sonypi_helpev },
{ SONYPI_DEVICE_MODEL_TYPE2, 0x21, SONYPI_HELP_MASK, sonypi_helpev },
{ SONYPI_DEVICE_MODEL_TYPE2, 0x21, SONYPI_ZOOM_MASK, sonypi_zoomev },
{ SONYPI_DEVICE_MODEL_TYPE2, 0x20, SONYPI_THUMBPHRASE_MASK, sonypi_thumbphraseev },
@@ -391,6 +413,12 @@ static struct sonypi_eventtypes {
{ SONYPI_DEVICE_MODEL_TYPE2, 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev },
{ SONYPI_DEVICE_MODEL_TYPE2, 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev },
+ { SONYPI_DEVICE_MODEL_TYPE3, 0, 0xffffffff, sonypi_releaseev },
+ { SONYPI_DEVICE_MODEL_TYPE3, 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
+ { SONYPI_DEVICE_MODEL_TYPE3, 0x31, SONYPI_WIRELESS_MASK, sonypi_wlessev },
+ { SONYPI_DEVICE_MODEL_TYPE3, 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
+ { SONYPI_DEVICE_MODEL_TYPE3, 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev },
+ { SONYPI_DEVICE_MODEL_TYPE3, 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev },
{ 0 }
};
@@ -563,6 +591,23 @@ static void sonypi_type2_srs(void)
udelay(10);
}
+static void sonypi_type3_srs(void)
+{
+ u16 v16;
+ u8 v8;
+
+ /* This model type uses the same initialiazation of
+ * the embedded controller as the type2 models. */
+ sonypi_type2_srs();
+
+ /* Initialization of PCI config space of the LPC interface bridge. */
+ v16 = (sonypi_device.ioport1 & 0xFFF0) | 0x01;
+ pci_write_config_word(sonypi_device.dev, SONYPI_TYPE3_GID2, v16);
+ pci_read_config_byte(sonypi_device.dev, SONYPI_TYPE3_MISC, &v8);
+ v8 = (v8 & 0xCF) | 0x10;
+ pci_write_config_byte(sonypi_device.dev, SONYPI_TYPE3_MISC, v8);
+}
+
/* Disables the device - this comes from the AML code in the ACPI bios */
static void sonypi_type1_dis(void)
{
@@ -587,6 +632,13 @@ static void sonypi_type2_dis(void)
printk(KERN_WARNING "ec_write failed\n");
}
+static void sonypi_type3_dis(void)
+{
+ sonypi_type2_dis();
+ udelay(10);
+ pci_write_config_word(sonypi_device.dev, SONYPI_TYPE3_GID2, 0);
+}
+
static u8 sonypi_call1(u8 dev)
{
u8 v1, v2;
@@ -1067,10 +1119,17 @@ static struct miscdevice sonypi_misc_device = {
static void sonypi_enable(unsigned int camera_on)
{
- if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2)
- sonypi_type2_srs();
- else
+ switch (sonypi_device.model) {
+ case SONYPI_DEVICE_MODEL_TYPE1:
sonypi_type1_srs();
+ break;
+ case SONYPI_DEVICE_MODEL_TYPE2:
+ sonypi_type2_srs();
+ break;
+ case SONYPI_DEVICE_MODEL_TYPE3:
+ sonypi_type3_srs();
+ break;
+ }
sonypi_call1(0x82);
sonypi_call2(0x81, 0xff);
@@ -1094,10 +1153,18 @@ static int sonypi_disable(void)
if (!SONYPI_ACPI_ACTIVE && fnkeyinit)
outb(0xf1, 0xb2);
- if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2)
- sonypi_type2_dis();
- else
+ switch (sonypi_device.model) {
+ case SONYPI_DEVICE_MODEL_TYPE1:
sonypi_type1_dis();
+ break;
+ case SONYPI_DEVICE_MODEL_TYPE2:
+ sonypi_type2_dis();
+ break;
+ case SONYPI_DEVICE_MODEL_TYPE3:
+ sonypi_type3_dis();
+ break;
+ }
+
return 0;
}
@@ -1143,12 +1210,16 @@ static int __devinit sonypi_probe(void)
struct sonypi_irq_list *irq_list;
struct pci_dev *pcidev;
- pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_82371AB_3, NULL);
+ if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_82371AB_3, NULL)))
+ sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE1;
+ else if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_ICH6_1, NULL)))
+ sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE3;
+ else
+ sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE2;
sonypi_device.dev = pcidev;
- sonypi_device.model = pcidev ?
- SONYPI_DEVICE_MODEL_TYPE1 : SONYPI_DEVICE_MODEL_TYPE2;
spin_lock_init(&sonypi_device.fifo_lock);
sonypi_device.fifo = kfifo_alloc(SONYPI_BUF_SIZE, GFP_KERNEL,
@@ -1176,16 +1247,22 @@ static int __devinit sonypi_probe(void)
goto out_miscreg;
}
- if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2) {
+
+ if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE1) {
+ ioport_list = sonypi_type1_ioport_list;
+ sonypi_device.region_size = SONYPI_TYPE1_REGION_SIZE;
+ sonypi_device.evtype_offset = SONYPI_TYPE1_EVTYPE_OFFSET;
+ irq_list = sonypi_type1_irq_list;
+ } else if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2) {
ioport_list = sonypi_type2_ioport_list;
sonypi_device.region_size = SONYPI_TYPE2_REGION_SIZE;
sonypi_device.evtype_offset = SONYPI_TYPE2_EVTYPE_OFFSET;
irq_list = sonypi_type2_irq_list;
} else {
- ioport_list = sonypi_type1_ioport_list;
- sonypi_device.region_size = SONYPI_TYPE1_REGION_SIZE;
- sonypi_device.evtype_offset = SONYPI_TYPE1_EVTYPE_OFFSET;
- irq_list = sonypi_type1_irq_list;
+ ioport_list = sonypi_type3_ioport_list;
+ sonypi_device.region_size = SONYPI_TYPE3_REGION_SIZE;
+ sonypi_device.evtype_offset = SONYPI_TYPE3_EVTYPE_OFFSET;
+ irq_list = sonypi_type3_irq_list;
}
for (i = 0; ioport_list[i].port1; i++) {
@@ -1274,11 +1351,10 @@ static int __devinit sonypi_probe(void)
printk(KERN_INFO "sonypi: Sony Programmable I/O Controller Driver"
"v%s.\n", SONYPI_DRIVER_VERSION);
- printk(KERN_INFO "sonypi: detected %s model, "
+ printk(KERN_INFO "sonypi: detected type%d model, "
"verbose = %d, fnkeyinit = %s, camera = %s, "
"compat = %s, mask = 0x%08lx, useinput = %s, acpi = %s\n",
- (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE1) ?
- "type1" : "type2",
+ sonypi_device.model,
verbose,
fnkeyinit ? "on" : "off",
camera ? "on" : "off",
diff --git a/drivers/char/tpm/tpm_atmel.c b/drivers/char/tpm/tpm_atmel.c
index cc2cc77fd174..c0d64914595f 100644
--- a/drivers/char/tpm/tpm_atmel.c
+++ b/drivers/char/tpm/tpm_atmel.c
@@ -206,6 +206,9 @@ static struct pci_device_id tpm_pci_tbl[] __devinitdata = {
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0)},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12)},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_0)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0)},
{PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_LPC)},
{PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6LPC)},
{0,}
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 6e4be3bb2d89..9d657127f313 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -153,7 +153,6 @@ static int tty_release(struct inode *, struct file *);
int tty_ioctl(struct inode * inode, struct file * file,
unsigned int cmd, unsigned long arg);
static int tty_fasync(int fd, struct file * filp, int on);
-extern void rs_360_init(void);
static void release_mem(struct tty_struct *tty, int idx);
@@ -2911,11 +2910,6 @@ void __init console_init(void)
#ifdef CONFIG_EARLY_PRINTK
disable_early_printk();
#endif
-#ifdef CONFIG_SERIAL_68360
- /* This is not a console initcall. I know not what it's doing here.
- So I haven't moved it. dwmw2 */
- rs_360_init();
-#endif
call = __con_initcall_start;
while (call < __con_initcall_end) {
(*call)();
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index 665103ccaee8..b8d0c290b0db 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -434,21 +434,25 @@ void invert_screen(struct vc_data *vc, int offset, int count, int viewed)
/* used by selection: complement pointer position */
void complement_pos(struct vc_data *vc, int offset)
{
- static unsigned short *p;
+ static int old_offset = -1;
static unsigned short old;
static unsigned short oldx, oldy;
WARN_CONSOLE_UNLOCKED();
- if (p) {
- scr_writew(old, p);
+ if (old_offset != -1 && old_offset >= 0 &&
+ old_offset < vc->vc_screenbuf_size) {
+ scr_writew(old, screenpos(vc, old_offset, 1));
if (DO_UPDATE(vc))
vc->vc_sw->con_putc(vc, old, oldy, oldx);
}
- if (offset == -1)
- p = NULL;
- else {
+
+ old_offset = offset;
+
+ if (offset != -1 && offset >= 0 &&
+ offset < vc->vc_screenbuf_size) {
unsigned short new;
+ unsigned short *p;
p = screenpos(vc, offset, 1);
old = scr_readw(p);
new = old ^ vc->vc_complement_mask;
@@ -459,6 +463,7 @@ void complement_pos(struct vc_data *vc, int offset)
vc->vc_sw->con_putc(vc, new, oldy, oldx);
}
}
+
}
static void insert_char(struct vc_data *vc, unsigned int nr)
@@ -2272,7 +2277,9 @@ int tioclinux(struct tty_struct *tty, unsigned long arg)
ret = paste_selection(tty);
break;
case TIOCL_UNBLANKSCREEN:
+ acquire_console_sem();
unblank_screen();
+ release_console_sem();
break;
case TIOCL_SELLOADLUT:
ret = sel_loadlut(p);
@@ -2317,8 +2324,10 @@ int tioclinux(struct tty_struct *tty, unsigned long arg)
}
break;
case TIOCL_BLANKSCREEN: /* until explicitly unblanked, not only poked */
+ acquire_console_sem();
ignore_poke = 1;
do_blank_screen(0);
+ release_console_sem();
break;
case TIOCL_BLANKEDSCREEN:
ret = console_blanked;
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
index 5b29c3b2a331..327b58e64875 100644
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -58,4 +58,31 @@ config EFI_PCDP
See <http://www.dig64.org/specifications/DIG64_HCDPv20_042804.pdf>
+config DELL_RBU
+ tristate "BIOS update support for DELL systems via sysfs"
+ select FW_LOADER
+ help
+ Say m if you want to have the option of updating the BIOS for your
+ DELL system. Note you need a Dell OpenManage or Dell Update package (DUP)
+ supporting application to comunicate with the BIOS regarding the new
+ image for the image update to take effect.
+ See <file:Documentation/dell_rbu.txt> for more details on the driver.
+
+config DCDBAS
+ tristate "Dell Systems Management Base Driver"
+ depends on X86 || X86_64
+ default m
+ help
+ The Dell Systems Management Base Driver provides a sysfs interface
+ for systems management software to perform System Management
+ Interrupts (SMIs) and Host Control Actions (system power cycle or
+ power off after OS shutdown) on certain Dell systems.
+
+ See <file:Documentation/dcdbas.txt> for more details on the driver
+ and the Dell systems on which Dell systems management software makes
+ use of this driver.
+
+ Say Y or M here to enable the driver for use by Dell systems
+ management software such as Dell OpenManage.
+
endmenu
diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile
index 90fd0b26db8b..85429979d0db 100644
--- a/drivers/firmware/Makefile
+++ b/drivers/firmware/Makefile
@@ -4,3 +4,5 @@
obj-$(CONFIG_EDD) += edd.o
obj-$(CONFIG_EFI_VARS) += efivars.o
obj-$(CONFIG_EFI_PCDP) += pcdp.o
+obj-$(CONFIG_DELL_RBU) += dell_rbu.o
+obj-$(CONFIG_DCDBAS) += dcdbas.o
diff --git a/drivers/firmware/dcdbas.c b/drivers/firmware/dcdbas.c
new file mode 100644
index 000000000000..955537fe9958
--- /dev/null
+++ b/drivers/firmware/dcdbas.c
@@ -0,0 +1,596 @@
+/*
+ * dcdbas.c: Dell Systems Management Base Driver
+ *
+ * The Dell Systems Management Base Driver provides a sysfs interface for
+ * systems management software to perform System Management Interrupts (SMIs)
+ * and Host Control Actions (power cycle or power off after OS shutdown) on
+ * Dell systems.
+ *
+ * See Documentation/dcdbas.txt for more information.
+ *
+ * Copyright (C) 1995-2005 Dell Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License v2.0 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mc146818rtc.h>
+#include <linux/module.h>
+#include <linux/reboot.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <asm/io.h>
+#include <asm/semaphore.h>
+
+#include "dcdbas.h"
+
+#define DRIVER_NAME "dcdbas"
+#define DRIVER_VERSION "5.6.0-1"
+#define DRIVER_DESCRIPTION "Dell Systems Management Base Driver"
+
+static struct platform_device *dcdbas_pdev;
+
+static u8 *smi_data_buf;
+static dma_addr_t smi_data_buf_handle;
+static unsigned long smi_data_buf_size;
+static u32 smi_data_buf_phys_addr;
+static DECLARE_MUTEX(smi_data_lock);
+
+static unsigned int host_control_action;
+static unsigned int host_control_smi_type;
+static unsigned int host_control_on_shutdown;
+
+/**
+ * smi_data_buf_free: free SMI data buffer
+ */
+static void smi_data_buf_free(void)
+{
+ if (!smi_data_buf)
+ return;
+
+ dev_dbg(&dcdbas_pdev->dev, "%s: phys: %x size: %lu\n",
+ __FUNCTION__, smi_data_buf_phys_addr, smi_data_buf_size);
+
+ dma_free_coherent(&dcdbas_pdev->dev, smi_data_buf_size, smi_data_buf,
+ smi_data_buf_handle);
+ smi_data_buf = NULL;
+ smi_data_buf_handle = 0;
+ smi_data_buf_phys_addr = 0;
+ smi_data_buf_size = 0;
+}
+
+/**
+ * smi_data_buf_realloc: grow SMI data buffer if needed
+ */
+static int smi_data_buf_realloc(unsigned long size)
+{
+ void *buf;
+ dma_addr_t handle;
+
+ if (smi_data_buf_size >= size)
+ return 0;
+
+ if (size > MAX_SMI_DATA_BUF_SIZE)
+ return -EINVAL;
+
+ /* new buffer is needed */
+ buf = dma_alloc_coherent(&dcdbas_pdev->dev, size, &handle, GFP_KERNEL);
+ if (!buf) {
+ dev_dbg(&dcdbas_pdev->dev,
+ "%s: failed to allocate memory size %lu\n",
+ __FUNCTION__, size);
+ return -ENOMEM;
+ }
+ /* memory zeroed by dma_alloc_coherent */
+
+ if (smi_data_buf)
+ memcpy(buf, smi_data_buf, smi_data_buf_size);
+
+ /* free any existing buffer */
+ smi_data_buf_free();
+
+ /* set up new buffer for use */
+ smi_data_buf = buf;
+ smi_data_buf_handle = handle;
+ smi_data_buf_phys_addr = (u32) virt_to_phys(buf);
+ smi_data_buf_size = size;
+
+ dev_dbg(&dcdbas_pdev->dev, "%s: phys: %x size: %lu\n",
+ __FUNCTION__, smi_data_buf_phys_addr, smi_data_buf_size);
+
+ return 0;
+}
+
+static ssize_t smi_data_buf_phys_addr_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%x\n", smi_data_buf_phys_addr);
+}
+
+static ssize_t smi_data_buf_size_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%lu\n", smi_data_buf_size);
+}
+
+static ssize_t smi_data_buf_size_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long buf_size;
+ ssize_t ret;
+
+ buf_size = simple_strtoul(buf, NULL, 10);
+
+ /* make sure SMI data buffer is at least buf_size */
+ down(&smi_data_lock);
+ ret = smi_data_buf_realloc(buf_size);
+ up(&smi_data_lock);
+ if (ret)
+ return ret;
+
+ return count;
+}
+
+static ssize_t smi_data_read(struct kobject *kobj, char *buf, loff_t pos,
+ size_t count)
+{
+ size_t max_read;
+ ssize_t ret;
+
+ down(&smi_data_lock);
+
+ if (pos >= smi_data_buf_size) {
+ ret = 0;
+ goto out;
+ }
+
+ max_read = smi_data_buf_size - pos;
+ ret = min(max_read, count);
+ memcpy(buf, smi_data_buf + pos, ret);
+out:
+ up(&smi_data_lock);
+ return ret;
+}
+
+static ssize_t smi_data_write(struct kobject *kobj, char *buf, loff_t pos,
+ size_t count)
+{
+ ssize_t ret;
+
+ down(&smi_data_lock);
+
+ ret = smi_data_buf_realloc(pos + count);
+ if (ret)
+ goto out;
+
+ memcpy(smi_data_buf + pos, buf, count);
+ ret = count;
+out:
+ up(&smi_data_lock);
+ return ret;
+}
+
+static ssize_t host_control_action_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%u\n", host_control_action);
+}
+
+static ssize_t host_control_action_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ ssize_t ret;
+
+ /* make sure buffer is available for host control command */
+ down(&smi_data_lock);
+ ret = smi_data_buf_realloc(sizeof(struct apm_cmd));
+ up(&smi_data_lock);
+ if (ret)
+ return ret;
+
+ host_control_action = simple_strtoul(buf, NULL, 10);
+ return count;
+}
+
+static ssize_t host_control_smi_type_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%u\n", host_control_smi_type);
+}
+
+static ssize_t host_control_smi_type_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ host_control_smi_type = simple_strtoul(buf, NULL, 10);
+ return count;
+}
+
+static ssize_t host_control_on_shutdown_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%u\n", host_control_on_shutdown);
+}
+
+static ssize_t host_control_on_shutdown_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ host_control_on_shutdown = simple_strtoul(buf, NULL, 10);
+ return count;
+}
+
+/**
+ * smi_request: generate SMI request
+ *
+ * Called with smi_data_lock.
+ */
+static int smi_request(struct smi_cmd *smi_cmd)
+{
+ cpumask_t old_mask;
+ int ret = 0;
+
+ if (smi_cmd->magic != SMI_CMD_MAGIC) {
+ dev_info(&dcdbas_pdev->dev, "%s: invalid magic value\n",
+ __FUNCTION__);
+ return -EBADR;
+ }
+
+ /* SMI requires CPU 0 */
+ old_mask = current->cpus_allowed;
+ set_cpus_allowed(current, cpumask_of_cpu(0));
+ if (smp_processor_id() != 0) {
+ dev_dbg(&dcdbas_pdev->dev, "%s: failed to get CPU 0\n",
+ __FUNCTION__);
+ ret = -EBUSY;
+ goto out;
+ }
+
+ /* generate SMI */
+ asm volatile (
+ "outb %b0,%w1"
+ : /* no output args */
+ : "a" (smi_cmd->command_code),
+ "d" (smi_cmd->command_address),
+ "b" (smi_cmd->ebx),
+ "c" (smi_cmd->ecx)
+ : "memory"
+ );
+
+out:
+ set_cpus_allowed(current, old_mask);
+ return ret;
+}
+
+/**
+ * smi_request_store:
+ *
+ * The valid values are:
+ * 0: zero SMI data buffer
+ * 1: generate calling interface SMI
+ * 2: generate raw SMI
+ *
+ * User application writes smi_cmd to smi_data before telling driver
+ * to generate SMI.
+ */
+static ssize_t smi_request_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct smi_cmd *smi_cmd;
+ unsigned long val = simple_strtoul(buf, NULL, 10);
+ ssize_t ret;
+
+ down(&smi_data_lock);
+
+ if (smi_data_buf_size < sizeof(struct smi_cmd)) {
+ ret = -ENODEV;
+ goto out;
+ }
+ smi_cmd = (struct smi_cmd *)smi_data_buf;
+
+ switch (val) {
+ case 2:
+ /* Raw SMI */
+ ret = smi_request(smi_cmd);
+ if (!ret)
+ ret = count;
+ break;
+ case 1:
+ /* Calling Interface SMI */
+ smi_cmd->ebx = (u32) virt_to_phys(smi_cmd->command_buffer);
+ ret = smi_request(smi_cmd);
+ if (!ret)
+ ret = count;
+ break;
+ case 0:
+ memset(smi_data_buf, 0, smi_data_buf_size);
+ ret = count;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+out:
+ up(&smi_data_lock);
+ return ret;
+}
+
+/**
+ * host_control_smi: generate host control SMI
+ *
+ * Caller must set up the host control command in smi_data_buf.
+ */
+static int host_control_smi(void)
+{
+ struct apm_cmd *apm_cmd;
+ u8 *data;
+ unsigned long flags;
+ u32 num_ticks;
+ s8 cmd_status;
+ u8 index;
+
+ apm_cmd = (struct apm_cmd *)smi_data_buf;
+ apm_cmd->status = ESM_STATUS_CMD_UNSUCCESSFUL;
+
+ switch (host_control_smi_type) {
+ case HC_SMITYPE_TYPE1:
+ spin_lock_irqsave(&rtc_lock, flags);
+ /* write SMI data buffer physical address */
+ data = (u8 *)&smi_data_buf_phys_addr;
+ for (index = PE1300_CMOS_CMD_STRUCT_PTR;
+ index < (PE1300_CMOS_CMD_STRUCT_PTR + 4);
+ index++, data++) {
+ outb(index,
+ (CMOS_BASE_PORT + CMOS_PAGE2_INDEX_PORT_PIIX4));
+ outb(*data,
+ (CMOS_BASE_PORT + CMOS_PAGE2_DATA_PORT_PIIX4));
+ }
+
+ /* first set status to -1 as called by spec */
+ cmd_status = ESM_STATUS_CMD_UNSUCCESSFUL;
+ outb((u8) cmd_status, PCAT_APM_STATUS_PORT);
+
+ /* generate SMM call */
+ outb(ESM_APM_CMD, PCAT_APM_CONTROL_PORT);
+ spin_unlock_irqrestore(&rtc_lock, flags);
+
+ /* wait a few to see if it executed */
+ num_ticks = TIMEOUT_USEC_SHORT_SEMA_BLOCKING;
+ while ((cmd_status = inb(PCAT_APM_STATUS_PORT))
+ == ESM_STATUS_CMD_UNSUCCESSFUL) {
+ num_ticks--;
+ if (num_ticks == EXPIRED_TIMER)
+ return -ETIME;
+ }
+ break;
+
+ case HC_SMITYPE_TYPE2:
+ case HC_SMITYPE_TYPE3:
+ spin_lock_irqsave(&rtc_lock, flags);
+ /* write SMI data buffer physical address */
+ data = (u8 *)&smi_data_buf_phys_addr;
+ for (index = PE1400_CMOS_CMD_STRUCT_PTR;
+ index < (PE1400_CMOS_CMD_STRUCT_PTR + 4);
+ index++, data++) {
+ outb(index, (CMOS_BASE_PORT + CMOS_PAGE1_INDEX_PORT));
+ outb(*data, (CMOS_BASE_PORT + CMOS_PAGE1_DATA_PORT));
+ }
+
+ /* generate SMM call */
+ if (host_control_smi_type == HC_SMITYPE_TYPE3)
+ outb(ESM_APM_CMD, PCAT_APM_CONTROL_PORT);
+ else
+ outb(ESM_APM_CMD, PE1400_APM_CONTROL_PORT);
+
+ /* restore RTC index pointer since it was written to above */
+ CMOS_READ(RTC_REG_C);
+ spin_unlock_irqrestore(&rtc_lock, flags);
+
+ /* read control port back to serialize write */
+ cmd_status = inb(PE1400_APM_CONTROL_PORT);
+
+ /* wait a few to see if it executed */
+ num_ticks = TIMEOUT_USEC_SHORT_SEMA_BLOCKING;
+ while (apm_cmd->status == ESM_STATUS_CMD_UNSUCCESSFUL) {
+ num_ticks--;
+ if (num_ticks == EXPIRED_TIMER)
+ return -ETIME;
+ }
+ break;
+
+ default:
+ dev_dbg(&dcdbas_pdev->dev, "%s: invalid SMI type %u\n",
+ __FUNCTION__, host_control_smi_type);
+ return -ENOSYS;
+ }
+
+ return 0;
+}
+
+/**
+ * dcdbas_host_control: initiate host control
+ *
+ * This function is called by the driver after the system has
+ * finished shutting down if the user application specified a
+ * host control action to perform on shutdown. It is safe to
+ * use smi_data_buf at this point because the system has finished
+ * shutting down and no userspace apps are running.
+ */
+static void dcdbas_host_control(void)
+{
+ struct apm_cmd *apm_cmd;
+ u8 action;
+
+ if (host_control_action == HC_ACTION_NONE)
+ return;
+
+ action = host_control_action;
+ host_control_action = HC_ACTION_NONE;
+
+ if (!smi_data_buf) {
+ dev_dbg(&dcdbas_pdev->dev, "%s: no SMI buffer\n", __FUNCTION__);
+ return;
+ }
+
+ if (smi_data_buf_size < sizeof(struct apm_cmd)) {
+ dev_dbg(&dcdbas_pdev->dev, "%s: SMI buffer too small\n",
+ __FUNCTION__);
+ return;
+ }
+
+ apm_cmd = (struct apm_cmd *)smi_data_buf;
+
+ /* power off takes precedence */
+ if (action & HC_ACTION_HOST_CONTROL_POWEROFF) {
+ apm_cmd->command = ESM_APM_POWER_CYCLE;
+ apm_cmd->reserved = 0;
+ *((s16 *)&apm_cmd->parameters.shortreq.parm[0]) = (s16) 0;
+ host_control_smi();
+ } else if (action & HC_ACTION_HOST_CONTROL_POWERCYCLE) {
+ apm_cmd->command = ESM_APM_POWER_CYCLE;
+ apm_cmd->reserved = 0;
+ *((s16 *)&apm_cmd->parameters.shortreq.parm[0]) = (s16) 20;
+ host_control_smi();
+ }
+}
+
+/**
+ * dcdbas_reboot_notify: handle reboot notification for host control
+ */
+static int dcdbas_reboot_notify(struct notifier_block *nb, unsigned long code,
+ void *unused)
+{
+ static unsigned int notify_cnt = 0;
+
+ switch (code) {
+ case SYS_DOWN:
+ case SYS_HALT:
+ case SYS_POWER_OFF:
+ if (host_control_on_shutdown) {
+ /* firmware is going to perform host control action */
+ if (++notify_cnt == 2) {
+ printk(KERN_WARNING
+ "Please wait for shutdown "
+ "action to complete...\n");
+ dcdbas_host_control();
+ }
+ /*
+ * register again and initiate the host control
+ * action on the second notification to allow
+ * everyone that registered to be notified
+ */
+ register_reboot_notifier(nb);
+ }
+ break;
+ }
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block dcdbas_reboot_nb = {
+ .notifier_call = dcdbas_reboot_notify,
+ .next = NULL,
+ .priority = 0
+};
+
+static DCDBAS_BIN_ATTR_RW(smi_data);
+
+static struct bin_attribute *dcdbas_bin_attrs[] = {
+ &bin_attr_smi_data,
+ NULL
+};
+
+static DCDBAS_DEV_ATTR_RW(smi_data_buf_size);
+static DCDBAS_DEV_ATTR_RO(smi_data_buf_phys_addr);
+static DCDBAS_DEV_ATTR_WO(smi_request);
+static DCDBAS_DEV_ATTR_RW(host_control_action);
+static DCDBAS_DEV_ATTR_RW(host_control_smi_type);
+static DCDBAS_DEV_ATTR_RW(host_control_on_shutdown);
+
+static struct device_attribute *dcdbas_dev_attrs[] = {
+ &dev_attr_smi_data_buf_size,
+ &dev_attr_smi_data_buf_phys_addr,
+ &dev_attr_smi_request,
+ &dev_attr_host_control_action,
+ &dev_attr_host_control_smi_type,
+ &dev_attr_host_control_on_shutdown,
+ NULL
+};
+
+/**
+ * dcdbas_init: initialize driver
+ */
+static int __init dcdbas_init(void)
+{
+ int i;
+
+ host_control_action = HC_ACTION_NONE;
+ host_control_smi_type = HC_SMITYPE_NONE;
+
+ dcdbas_pdev = platform_device_register_simple(DRIVER_NAME, -1, NULL, 0);
+ if (IS_ERR(dcdbas_pdev))
+ return PTR_ERR(dcdbas_pdev);
+
+ /*
+ * BIOS SMI calls require buffer addresses be in 32-bit address space.
+ * This is done by setting the DMA mask below.
+ */
+ dcdbas_pdev->dev.coherent_dma_mask = DMA_32BIT_MASK;
+ dcdbas_pdev->dev.dma_mask = &dcdbas_pdev->dev.coherent_dma_mask;
+
+ register_reboot_notifier(&dcdbas_reboot_nb);
+
+ for (i = 0; dcdbas_bin_attrs[i]; i++)
+ sysfs_create_bin_file(&dcdbas_pdev->dev.kobj,
+ dcdbas_bin_attrs[i]);
+
+ for (i = 0; dcdbas_dev_attrs[i]; i++)
+ device_create_file(&dcdbas_pdev->dev, dcdbas_dev_attrs[i]);
+
+ dev_info(&dcdbas_pdev->dev, "%s (version %s)\n",
+ DRIVER_DESCRIPTION, DRIVER_VERSION);
+
+ return 0;
+}
+
+/**
+ * dcdbas_exit: perform driver cleanup
+ */
+static void __exit dcdbas_exit(void)
+{
+ platform_device_unregister(dcdbas_pdev);
+ unregister_reboot_notifier(&dcdbas_reboot_nb);
+ smi_data_buf_free();
+}
+
+module_init(dcdbas_init);
+module_exit(dcdbas_exit);
+
+MODULE_DESCRIPTION(DRIVER_DESCRIPTION " (version " DRIVER_VERSION ")");
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_AUTHOR("Dell Inc.");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/firmware/dcdbas.h b/drivers/firmware/dcdbas.h
new file mode 100644
index 000000000000..58a85182b3e8
--- /dev/null
+++ b/drivers/firmware/dcdbas.h
@@ -0,0 +1,107 @@
+/*
+ * dcdbas.h: Definitions for Dell Systems Management Base driver
+ *
+ * Copyright (C) 1995-2005 Dell Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License v2.0 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _DCDBAS_H_
+#define _DCDBAS_H_
+
+#include <linux/device.h>
+#include <linux/input.h>
+#include <linux/sysfs.h>
+#include <linux/types.h>
+
+#define MAX_SMI_DATA_BUF_SIZE (256 * 1024)
+
+#define HC_ACTION_NONE (0)
+#define HC_ACTION_HOST_CONTROL_POWEROFF BIT(1)
+#define HC_ACTION_HOST_CONTROL_POWERCYCLE BIT(2)
+
+#define HC_SMITYPE_NONE (0)
+#define HC_SMITYPE_TYPE1 (1)
+#define HC_SMITYPE_TYPE2 (2)
+#define HC_SMITYPE_TYPE3 (3)
+
+#define ESM_APM_CMD (0x0A0)
+#define ESM_APM_POWER_CYCLE (0x10)
+#define ESM_STATUS_CMD_UNSUCCESSFUL (-1)
+
+#define CMOS_BASE_PORT (0x070)
+#define CMOS_PAGE1_INDEX_PORT (0)
+#define CMOS_PAGE1_DATA_PORT (1)
+#define CMOS_PAGE2_INDEX_PORT_PIIX4 (2)
+#define CMOS_PAGE2_DATA_PORT_PIIX4 (3)
+#define PE1400_APM_CONTROL_PORT (0x0B0)
+#define PCAT_APM_CONTROL_PORT (0x0B2)
+#define PCAT_APM_STATUS_PORT (0x0B3)
+#define PE1300_CMOS_CMD_STRUCT_PTR (0x38)
+#define PE1400_CMOS_CMD_STRUCT_PTR (0x70)
+
+#define MAX_SYSMGMT_SHORTCMD_PARMBUF_LEN (14)
+#define MAX_SYSMGMT_LONGCMD_SGENTRY_NUM (16)
+
+#define TIMEOUT_USEC_SHORT_SEMA_BLOCKING (10000)
+#define EXPIRED_TIMER (0)
+
+#define SMI_CMD_MAGIC (0x534D4931)
+
+#define DCDBAS_DEV_ATTR_RW(_name) \
+ DEVICE_ATTR(_name,0600,_name##_show,_name##_store);
+
+#define DCDBAS_DEV_ATTR_RO(_name) \
+ DEVICE_ATTR(_name,0400,_name##_show,NULL);
+
+#define DCDBAS_DEV_ATTR_WO(_name) \
+ DEVICE_ATTR(_name,0200,NULL,_name##_store);
+
+#define DCDBAS_BIN_ATTR_RW(_name) \
+struct bin_attribute bin_attr_##_name = { \
+ .attr = { .name = __stringify(_name), \
+ .mode = 0600, \
+ .owner = THIS_MODULE }, \
+ .read = _name##_read, \
+ .write = _name##_write, \
+}
+
+struct smi_cmd {
+ __u32 magic;
+ __u32 ebx;
+ __u32 ecx;
+ __u16 command_address;
+ __u8 command_code;
+ __u8 reserved;
+ __u8 command_buffer[1];
+} __attribute__ ((packed));
+
+struct apm_cmd {
+ __u8 command;
+ __s8 status;
+ __u16 reserved;
+ union {
+ struct {
+ __u8 parm[MAX_SYSMGMT_SHORTCMD_PARMBUF_LEN];
+ } __attribute__ ((packed)) shortreq;
+
+ struct {
+ __u16 num_sg_entries;
+ struct {
+ __u32 size;
+ __u64 addr;
+ } __attribute__ ((packed))
+ sglist[MAX_SYSMGMT_LONGCMD_SGENTRY_NUM];
+ } __attribute__ ((packed)) longreq;
+ } __attribute__ ((packed)) parameters;
+} __attribute__ ((packed));
+
+#endif /* _DCDBAS_H_ */
+
diff --git a/drivers/firmware/dell_rbu.c b/drivers/firmware/dell_rbu.c
new file mode 100644
index 000000000000..3b865f34a095
--- /dev/null
+++ b/drivers/firmware/dell_rbu.c
@@ -0,0 +1,634 @@
+/*
+ * dell_rbu.c
+ * Bios Update driver for Dell systems
+ * Author: Dell Inc
+ * Abhay Salunke <abhay_salunke@dell.com>
+ *
+ * Copyright (C) 2005 Dell Inc.
+ *
+ * Remote BIOS Update (rbu) driver is used for updating DELL BIOS by
+ * creating entries in the /sys file systems on Linux 2.6 and higher
+ * kernels. The driver supports two mechanism to update the BIOS namely
+ * contiguous and packetized. Both these methods still require having some
+ * application to set the CMOS bit indicating the BIOS to update itself
+ * after a reboot.
+ *
+ * Contiguous method:
+ * This driver writes the incoming data in a monolithic image by allocating
+ * contiguous physical pages large enough to accommodate the incoming BIOS
+ * image size.
+ *
+ * Packetized method:
+ * The driver writes the incoming packet image by allocating a new packet
+ * on every time the packet data is written. This driver requires an
+ * application to break the BIOS image in to fixed sized packet chunks.
+ *
+ * See Documentation/dell_rbu.txt for more info.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License v2.0 as published by
+ * the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <linux/version.h>
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/blkdev.h>
+#include <linux/device.h>
+#include <linux/spinlock.h>
+#include <linux/moduleparam.h>
+#include <linux/firmware.h>
+#include <linux/dma-mapping.h>
+
+MODULE_AUTHOR("Abhay Salunke <abhay_salunke@dell.com>");
+MODULE_DESCRIPTION("Driver for updating BIOS image on DELL systems");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1.0");
+
+#define BIOS_SCAN_LIMIT 0xffffffff
+#define MAX_IMAGE_LENGTH 16
+static struct _rbu_data {
+ void *image_update_buffer;
+ unsigned long image_update_buffer_size;
+ unsigned long bios_image_size;
+ int image_update_ordernum;
+ int dma_alloc;
+ spinlock_t lock;
+ unsigned long packet_read_count;
+ unsigned long packet_write_count;
+ unsigned long num_packets;
+ unsigned long packetsize;
+} rbu_data;
+
+static char image_type[MAX_IMAGE_LENGTH] = "mono";
+module_param_string(image_type, image_type, sizeof(image_type), 0);
+MODULE_PARM_DESC(image_type, "BIOS image type. choose- mono or packet");
+
+struct packet_data {
+ struct list_head list;
+ size_t length;
+ void *data;
+ int ordernum;
+};
+
+static struct packet_data packet_data_head;
+
+static struct platform_device *rbu_device;
+static int context;
+static dma_addr_t dell_rbu_dmaaddr;
+
+static void init_packet_head(void)
+{
+ INIT_LIST_HEAD(&packet_data_head.list);
+ rbu_data.packet_write_count = 0;
+ rbu_data.packet_read_count = 0;
+ rbu_data.num_packets = 0;
+ rbu_data.packetsize = 0;
+}
+
+static int fill_last_packet(void *data, size_t length)
+{
+ struct list_head *ptemp_list;
+ struct packet_data *packet = NULL;
+ int packet_count = 0;
+
+ pr_debug("fill_last_packet: entry \n");
+
+ if (!rbu_data.num_packets) {
+ pr_debug("fill_last_packet: num_packets=0\n");
+ return -ENOMEM;
+ }
+
+ packet_count = rbu_data.num_packets;
+
+ ptemp_list = (&packet_data_head.list)->prev;
+
+ packet = list_entry(ptemp_list, struct packet_data, list);
+
+ if ((rbu_data.packet_write_count + length) > rbu_data.packetsize) {
+ pr_debug("dell_rbu:%s: packet size data "
+ "overrun\n", __FUNCTION__);
+ return -EINVAL;
+ }
+
+ pr_debug("fill_last_packet : buffer = %p\n", packet->data);
+
+ memcpy((packet->data + rbu_data.packet_write_count), data, length);
+
+ if ((rbu_data.packet_write_count + length) == rbu_data.packetsize) {
+ /*
+ * this was the last data chunk in the packet
+ * so reinitialize the packet data counter to zero
+ */
+ rbu_data.packet_write_count = 0;
+ } else
+ rbu_data.packet_write_count += length;
+
+ pr_debug("fill_last_packet: exit \n");
+ return 0;
+}
+
+static int create_packet(size_t length)
+{
+ struct packet_data *newpacket;
+ int ordernum = 0;
+
+ pr_debug("create_packet: entry \n");
+
+ if (!rbu_data.packetsize) {
+ pr_debug("create_packet: packetsize not specified\n");
+ return -EINVAL;
+ }
+
+ newpacket = kmalloc(sizeof(struct packet_data), GFP_KERNEL);
+ if (!newpacket) {
+ printk(KERN_WARNING
+ "dell_rbu:%s: failed to allocate new "
+ "packet\n", __FUNCTION__);
+ return -ENOMEM;
+ }
+
+ ordernum = get_order(length);
+ /*
+ * there is no upper limit on memory
+ * address for packetized mechanism
+ */
+ newpacket->data = (unsigned char *)__get_free_pages(GFP_KERNEL,
+ ordernum);
+
+ pr_debug("create_packet: newpacket %p\n", newpacket->data);
+
+ if (!newpacket->data) {
+ printk(KERN_WARNING
+ "dell_rbu:%s: failed to allocate new "
+ "packet\n", __FUNCTION__);
+ kfree(newpacket);
+ return -ENOMEM;
+ }
+
+ newpacket->ordernum = ordernum;
+ ++rbu_data.num_packets;
+ /*
+ * initialize the newly created packet headers
+ */
+ INIT_LIST_HEAD(&newpacket->list);
+ list_add_tail(&newpacket->list, &packet_data_head.list);
+ /*
+ * packets have fixed size
+ */
+ newpacket->length = rbu_data.packetsize;
+
+ pr_debug("create_packet: exit \n");
+
+ return 0;
+}
+
+static int packetize_data(void *data, size_t length)
+{
+ int rc = 0;
+
+ if (!rbu_data.packet_write_count) {
+ if ((rc = create_packet(length)))
+ return rc;
+ }
+ if ((rc = fill_last_packet(data, length)))
+ return rc;
+
+ return rc;
+}
+
+static int
+do_packet_read(char *data, struct list_head *ptemp_list,
+ int length, int bytes_read, int *list_read_count)
+{
+ void *ptemp_buf;
+ struct packet_data *newpacket = NULL;
+ int bytes_copied = 0;
+ int j = 0;
+
+ newpacket = list_entry(ptemp_list, struct packet_data, list);
+ *list_read_count += newpacket->length;
+
+ if (*list_read_count > bytes_read) {
+ /* point to the start of unread data */
+ j = newpacket->length - (*list_read_count - bytes_read);
+ /* point to the offset in the packet buffer */
+ ptemp_buf = (u8 *) newpacket->data + j;
+ /*
+ * check if there is enough room in
+ * * the incoming buffer
+ */
+ if (length > (*list_read_count - bytes_read))
+ /*
+ * copy what ever is there in this
+ * packet and move on
+ */
+ bytes_copied = (*list_read_count - bytes_read);
+ else
+ /* copy the remaining */
+ bytes_copied = length;
+ memcpy(data, ptemp_buf, bytes_copied);
+ }
+ return bytes_copied;
+}
+
+static int packet_read_list(char *data, size_t * pread_length)
+{
+ struct list_head *ptemp_list;
+ int temp_count = 0;
+ int bytes_copied = 0;
+ int bytes_read = 0;
+ int remaining_bytes = 0;
+ char *pdest = data;
+
+ /* check if we have any packets */
+ if (0 == rbu_data.num_packets)
+ return -ENOMEM;
+
+ remaining_bytes = *pread_length;
+ bytes_read = rbu_data.packet_read_count;
+
+ ptemp_list = (&packet_data_head.list)->next;
+ while (!list_empty(ptemp_list)) {
+ bytes_copied = do_packet_read(pdest, ptemp_list,
+ remaining_bytes, bytes_read,
+ &temp_count);
+ remaining_bytes -= bytes_copied;
+ bytes_read += bytes_copied;
+ pdest += bytes_copied;
+ /*
+ * check if we reached end of buffer before reaching the
+ * last packet
+ */
+ if (remaining_bytes == 0)
+ break;
+
+ ptemp_list = ptemp_list->next;
+ }
+ /*finally set the bytes read */
+ *pread_length = bytes_read - rbu_data.packet_read_count;
+ rbu_data.packet_read_count = bytes_read;
+ return 0;
+}
+
+static void packet_empty_list(void)
+{
+ struct list_head *ptemp_list;
+ struct list_head *pnext_list;
+ struct packet_data *newpacket;
+
+ ptemp_list = (&packet_data_head.list)->next;
+ while (!list_empty(ptemp_list)) {
+ newpacket =
+ list_entry(ptemp_list, struct packet_data, list);
+ pnext_list = ptemp_list->next;
+ list_del(ptemp_list);
+ ptemp_list = pnext_list;
+ /*
+ * zero out the RBU packet memory before freeing
+ * to make sure there are no stale RBU packets left in memory
+ */
+ memset(newpacket->data, 0, rbu_data.packetsize);
+ free_pages((unsigned long)newpacket->data,
+ newpacket->ordernum);
+ kfree(newpacket);
+ }
+ rbu_data.packet_write_count = 0;
+ rbu_data.packet_read_count = 0;
+ rbu_data.num_packets = 0;
+ rbu_data.packetsize = 0;
+}
+
+/*
+ * img_update_free: Frees the buffer allocated for storing BIOS image
+ * Always called with lock held and returned with lock held
+ */
+static void img_update_free(void)
+{
+ if (!rbu_data.image_update_buffer)
+ return;
+ /*
+ * zero out this buffer before freeing it to get rid of any stale
+ * BIOS image copied in memory.
+ */
+ memset(rbu_data.image_update_buffer, 0,
+ rbu_data.image_update_buffer_size);
+ if (rbu_data.dma_alloc == 1)
+ dma_free_coherent(NULL, rbu_data.bios_image_size,
+ rbu_data.image_update_buffer,
+ dell_rbu_dmaaddr);
+ else
+ free_pages((unsigned long)rbu_data.image_update_buffer,
+ rbu_data.image_update_ordernum);
+
+ /*
+ * Re-initialize the rbu_data variables after a free
+ */
+ rbu_data.image_update_ordernum = -1;
+ rbu_data.image_update_buffer = NULL;
+ rbu_data.image_update_buffer_size = 0;
+ rbu_data.bios_image_size = 0;
+ rbu_data.dma_alloc = 0;
+}
+
+/*
+ * img_update_realloc: This function allocates the contiguous pages to
+ * accommodate the requested size of data. The memory address and size
+ * values are stored globally and on every call to this function the new
+ * size is checked to see if more data is required than the existing size.
+ * If true the previous memory is freed and new allocation is done to
+ * accommodate the new size. If the incoming size is less then than the
+ * already allocated size, then that memory is reused. This function is
+ * called with lock held and returns with lock held.
+ */
+static int img_update_realloc(unsigned long size)
+{
+ unsigned char *image_update_buffer = NULL;
+ unsigned long rc;
+ unsigned long img_buf_phys_addr;
+ int ordernum;
+ int dma_alloc = 0;
+
+ /*
+ * check if the buffer of sufficient size has been
+ * already allocated
+ */
+ if (rbu_data.image_update_buffer_size >= size) {
+ /*
+ * check for corruption
+ */
+ if ((size != 0) && (rbu_data.image_update_buffer == NULL)) {
+ printk(KERN_ERR "dell_rbu:%s: corruption "
+ "check failed\n", __FUNCTION__);
+ return -EINVAL;
+ }
+ /*
+ * we have a valid pre-allocated buffer with
+ * sufficient size
+ */
+ return 0;
+ }
+
+ /*
+ * free any previously allocated buffer
+ */
+ img_update_free();
+
+ spin_unlock(&rbu_data.lock);
+
+ ordernum = get_order(size);
+ image_update_buffer =
+ (unsigned char *)__get_free_pages(GFP_KERNEL, ordernum);
+
+ img_buf_phys_addr =
+ (unsigned long)virt_to_phys(image_update_buffer);
+
+ if (img_buf_phys_addr > BIOS_SCAN_LIMIT) {
+ free_pages((unsigned long)image_update_buffer, ordernum);
+ ordernum = -1;
+ image_update_buffer = dma_alloc_coherent(NULL, size,
+ &dell_rbu_dmaaddr,
+ GFP_KERNEL);
+ dma_alloc = 1;
+ }
+
+ spin_lock(&rbu_data.lock);
+
+ if (image_update_buffer != NULL) {
+ rbu_data.image_update_buffer = image_update_buffer;
+ rbu_data.image_update_buffer_size = size;
+ rbu_data.bios_image_size =
+ rbu_data.image_update_buffer_size;
+ rbu_data.image_update_ordernum = ordernum;
+ rbu_data.dma_alloc = dma_alloc;
+ rc = 0;
+ } else {
+ pr_debug("Not enough memory for image update:"
+ "size = %ld\n", size);
+ rc = -ENOMEM;
+ }
+
+ return rc;
+}
+
+static ssize_t read_packet_data(char *buffer, loff_t pos, size_t count)
+{
+ int retval;
+ size_t bytes_left;
+ size_t data_length;
+ char *ptempBuf = buffer;
+ unsigned long imagesize;
+
+ /* check to see if we have something to return */
+ if (rbu_data.num_packets == 0) {
+ pr_debug("read_packet_data: no packets written\n");
+ retval = -ENOMEM;
+ goto read_rbu_data_exit;
+ }
+
+ imagesize = rbu_data.num_packets * rbu_data.packetsize;
+
+ if (pos > imagesize) {
+ retval = 0;
+ printk(KERN_WARNING "dell_rbu:read_packet_data: "
+ "data underrun\n");
+ goto read_rbu_data_exit;
+ }
+
+ bytes_left = imagesize - pos;
+ data_length = min(bytes_left, count);
+
+ if ((retval = packet_read_list(ptempBuf, &data_length)) < 0)
+ goto read_rbu_data_exit;
+
+ if ((pos + count) > imagesize) {
+ rbu_data.packet_read_count = 0;
+ /* this was the last copy */
+ retval = bytes_left;
+ } else
+ retval = count;
+
+ read_rbu_data_exit:
+ return retval;
+}
+
+static ssize_t read_rbu_mono_data(char *buffer, loff_t pos, size_t count)
+{
+ unsigned char *ptemp = NULL;
+ size_t bytes_left = 0;
+ size_t data_length = 0;
+ ssize_t ret_count = 0;
+
+ /* check to see if we have something to return */
+ if ((rbu_data.image_update_buffer == NULL) ||
+ (rbu_data.bios_image_size == 0)) {
+ pr_debug("read_rbu_data_mono: image_update_buffer %p ,"
+ "bios_image_size %lu\n",
+ rbu_data.image_update_buffer,
+ rbu_data.bios_image_size);
+ ret_count = -ENOMEM;
+ goto read_rbu_data_exit;
+ }
+
+ if (pos > rbu_data.bios_image_size) {
+ ret_count = 0;
+ goto read_rbu_data_exit;
+ }
+
+ bytes_left = rbu_data.bios_image_size - pos;
+ data_length = min(bytes_left, count);
+
+ ptemp = rbu_data.image_update_buffer;
+ memcpy(buffer, (ptemp + pos), data_length);
+
+ if ((pos + count) > rbu_data.bios_image_size)
+ /* this was the last copy */
+ ret_count = bytes_left;
+ else
+ ret_count = count;
+ read_rbu_data_exit:
+ return ret_count;
+}
+
+static ssize_t
+read_rbu_data(struct kobject *kobj, char *buffer, loff_t pos, size_t count)
+{
+ ssize_t ret_count = 0;
+
+ spin_lock(&rbu_data.lock);
+
+ if (!strcmp(image_type, "mono"))
+ ret_count = read_rbu_mono_data(buffer, pos, count);
+ else if (!strcmp(image_type, "packet"))
+ ret_count = read_packet_data(buffer, pos, count);
+ else
+ pr_debug("read_rbu_data: invalid image type specified\n");
+
+ spin_unlock(&rbu_data.lock);
+ return ret_count;
+}
+
+static ssize_t
+read_rbu_image_type(struct kobject *kobj, char *buffer, loff_t pos,
+ size_t count)
+{
+ int size = 0;
+ if (!pos)
+ size = sprintf(buffer, "%s\n", image_type);
+ return size;
+}
+
+static ssize_t
+write_rbu_image_type(struct kobject *kobj, char *buffer, loff_t pos,
+ size_t count)
+{
+ int rc = count;
+ spin_lock(&rbu_data.lock);
+
+ if (strlen(buffer) < MAX_IMAGE_LENGTH)
+ sscanf(buffer, "%s", image_type);
+ else
+ printk(KERN_WARNING "dell_rbu: image_type is invalid"
+ "max chars = %d, \n incoming str--%s-- \n",
+ MAX_IMAGE_LENGTH, buffer);
+
+ /* we must free all previous allocations */
+ packet_empty_list();
+ img_update_free();
+
+ spin_unlock(&rbu_data.lock);
+ return rc;
+
+}
+
+static struct bin_attribute rbu_data_attr = {
+ .attr = {.name = "data",.owner = THIS_MODULE,.mode = 0444},
+ .read = read_rbu_data,
+};
+
+static struct bin_attribute rbu_image_type_attr = {
+ .attr = {.name = "image_type",.owner = THIS_MODULE,.mode = 0644},
+ .read = read_rbu_image_type,
+ .write = write_rbu_image_type,
+};
+
+static void callbackfn_rbu(const struct firmware *fw, void *context)
+{
+ int rc = 0;
+
+ if (!fw || !fw->size)
+ return;
+
+ spin_lock(&rbu_data.lock);
+ if (!strcmp(image_type, "mono")) {
+ if (!img_update_realloc(fw->size))
+ memcpy(rbu_data.image_update_buffer,
+ fw->data, fw->size);
+ } else if (!strcmp(image_type, "packet")) {
+ if (!rbu_data.packetsize)
+ rbu_data.packetsize = fw->size;
+ else if (rbu_data.packetsize != fw->size) {
+ packet_empty_list();
+ rbu_data.packetsize = fw->size;
+ }
+ packetize_data(fw->data, fw->size);
+ } else
+ pr_debug("invalid image type specified.\n");
+ spin_unlock(&rbu_data.lock);
+
+ rc = request_firmware_nowait(THIS_MODULE, FW_ACTION_NOHOTPLUG,
+ "dell_rbu", &rbu_device->dev,
+ &context, callbackfn_rbu);
+ if (rc)
+ printk(KERN_ERR
+ "dell_rbu:%s request_firmware_nowait failed"
+ " %d\n", __FUNCTION__, rc);
+}
+
+static int __init dcdrbu_init(void)
+{
+ int rc = 0;
+ spin_lock_init(&rbu_data.lock);
+
+ init_packet_head();
+ rbu_device =
+ platform_device_register_simple("dell_rbu", -1, NULL, 0);
+ if (!rbu_device) {
+ printk(KERN_ERR
+ "dell_rbu:%s:platform_device_register_simple "
+ "failed\n", __FUNCTION__);
+ return -EIO;
+ }
+
+ sysfs_create_bin_file(&rbu_device->dev.kobj, &rbu_data_attr);
+ sysfs_create_bin_file(&rbu_device->dev.kobj, &rbu_image_type_attr);
+
+ rc = request_firmware_nowait(THIS_MODULE, FW_ACTION_NOHOTPLUG,
+ "dell_rbu", &rbu_device->dev,
+ &context, callbackfn_rbu);
+ if (rc)
+ printk(KERN_ERR "dell_rbu:%s:request_firmware_nowait"
+ " failed %d\n", __FUNCTION__, rc);
+
+ return rc;
+
+}
+
+static __exit void dcdrbu_exit(void)
+{
+ spin_lock(&rbu_data.lock);
+ packet_empty_list();
+ img_update_free();
+ spin_unlock(&rbu_data.lock);
+ platform_device_unregister(rbu_device);
+}
+
+module_exit(dcdrbu_exit);
+module_init(dcdrbu_init);
diff --git a/drivers/i2c/chips/isp1301_omap.c b/drivers/i2c/chips/isp1301_omap.c
index 354a26295672..8ee56d4b3891 100644
--- a/drivers/i2c/chips/isp1301_omap.c
+++ b/drivers/i2c/chips/isp1301_omap.c
@@ -1489,7 +1489,7 @@ static int isp1301_probe(struct i2c_adapter *bus, int address, int kind)
if (the_transceiver)
return 0;
- isp = kcalloc(1, sizeof *isp, GFP_KERNEL);
+ isp = kzalloc(sizeof *isp, GFP_KERNEL);
if (!isp)
return 0;
diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c
index bebcc47ab06c..b23322523ef5 100644
--- a/drivers/ieee1394/nodemgr.c
+++ b/drivers/ieee1394/nodemgr.c
@@ -1068,6 +1068,8 @@ static int nodemgr_hotplug(struct class_device *cdev, char **envp, int num_envp,
struct unit_directory *ud;
int i = 0;
int length = 0;
+ /* ieee1394:venNmoNspNverN */
+ char buf[8 + 1 + 3 + 8 + 2 + 8 + 2 + 8 + 3 + 8 + 1];
if (!cdev)
return -ENODEV;
@@ -1094,6 +1096,12 @@ do { \
PUT_ENVP("GUID=%016Lx", (unsigned long long)ud->ne->guid);
PUT_ENVP("SPECIFIER_ID=%06x", ud->specifier_id);
PUT_ENVP("VERSION=%06x", ud->version);
+ snprintf(buf, sizeof(buf), "ieee1394:ven%08Xmo%08Xsp%08Xver%08X",
+ ud->vendor_id,
+ ud->model_id,
+ ud->specifier_id,
+ ud->version);
+ PUT_ENVP("MODALIAS=%s", buf);
#undef PUT_ENVP
diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c
index fae1c2dcee51..211ba3223f65 100644
--- a/drivers/infiniband/core/sysfs.c
+++ b/drivers/infiniband/core/sysfs.c
@@ -463,7 +463,7 @@ alloc_group_attrs(ssize_t (*show)(struct ib_port *,
return NULL;
for (i = 0; i < len; i++) {
- element = kcalloc(1, sizeof(struct port_table_attribute),
+ element = kzalloc(sizeof(struct port_table_attribute),
GFP_KERNEL);
if (!element)
goto err;
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index f8b278d3559b..19c14c4beb44 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -393,6 +393,7 @@ static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case EV_LED: bits = dev->ledbit; len = LED_MAX; break;
case EV_SND: bits = dev->sndbit; len = SND_MAX; break;
case EV_FF: bits = dev->ffbit; len = FF_MAX; break;
+ case EV_SW: bits = dev->swbit; len = SW_MAX; break;
default: return -EINVAL;
}
len = NBITS(len) * sizeof(long);
@@ -421,6 +422,13 @@ static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
return copy_to_user(p, dev->snd, len) ? -EFAULT : len;
}
+ if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSW(0))) {
+ int len;
+ len = NBITS(SW_MAX) * sizeof(long);
+ if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
+ return copy_to_user(p, dev->sw, len) ? -EFAULT : len;
+ }
+
if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) {
int len;
if (!dev->name) return -ENOENT;
diff --git a/drivers/input/gameport/emu10k1-gp.c b/drivers/input/gameport/emu10k1-gp.c
index a0118038330a..462f8d300aae 100644
--- a/drivers/input/gameport/emu10k1-gp.c
+++ b/drivers/input/gameport/emu10k1-gp.c
@@ -75,7 +75,7 @@ static int __devinit emu_probe(struct pci_dev *pdev, const struct pci_device_id
if (!request_region(ioport, iolen, "emu10k1-gp"))
return -EBUSY;
- emu = kcalloc(1, sizeof(struct emu), GFP_KERNEL);
+ emu = kzalloc(sizeof(struct emu), GFP_KERNEL);
port = gameport_allocate_port();
if (!emu || !port) {
printk(KERN_ERR "emu10k1-gp: Memory allocation failed\n");
diff --git a/drivers/input/gameport/fm801-gp.c b/drivers/input/gameport/fm801-gp.c
index 57615bc63906..47e93daa0fa7 100644
--- a/drivers/input/gameport/fm801-gp.c
+++ b/drivers/input/gameport/fm801-gp.c
@@ -83,7 +83,7 @@ static int __devinit fm801_gp_probe(struct pci_dev *pci, const struct pci_device
struct fm801_gp *gp;
struct gameport *port;
- gp = kcalloc(1, sizeof(struct fm801_gp), GFP_KERNEL);
+ gp = kzalloc(sizeof(struct fm801_gp), GFP_KERNEL);
port = gameport_allocate_port();
if (!gp || !port) {
printk(KERN_ERR "fm801-gp: Memory allocation failed\n");
diff --git a/drivers/input/gameport/ns558.c b/drivers/input/gameport/ns558.c
index 70f051894a3c..d2e55dc956ba 100644
--- a/drivers/input/gameport/ns558.c
+++ b/drivers/input/gameport/ns558.c
@@ -142,7 +142,7 @@ static int ns558_isa_probe(int io)
return -EBUSY;
}
- ns558 = kcalloc(1, sizeof(struct ns558), GFP_KERNEL);
+ ns558 = kzalloc(sizeof(struct ns558), GFP_KERNEL);
port = gameport_allocate_port();
if (!ns558 || !port) {
printk(KERN_ERR "ns558: Memory allocation failed.\n");
@@ -215,7 +215,7 @@ static int ns558_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *did)
if (!request_region(ioport, iolen, "ns558-pnp"))
return -EBUSY;
- ns558 = kcalloc(1, sizeof(struct ns558), GFP_KERNEL);
+ ns558 = kzalloc(sizeof(struct ns558), GFP_KERNEL);
port = gameport_allocate_port();
if (!ns558 || !port) {
printk(KERN_ERR "ns558: Memory allocation failed\n");
diff --git a/drivers/input/input.c b/drivers/input/input.c
index a275211c8e1e..88636a204525 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -89,6 +89,15 @@ void input_event(struct input_dev *dev, unsigned int type, unsigned int code, in
break;
+ case EV_SW:
+
+ if (code > SW_MAX || !test_bit(code, dev->swbit) || !!test_bit(code, dev->sw) == value)
+ return;
+
+ change_bit(code, dev->sw);
+
+ break;
+
case EV_ABS:
if (code > ABS_MAX || !test_bit(code, dev->absbit))
@@ -402,6 +411,7 @@ static void input_call_hotplug(char *verb, struct input_dev *dev)
SPRINTF_BIT_A2(ledbit, "LED=", LED_MAX, EV_LED);
SPRINTF_BIT_A2(sndbit, "SND=", SND_MAX, EV_SND);
SPRINTF_BIT_A2(ffbit, "FF=", FF_MAX, EV_FF);
+ SPRINTF_BIT_A2(swbit, "SW=", SW_MAX, EV_SW);
envp[i++] = NULL;
@@ -490,6 +500,7 @@ static int input_devices_read(char *buf, char **start, off_t pos, int count, int
SPRINTF_BIT_B2(ledbit, "LED=", LED_MAX, EV_LED);
SPRINTF_BIT_B2(sndbit, "SND=", SND_MAX, EV_SND);
SPRINTF_BIT_B2(ffbit, "FF=", FF_MAX, EV_FF);
+ SPRINTF_BIT_B2(swbit, "SW=", SW_MAX, EV_SW);
len += sprintf(buf + len, "\n");
diff --git a/drivers/input/joystick/a3d.c b/drivers/input/joystick/a3d.c
index bf34f75b9467..bf65430181fa 100644
--- a/drivers/input/joystick/a3d.c
+++ b/drivers/input/joystick/a3d.c
@@ -269,7 +269,7 @@ static int a3d_connect(struct gameport *gameport, struct gameport_driver *drv)
int i;
int err;
- if (!(a3d = kcalloc(1, sizeof(struct a3d), GFP_KERNEL)))
+ if (!(a3d = kzalloc(sizeof(struct a3d), GFP_KERNEL)))
return -ENOMEM;
a3d->gameport = gameport;
diff --git a/drivers/input/joystick/adi.c b/drivers/input/joystick/adi.c
index 265962956c63..cf35ae638a0d 100644
--- a/drivers/input/joystick/adi.c
+++ b/drivers/input/joystick/adi.c
@@ -469,7 +469,7 @@ static int adi_connect(struct gameport *gameport, struct gameport_driver *drv)
int i;
int err;
- if (!(port = kcalloc(1, sizeof(struct adi_port), GFP_KERNEL)))
+ if (!(port = kzalloc(sizeof(struct adi_port), GFP_KERNEL)))
return -ENOMEM;
port->gameport = gameport;
diff --git a/drivers/input/joystick/analog.c b/drivers/input/joystick/analog.c
index c3a5739030c3..64b1313a3c66 100644
--- a/drivers/input/joystick/analog.c
+++ b/drivers/input/joystick/analog.c
@@ -655,7 +655,7 @@ static int analog_connect(struct gameport *gameport, struct gameport_driver *drv
int i;
int err;
- if (!(port = kcalloc(1, sizeof(struct analog_port), GFP_KERNEL)))
+ if (!(port = kzalloc(sizeof(struct analog_port), GFP_KERNEL)))
return - ENOMEM;
err = analog_init_port(gameport, drv, port);
diff --git a/drivers/input/joystick/cobra.c b/drivers/input/joystick/cobra.c
index a6002205328f..0b2e9fa26579 100644
--- a/drivers/input/joystick/cobra.c
+++ b/drivers/input/joystick/cobra.c
@@ -163,7 +163,7 @@ static int cobra_connect(struct gameport *gameport, struct gameport_driver *drv)
int i, j;
int err;
- if (!(cobra = kcalloc(1, sizeof(struct cobra), GFP_KERNEL)))
+ if (!(cobra = kzalloc(sizeof(struct cobra), GFP_KERNEL)))
return -ENOMEM;
cobra->gameport = gameport;
diff --git a/drivers/input/joystick/db9.c b/drivers/input/joystick/db9.c
index fbd3eed07f90..2a3e4bb2da50 100644
--- a/drivers/input/joystick/db9.c
+++ b/drivers/input/joystick/db9.c
@@ -572,7 +572,7 @@ static struct db9 __init *db9_probe(int *config, int nargs)
}
}
- if (!(db9 = kcalloc(1, sizeof(struct db9), GFP_KERNEL))) {
+ if (!(db9 = kzalloc(sizeof(struct db9), GFP_KERNEL))) {
parport_put_port(pp);
return NULL;
}
diff --git a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c
index 95bbdd302aad..5427bf9fc862 100644
--- a/drivers/input/joystick/gamecon.c
+++ b/drivers/input/joystick/gamecon.c
@@ -554,7 +554,7 @@ static struct gc __init *gc_probe(int *config, int nargs)
return NULL;
}
- if (!(gc = kcalloc(1, sizeof(struct gc), GFP_KERNEL))) {
+ if (!(gc = kzalloc(sizeof(struct gc), GFP_KERNEL))) {
parport_put_port(pp);
return NULL;
}
diff --git a/drivers/input/joystick/gf2k.c b/drivers/input/joystick/gf2k.c
index 7d969420066c..8e4f92b115e6 100644
--- a/drivers/input/joystick/gf2k.c
+++ b/drivers/input/joystick/gf2k.c
@@ -242,7 +242,7 @@ static int gf2k_connect(struct gameport *gameport, struct gameport_driver *drv)
unsigned char data[GF2K_LENGTH];
int i, err;
- if (!(gf2k = kcalloc(1, sizeof(struct gf2k), GFP_KERNEL)))
+ if (!(gf2k = kzalloc(sizeof(struct gf2k), GFP_KERNEL)))
return -ENOMEM;
gf2k->gameport = gameport;
diff --git a/drivers/input/joystick/grip.c b/drivers/input/joystick/grip.c
index d1500d2562d6..9d3f910dd568 100644
--- a/drivers/input/joystick/grip.c
+++ b/drivers/input/joystick/grip.c
@@ -301,7 +301,7 @@ static int grip_connect(struct gameport *gameport, struct gameport_driver *drv)
int i, j, t;
int err;
- if (!(grip = kcalloc(1, sizeof(struct grip), GFP_KERNEL)))
+ if (!(grip = kzalloc(sizeof(struct grip), GFP_KERNEL)))
return -ENOMEM;
grip->gameport = gameport;
diff --git a/drivers/input/joystick/grip_mp.c b/drivers/input/joystick/grip_mp.c
index 0da7bd133ccf..da17eee6f574 100644
--- a/drivers/input/joystick/grip_mp.c
+++ b/drivers/input/joystick/grip_mp.c
@@ -607,7 +607,7 @@ static int grip_connect(struct gameport *gameport, struct gameport_driver *drv)
struct grip_mp *grip;
int err;
- if (!(grip = kcalloc(1, sizeof(struct grip_mp), GFP_KERNEL)))
+ if (!(grip = kzalloc(sizeof(struct grip_mp), GFP_KERNEL)))
return -ENOMEM;
grip->gameport = gameport;
diff --git a/drivers/input/joystick/guillemot.c b/drivers/input/joystick/guillemot.c
index f93da7bc082d..6a70ec429f06 100644
--- a/drivers/input/joystick/guillemot.c
+++ b/drivers/input/joystick/guillemot.c
@@ -183,7 +183,7 @@ static int guillemot_connect(struct gameport *gameport, struct gameport_driver *
int i, t;
int err;
- if (!(guillemot = kcalloc(1, sizeof(struct guillemot), GFP_KERNEL)))
+ if (!(guillemot = kzalloc(sizeof(struct guillemot), GFP_KERNEL)))
return -ENOMEM;
guillemot->gameport = gameport;
diff --git a/drivers/input/joystick/interact.c b/drivers/input/joystick/interact.c
index 9d3f8c38cb09..d7b3472bd686 100644
--- a/drivers/input/joystick/interact.c
+++ b/drivers/input/joystick/interact.c
@@ -212,7 +212,7 @@ static int interact_connect(struct gameport *gameport, struct gameport_driver *d
int i, t;
int err;
- if (!(interact = kcalloc(1, sizeof(struct interact), GFP_KERNEL)))
+ if (!(interact = kzalloc(sizeof(struct interact), GFP_KERNEL)))
return -ENOMEM;
interact->gameport = gameport;
diff --git a/drivers/input/joystick/sidewinder.c b/drivers/input/joystick/sidewinder.c
index 47144a7ed9e7..9e0353721a35 100644
--- a/drivers/input/joystick/sidewinder.c
+++ b/drivers/input/joystick/sidewinder.c
@@ -590,7 +590,7 @@ static int sw_connect(struct gameport *gameport, struct gameport_driver *drv)
comment[0] = 0;
- sw = kcalloc(1, sizeof(struct sw), GFP_KERNEL);
+ sw = kzalloc(sizeof(struct sw), GFP_KERNEL);
buf = kmalloc(SW_LENGTH, GFP_KERNEL);
idbuf = kmalloc(SW_LENGTH, GFP_KERNEL);
if (!sw || !buf || !idbuf) {
diff --git a/drivers/input/joystick/tmdc.c b/drivers/input/joystick/tmdc.c
index 9eb9954cac6e..7431efc4330e 100644
--- a/drivers/input/joystick/tmdc.c
+++ b/drivers/input/joystick/tmdc.c
@@ -262,7 +262,7 @@ static int tmdc_connect(struct gameport *gameport, struct gameport_driver *drv)
int i, j, k, l, m;
int err;
- if (!(tmdc = kcalloc(1, sizeof(struct tmdc), GFP_KERNEL)))
+ if (!(tmdc = kzalloc(sizeof(struct tmdc), GFP_KERNEL)))
return -ENOMEM;
tmdc->gameport = gameport;
diff --git a/drivers/input/joystick/turbografx.c b/drivers/input/joystick/turbografx.c
index 28100d461cb7..0c5b9c8297cd 100644
--- a/drivers/input/joystick/turbografx.c
+++ b/drivers/input/joystick/turbografx.c
@@ -178,7 +178,7 @@ static struct tgfx __init *tgfx_probe(int *config, int nargs)
return NULL;
}
- if (!(tgfx = kcalloc(1, sizeof(struct tgfx), GFP_KERNEL))) {
+ if (!(tgfx = kzalloc(sizeof(struct tgfx), GFP_KERNEL))) {
parport_put_port(pp);
return NULL;
}
diff --git a/drivers/input/keyboard/corgikbd.c b/drivers/input/keyboard/corgikbd.c
index a8551711e8d6..cd4b6e795013 100644
--- a/drivers/input/keyboard/corgikbd.c
+++ b/drivers/input/keyboard/corgikbd.c
@@ -16,6 +16,7 @@
#include <linux/init.h>
#include <linux/input.h>
#include <linux/interrupt.h>
+#include <linux/jiffies.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <asm/irq.h>
@@ -32,7 +33,6 @@
/* zero code, 124 scancodes + 3 hinge combinations */
#define NR_SCANCODES ( SCANCODE(KB_ROWS-1,KB_COLS-1) +1 +1 +3 )
#define SCAN_INTERVAL (HZ/10)
-#define CORGIKBD_PRESSED 1
#define HINGE_SCAN_INTERVAL (HZ/4)
@@ -73,25 +73,13 @@ struct corgikbd {
struct input_dev input;
char phys[32];
- unsigned char state[ARRAY_SIZE(corgikbd_keycode)];
spinlock_t lock;
-
struct timer_list timer;
struct timer_list htimer;
-};
-static void handle_scancode(unsigned int pressed,unsigned int scancode, struct corgikbd *corgikbd_data)
-{
- if (pressed && !(corgikbd_data->state[scancode] & CORGIKBD_PRESSED)) {
- corgikbd_data->state[scancode] |= CORGIKBD_PRESSED;
- input_report_key(&corgikbd_data->input, corgikbd_data->keycode[scancode], 1);
- if (corgikbd_data->keycode[scancode] == CORGI_KEY_OFF)
- input_event(&corgikbd_data->input, EV_PWR, CORGI_KEY_OFF, 1);
- } else if (!pressed && corgikbd_data->state[scancode] & CORGIKBD_PRESSED) {
- corgikbd_data->state[scancode] &= ~CORGIKBD_PRESSED;
- input_report_key(&corgikbd_data->input, corgikbd_data->keycode[scancode], 0);
- }
-}
+ unsigned int suspended;
+ unsigned long suspend_jiffies;
+};
#define KB_DISCHARGE_DELAY 10
#define KB_ACTIVATE_DELAY 10
@@ -105,36 +93,36 @@ static void handle_scancode(unsigned int pressed,unsigned int scancode, struct c
*/
static inline void corgikbd_discharge_all(void)
{
- // STROBE All HiZ
+ /* STROBE All HiZ */
GPCR2 = CORGI_GPIO_ALL_STROBE_BIT;
GPDR2 &= ~CORGI_GPIO_ALL_STROBE_BIT;
}
static inline void corgikbd_activate_all(void)
{
- // STROBE ALL -> High
+ /* STROBE ALL -> High */
GPSR2 = CORGI_GPIO_ALL_STROBE_BIT;
GPDR2 |= CORGI_GPIO_ALL_STROBE_BIT;
udelay(KB_DISCHARGE_DELAY);
- // Clear any interrupts we may have triggered when altering the GPIO lines
+ /* Clear any interrupts we may have triggered when altering the GPIO lines */
GEDR1 = CORGI_GPIO_HIGH_SENSE_BIT;
GEDR2 = CORGI_GPIO_LOW_SENSE_BIT;
}
static inline void corgikbd_activate_col(int col)
{
- // STROBE col -> High, not col -> HiZ
+ /* STROBE col -> High, not col -> HiZ */
GPSR2 = CORGI_GPIO_STROBE_BIT(col);
GPDR2 = (GPDR2 & ~CORGI_GPIO_ALL_STROBE_BIT) | CORGI_GPIO_STROBE_BIT(col);
}
static inline void corgikbd_reset_col(int col)
{
- // STROBE col -> Low
+ /* STROBE col -> Low */
GPCR2 = CORGI_GPIO_STROBE_BIT(col);
- // STROBE col -> out, not col -> HiZ
+ /* STROBE col -> out, not col -> HiZ */
GPDR2 = (GPDR2 & ~CORGI_GPIO_ALL_STROBE_BIT) | CORGI_GPIO_STROBE_BIT(col);
}
@@ -149,10 +137,13 @@ static inline void corgikbd_reset_col(int col)
/* Scan the hardware keyboard and push any changes up through the input layer */
static void corgikbd_scankeyboard(struct corgikbd *corgikbd_data, struct pt_regs *regs)
{
- unsigned int row, col, rowd, scancode;
+ unsigned int row, col, rowd;
unsigned long flags;
unsigned int num_pressed;
+ if (corgikbd_data->suspended)
+ return;
+
spin_lock_irqsave(&corgikbd_data->lock, flags);
if (regs)
@@ -173,10 +164,21 @@ static void corgikbd_scankeyboard(struct corgikbd *corgikbd_data, struct pt_regs
rowd = GET_ROWS_STATUS(col);
for (row = 0; row < KB_ROWS; row++) {
+ unsigned int scancode, pressed;
+
scancode = SCANCODE(row, col);
- handle_scancode((rowd & KB_ROWMASK(row)), scancode, corgikbd_data);
- if (rowd & KB_ROWMASK(row))
+ pressed = rowd & KB_ROWMASK(row);
+
+ input_report_key(&corgikbd_data->input, corgikbd_data->keycode[scancode], pressed);
+
+ if (pressed)
num_pressed++;
+
+ if (pressed && (corgikbd_data->keycode[scancode] == CORGI_KEY_OFF)
+ && time_after(jiffies, corgikbd_data->suspend_jiffies + HZ)) {
+ input_event(&corgikbd_data->input, EV_PWR, CORGI_KEY_OFF, 1);
+ corgikbd_data->suspend_jiffies=jiffies;
+ }
}
corgikbd_reset_col(col);
}
@@ -221,8 +223,11 @@ static void corgikbd_timer_callback(unsigned long data)
* The hinge switches generate no interrupt so they need to be
* monitored by a timer.
*
- * When we detect changes, we debounce it and then pass the three
- * positions the system can take as keypresses to the input system.
+ * We debounce the switches and pass them to the input system.
+ *
+ * gprr == 0x00 - Keyboard with Landscape Screen
+ * 0x08 - No Keyboard with Portrait Screen
+ * 0x0c - Keyboard and Screen Closed
*/
#define HINGE_STABLE_COUNT 2
@@ -235,7 +240,7 @@ static void corgikbd_hinge_timer(unsigned long data)
unsigned long gprr;
unsigned long flags;
- gprr = read_scoop_reg(SCOOP_GPRR) & (CORGI_SCP_SWA | CORGI_SCP_SWB);
+ gprr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_GPRR) & (CORGI_SCP_SWA | CORGI_SCP_SWB);
if (gprr != sharpsl_hinge_state) {
hinge_count = 0;
sharpsl_hinge_state = gprr;
@@ -244,9 +249,8 @@ static void corgikbd_hinge_timer(unsigned long data)
if (hinge_count >= HINGE_STABLE_COUNT) {
spin_lock_irqsave(&corgikbd_data->lock, flags);
- handle_scancode((sharpsl_hinge_state == 0x00), 125, corgikbd_data); /* Keyboard with Landscape Screen */
- handle_scancode((sharpsl_hinge_state == 0x08), 126, corgikbd_data); /* No Keyboard with Portrait Screen */
- handle_scancode((sharpsl_hinge_state == 0x0c), 127, corgikbd_data); /* Keyboard and Screen Closed */
+ input_report_switch(&corgikbd_data->input, SW_0, ((sharpsl_hinge_state & CORGI_SCP_SWA) != 0));
+ input_report_switch(&corgikbd_data->input, SW_1, ((sharpsl_hinge_state & CORGI_SCP_SWB) != 0));
input_sync(&corgikbd_data->input);
spin_unlock_irqrestore(&corgikbd_data->lock, flags);
@@ -255,19 +259,45 @@ static void corgikbd_hinge_timer(unsigned long data)
mod_timer(&corgikbd_data->htimer, jiffies + HINGE_SCAN_INTERVAL);
}
+#ifdef CONFIG_PM
+static int corgikbd_suspend(struct device *dev, pm_message_t state, uint32_t level)
+{
+ if (level == SUSPEND_POWER_DOWN) {
+ struct corgikbd *corgikbd = dev_get_drvdata(dev);
+ corgikbd->suspended = 1;
+ }
+ return 0;
+}
+
+static int corgikbd_resume(struct device *dev, uint32_t level)
+{
+ if (level == RESUME_POWER_ON) {
+ struct corgikbd *corgikbd = dev_get_drvdata(dev);
+
+ /* Upon resume, ignore the suspend key for a short while */
+ corgikbd->suspend_jiffies=jiffies;
+ corgikbd->suspended = 0;
+ }
+ return 0;
+}
+#else
+#define corgikbd_suspend NULL
+#define corgikbd_resume NULL
+#endif
+
static int __init corgikbd_probe(struct device *dev)
{
int i;
struct corgikbd *corgikbd;
- corgikbd = kcalloc(1, sizeof(struct corgikbd), GFP_KERNEL);
+ corgikbd = kzalloc(sizeof(struct corgikbd), GFP_KERNEL);
if (!corgikbd)
return -ENOMEM;
dev_set_drvdata(dev,corgikbd);
strcpy(corgikbd->phys, "corgikbd/input0");
- spin_lock_init(corgikbd->lock);
+ spin_lock_init(&corgikbd->lock);
/* Init Keyboard rescan timer */
init_timer(&corgikbd->timer);
@@ -279,6 +309,8 @@ static int __init corgikbd_probe(struct device *dev)
corgikbd->htimer.function = corgikbd_hinge_timer;
corgikbd->htimer.data = (unsigned long) corgikbd;
+ corgikbd->suspend_jiffies=jiffies;
+
init_input_dev(&corgikbd->input);
corgikbd->input.private = corgikbd;
corgikbd->input.name = "Corgi Keyboard";
@@ -288,7 +320,7 @@ static int __init corgikbd_probe(struct device *dev)
corgikbd->input.id.vendor = 0x0001;
corgikbd->input.id.product = 0x0001;
corgikbd->input.id.version = 0x0100;
- corgikbd->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_PWR);
+ corgikbd->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_PWR) | BIT(EV_SW);
corgikbd->input.keycode = corgikbd->keycode;
corgikbd->input.keycodesize = sizeof(unsigned char);
corgikbd->input.keycodemax = ARRAY_SIZE(corgikbd_keycode);
@@ -297,6 +329,8 @@ static int __init corgikbd_probe(struct device *dev)
for (i = 0; i < ARRAY_SIZE(corgikbd_keycode); i++)
set_bit(corgikbd->keycode[i], corgikbd->input.keybit);
clear_bit(0, corgikbd->input.keybit);
+ set_bit(SW_0, corgikbd->input.swbit);
+ set_bit(SW_1, corgikbd->input.swbit);
input_register_device(&corgikbd->input);
mod_timer(&corgikbd->htimer, jiffies + HINGE_SCAN_INTERVAL);
@@ -343,6 +377,8 @@ static struct device_driver corgikbd_driver = {
.bus = &platform_bus_type,
.probe = corgikbd_probe,
.remove = corgikbd_remove,
+ .suspend = corgikbd_suspend,
+ .resume = corgikbd_resume,
};
static int __devinit corgikbd_init(void)
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index 2bb2fe78bdca..12bdd3eff923 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -883,7 +883,7 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
psmouse_deactivate(parent);
}
- if (!(psmouse = kcalloc(1, sizeof(struct psmouse), GFP_KERNEL))) {
+ if (!(psmouse = kzalloc(sizeof(struct psmouse), GFP_KERNEL))) {
retval = -ENOMEM;
goto out;
}
diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c
index 79ca38469159..1bd88fca0542 100644
--- a/drivers/input/serio/serport.c
+++ b/drivers/input/serio/serport.c
@@ -87,7 +87,7 @@ static int serport_ldisc_open(struct tty_struct *tty)
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- serport = kcalloc(1, sizeof(struct serport), GFP_KERNEL);
+ serport = kzalloc(sizeof(struct serport), GFP_KERNEL);
if (!serport)
return -ENOMEM;
@@ -165,7 +165,7 @@ static ssize_t serport_ldisc_read(struct tty_struct * tty, struct file * file, u
if (test_and_set_bit(SERPORT_BUSY, &serport->flags))
return -EBUSY;
- serport->serio = serio = kcalloc(1, sizeof(struct serio), GFP_KERNEL);
+ serport->serio = serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
if (!serio)
return -ENOMEM;
diff --git a/drivers/input/touchscreen/corgi_ts.c b/drivers/input/touchscreen/corgi_ts.c
index 3f8b61cfbc37..5d19261b884f 100644
--- a/drivers/input/touchscreen/corgi_ts.c
+++ b/drivers/input/touchscreen/corgi_ts.c
@@ -53,11 +53,8 @@ struct corgi_ts {
#define SyncHS() while((STATUS_HSYNC) == 0); while((STATUS_HSYNC) != 0);
#define CCNT(a) asm volatile ("mrc p14, 0, %0, C1, C0, 0" : "=r"(a))
-#define CCNT_ON() {int pmnc = 1; asm volatile ("mcr p14, 0, %0, C0, C0, 0" : : "r"(pmnc));}
-#define CCNT_OFF() {int pmnc = 0; asm volatile ("mcr p14, 0, %0, C0, C0, 0" : : "r"(pmnc));}
-
-#define WAIT_HS_400_VGA 7013U // 17.615us
-#define WAIT_HS_400_QVGA 16622U // 41.750us
+#define PMNC_GET(x) asm volatile ("mrc p14, 0, %0, C0, C0, 0" : "=r"(x))
+#define PMNC_SET(x) asm volatile ("mcr p14, 0, %0, C0, C0, 0" : : "r"(x))
/* ADS7846 Touch Screen Controller bit definitions */
@@ -69,41 +66,29 @@ struct corgi_ts {
#define ADSCTRL_STS (1u << 7) /* Start Bit */
/* External Functions */
-extern int w100fb_get_xres(void);
-extern int w100fb_get_blanking(void);
-extern int w100fb_get_fastsysclk(void);
+extern unsigned long w100fb_get_hsynclen(struct device *dev);
extern unsigned int get_clk_frequency_khz(int info);
static unsigned long calc_waittime(void)
{
- int w100fb_xres = w100fb_get_xres();
- unsigned int waittime = 0;
-
- if (w100fb_xres == 480 || w100fb_xres == 640) {
- waittime = WAIT_HS_400_VGA * get_clk_frequency_khz(0) / 398131U;
-
- if (w100fb_get_fastsysclk() == 100)
- waittime = waittime * 75 / 100;
-
- if (w100fb_xres == 640)
- waittime *= 3;
+ unsigned long hsync_len = w100fb_get_hsynclen(&corgifb_device.dev);
- return waittime;
- }
-
- return WAIT_HS_400_QVGA * get_clk_frequency_khz(0) / 398131U;
+ if (hsync_len)
+ return get_clk_frequency_khz(0)*1000/hsync_len;
+ else
+ return 0;
}
static int sync_receive_data_send_cmd(int doRecive, int doSend, unsigned int address, unsigned long wait_time)
{
+ unsigned long timer1 = 0, timer2, pmnc = 0;
int pos = 0;
- unsigned long timer1 = 0, timer2;
- int dosleep;
- dosleep = !w100fb_get_blanking();
+ if (wait_time && doSend) {
+ PMNC_GET(pmnc);
+ if (!(pmnc & 0x01))
+ PMNC_SET(0x01);
- if (dosleep && doSend) {
- CCNT_ON();
/* polling HSync */
SyncHS();
/* get CCNT */
@@ -119,11 +104,11 @@ static int sync_receive_data_send_cmd(int doRecive, int doSend, unsigned int add
corgi_ssp_ads7846_put(cmd);
corgi_ssp_ads7846_get();
- if (dosleep) {
+ if (wait_time) {
/* Wait after HSync */
CCNT(timer2);
if (timer2-timer1 > wait_time) {
- /* timeout */
+ /* too slow - timeout, try again */
SyncHS();
/* get OSCR */
CCNT(timer1);
@@ -134,8 +119,8 @@ static int sync_receive_data_send_cmd(int doRecive, int doSend, unsigned int add
CCNT(timer2);
}
corgi_ssp_ads7846_put(cmd);
- if (dosleep)
- CCNT_OFF();
+ if (wait_time && !(pmnc & 0x01))
+ PMNC_SET(pmnc);
}
return pos;
}
@@ -244,7 +229,7 @@ static irqreturn_t ts_interrupt(int irq, void *dev_id, struct pt_regs *regs)
}
#ifdef CONFIG_PM
-static int corgits_suspend(struct device *dev, uint32_t state, uint32_t level)
+static int corgits_suspend(struct device *dev, pm_message_t state, uint32_t level)
{
if (level == SUSPEND_POWER_DOWN) {
struct corgi_ts *corgi_ts = dev_get_drvdata(dev);
diff --git a/drivers/isdn/hisax/hisax.h b/drivers/isdn/hisax/hisax.h
index 17cf7663c582..6eb96cba4d29 100644
--- a/drivers/isdn/hisax/hisax.h
+++ b/drivers/isdn/hisax/hisax.h
@@ -10,7 +10,6 @@
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/major.h>
-#include <asm/segment.h>
#include <asm/io.h>
#include <linux/delay.h>
#include <linux/kernel.h>
diff --git a/drivers/isdn/i4l/isdn_v110.c b/drivers/isdn/i4l/isdn_v110.c
index f47f2b9846d8..38619e8cd823 100644
--- a/drivers/isdn/i4l/isdn_v110.c
+++ b/drivers/isdn/i4l/isdn_v110.c
@@ -516,11 +516,11 @@ buffer_full:
}
int
-isdn_v110_stat_callback(int idx, isdn_ctrl * c)
+isdn_v110_stat_callback(int idx, isdn_ctrl *c)
{
isdn_v110_stream *v = NULL;
int i;
- int ret;
+ int ret = 0;
if (idx < 0)
return 0;
diff --git a/drivers/md/dm-io.c b/drivers/md/dm-io.c
index 45754bb6a799..9de000131a8a 100644
--- a/drivers/md/dm-io.c
+++ b/drivers/md/dm-io.c
@@ -239,6 +239,11 @@ static void vm_dp_init(struct dpages *dp, void *data)
dp->context_ptr = data;
}
+static void dm_bio_destructor(struct bio *bio)
+{
+ bio_free(bio, _bios);
+}
+
/*-----------------------------------------------------------------
* IO routines that accept a list of pages.
*---------------------------------------------------------------*/
@@ -263,6 +268,7 @@ static void do_region(int rw, unsigned int region, struct io_region *where,
bio->bi_bdev = where->bdev;
bio->bi_end_io = endio;
bio->bi_private = io;
+ bio->bi_destructor = dm_bio_destructor;
bio_set_region(bio, region);
/*
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index d487d9deb98e..930b9fc27953 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -399,6 +399,11 @@ struct clone_info {
unsigned short idx;
};
+static void dm_bio_destructor(struct bio *bio)
+{
+ bio_free(bio, dm_set);
+}
+
/*
* Creates a little bio that is just does part of a bvec.
*/
@@ -410,6 +415,7 @@ static struct bio *split_bvec(struct bio *bio, sector_t sector,
struct bio_vec *bv = bio->bi_io_vec + idx;
clone = bio_alloc_bioset(GFP_NOIO, 1, dm_set);
+ clone->bi_destructor = dm_bio_destructor;
*clone->bi_io_vec = *bv;
clone->bi_sector = sector;
diff --git a/drivers/media/dvb/bt8xx/Kconfig b/drivers/media/dvb/bt8xx/Kconfig
index b12545f093f8..1e85d16491b0 100644
--- a/drivers/media/dvb/bt8xx/Kconfig
+++ b/drivers/media/dvb/bt8xx/Kconfig
@@ -1,5 +1,5 @@
config DVB_BT8XX
- tristate "Nebula/Pinnacle PCTV/Twinhan PCI cards"
+ tristate "BT8xx based PCI cards"
depends on DVB_CORE && PCI && VIDEO_BT848
select DVB_MT352
select DVB_SP887X
@@ -8,8 +8,8 @@ config DVB_BT8XX
select DVB_OR51211
help
Support for PCI cards based on the Bt8xx PCI bridge. Examples are
- the Nebula cards, the Pinnacle PCTV cards, the Twinhan DST cards and
- pcHDTV HD2000 cards.
+ the Nebula cards, the Pinnacle PCTV cards, the Twinhan DST cards,
+ the pcHDTV HD2000 cards, and certain AVerMedia cards.
Since these cards have no MPEG decoder onboard, they transmit
only compressed MPEG data over the PCI bus, so you need
diff --git a/drivers/media/dvb/frontends/lgdt330x.c b/drivers/media/dvb/frontends/lgdt330x.c
index 1f1cd7a8d500..7142b9c51dd2 100644
--- a/drivers/media/dvb/frontends/lgdt330x.c
+++ b/drivers/media/dvb/frontends/lgdt330x.c
@@ -69,8 +69,8 @@ struct lgdt330x_state
};
static int i2c_write_demod_bytes (struct lgdt330x_state* state,
- u8 *buf, /* data bytes to send */
- int len /* number of bytes to send */ )
+ u8 *buf, /* data bytes to send */
+ int len /* number of bytes to send */ )
{
struct i2c_msg msg =
{ .addr = state->config->demod_address,
@@ -129,13 +129,13 @@ static int lgdt3302_SwReset(struct lgdt330x_state* state)
};
ret = i2c_write_demod_bytes(state,
- reset, sizeof(reset));
+ reset, sizeof(reset));
if (ret == 0) {
/* force reset high (inactive) and unmask interrupts */
reset[1] = 0x7f;
ret = i2c_write_demod_bytes(state,
- reset, sizeof(reset));
+ reset, sizeof(reset));
}
return ret;
}
@@ -149,13 +149,13 @@ static int lgdt3303_SwReset(struct lgdt330x_state* state)
};
ret = i2c_write_demod_bytes(state,
- reset, sizeof(reset));
+ reset, sizeof(reset));
if (ret == 0) {
/* force reset high (inactive) */
reset[1] = 0x01;
ret = i2c_write_demod_bytes(state,
- reset, sizeof(reset));
+ reset, sizeof(reset));
}
return ret;
}
@@ -172,7 +172,6 @@ static int lgdt330x_SwReset(struct lgdt330x_state* state)
}
}
-
static int lgdt330x_init(struct dvb_frontend* fe)
{
/* Hardware reset is done using gpio[0] of cx23880x chip.
@@ -229,13 +228,13 @@ static int lgdt330x_init(struct dvb_frontend* fe)
case LGDT3302:
chip_name = "LGDT3302";
err = i2c_write_demod_bytes(state, lgdt3302_init_data,
- sizeof(lgdt3302_init_data));
- break;
+ sizeof(lgdt3302_init_data));
+ break;
case LGDT3303:
chip_name = "LGDT3303";
err = i2c_write_demod_bytes(state, lgdt3303_init_data,
- sizeof(lgdt3303_init_data));
- break;
+ sizeof(lgdt3303_init_data));
+ break;
default:
chip_name = "undefined";
printk (KERN_WARNING "Only LGDT3302 and LGDT3303 are supported chips.\n");
@@ -262,15 +261,15 @@ static int lgdt330x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
switch (state->config->demod_chip) {
case LGDT3302:
err = i2c_read_demod_bytes(state, LGDT3302_PACKET_ERR_COUNTER1,
- buf, sizeof(buf));
- break;
+ buf, sizeof(buf));
+ break;
case LGDT3303:
err = i2c_read_demod_bytes(state, LGDT3303_PACKET_ERR_COUNTER1,
- buf, sizeof(buf));
- break;
+ buf, sizeof(buf));
+ break;
default:
printk(KERN_WARNING
- "Only LGDT3302 and LGDT3303 are supported chips.\n");
+ "Only LGDT3302 and LGDT3303 are supported chips.\n");
err = -ENODEV;
}
@@ -330,7 +329,7 @@ static int lgdt330x_set_parameters(struct dvb_frontend* fe,
if (state->config->demod_chip == LGDT3303) {
err = i2c_write_demod_bytes(state, lgdt3303_8vsb_44_data,
- sizeof(lgdt3303_8vsb_44_data));
+ sizeof(lgdt3303_8vsb_44_data));
}
break;
@@ -378,18 +377,19 @@ static int lgdt330x_set_parameters(struct dvb_frontend* fe,
/* Select the requested mode */
i2c_write_demod_bytes(state, top_ctrl_cfg,
- sizeof(top_ctrl_cfg));
- state->config->set_ts_params(fe, 0);
+ sizeof(top_ctrl_cfg));
+ if (state->config->set_ts_params)
+ state->config->set_ts_params(fe, 0);
state->current_modulation = param->u.vsb.modulation;
}
- /* Change only if we are actually changing the channel */
- if (state->current_frequency != param->frequency) {
- /* Tune to the new frequency */
+ /* Tune to the specified frequency */
+ if (state->config->pll_set)
state->config->pll_set(fe, param);
- /* Keep track of the new frequency */
- state->current_frequency = param->frequency;
- }
+
+ /* Keep track of the new frequency */
+ state->current_frequency = param->frequency;
+
lgdt330x_SwReset(state);
return 0;
}
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 810e7aac0a53..3e6f5347da21 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -29,7 +29,7 @@ obj-$(CONFIG_VIDEO_ZORAN_LML33R10) += saa7114.o adv7170.o zr36060.o
obj-$(CONFIG_VIDEO_ZORAN) += zr36067.o videocodec.o
obj-$(CONFIG_VIDEO_PMS) += pms.o
obj-$(CONFIG_VIDEO_PLANB) += planb.o
-obj-$(CONFIG_VIDEO_VINO) += vino.o
+obj-$(CONFIG_VIDEO_VINO) += vino.o saa7191.o indycam.o
obj-$(CONFIG_VIDEO_STRADIS) += stradis.o
obj-$(CONFIG_VIDEO_CPIA) += cpia.o
obj-$(CONFIG_VIDEO_CPIA_PP) += cpia_pp.o
diff --git a/drivers/media/video/adv7170.c b/drivers/media/video/adv7170.c
index 52e32f05d625..1ca2b67aedfb 100644
--- a/drivers/media/video/adv7170.c
+++ b/drivers/media/video/adv7170.c
@@ -43,7 +43,6 @@
#include <asm/pgtable.h>
#include <asm/page.h>
#include <linux/sched.h>
-#include <asm/segment.h>
#include <linux/types.h>
#include <linux/videodev.h>
diff --git a/drivers/media/video/adv7175.c b/drivers/media/video/adv7175.c
index b5ed9544bdea..173bca1e0295 100644
--- a/drivers/media/video/adv7175.c
+++ b/drivers/media/video/adv7175.c
@@ -39,7 +39,6 @@
#include <asm/pgtable.h>
#include <asm/page.h>
#include <linux/sched.h>
-#include <asm/segment.h>
#include <linux/types.h>
#include <linux/videodev.h>
diff --git a/drivers/media/video/bt819.c b/drivers/media/video/bt819.c
index c6cfa7c48b04..3ee0afca76a7 100644
--- a/drivers/media/video/bt819.c
+++ b/drivers/media/video/bt819.c
@@ -43,7 +43,6 @@
#include <asm/pgtable.h>
#include <asm/page.h>
#include <linux/sched.h>
-#include <asm/segment.h>
#include <linux/types.h>
#include <linux/videodev.h>
diff --git a/drivers/media/video/bt856.c b/drivers/media/video/bt856.c
index c13d28658868..8eb871d0e85b 100644
--- a/drivers/media/video/bt856.c
+++ b/drivers/media/video/bt856.c
@@ -43,7 +43,6 @@
#include <asm/pgtable.h>
#include <asm/page.h>
#include <linux/sched.h>
-#include <asm/segment.h>
#include <linux/types.h>
#include <linux/videodev.h>
diff --git a/drivers/media/video/indycam.c b/drivers/media/video/indycam.c
new file mode 100644
index 000000000000..b2b0384cd4b9
--- /dev/null
+++ b/drivers/media/video/indycam.c
@@ -0,0 +1,412 @@
+/*
+ * indycam.c - Silicon Graphics IndyCam digital camera driver
+ *
+ * Copyright (C) 2003 Ladislav Michl <ladis@linux-mips.org>
+ * Copyright (C) 2004,2005 Mikael Nousiainen <tmnousia@cc.hut.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+
+#include <linux/videodev.h>
+/* IndyCam decodes stream of photons into digital image representation ;-) */
+#include <linux/video_decoder.h>
+#include <linux/i2c.h>
+
+#include "indycam.h"
+
+//#define INDYCAM_DEBUG
+
+#define INDYCAM_MODULE_VERSION "0.0.3"
+
+MODULE_DESCRIPTION("SGI IndyCam driver");
+MODULE_VERSION(INDYCAM_MODULE_VERSION);
+MODULE_AUTHOR("Mikael Nousiainen <tmnousia@cc.hut.fi>");
+MODULE_LICENSE("GPL");
+
+#ifdef INDYCAM_DEBUG
+#define dprintk(x...) printk("IndyCam: " x);
+#define indycam_regdump(client) indycam_regdump_debug(client)
+#else
+#define dprintk(x...)
+#define indycam_regdump(client)
+#endif
+
+#define VINO_ADAPTER (I2C_ALGO_SGI | I2C_HW_SGI_VINO)
+
+struct indycam {
+ struct i2c_client *client;
+ int version;
+};
+
+static struct i2c_driver i2c_driver_indycam;
+
+static const unsigned char initseq[] = {
+ INDYCAM_CONTROL_AGCENA, /* INDYCAM_CONTROL */
+ INDYCAM_SHUTTER_DEFAULT, /* INDYCAM_SHUTTER */
+ INDYCAM_GAIN_DEFAULT, /* INDYCAM_GAIN */
+ 0x00, /* INDYCAM_BRIGHTNESS (read-only) */
+ INDYCAM_RED_BALANCE_DEFAULT, /* INDYCAM_RED_BALANCE */
+ INDYCAM_BLUE_BALANCE_DEFAULT, /* INDYCAM_BLUE_BALANCE */
+ INDYCAM_RED_SATURATION_DEFAULT, /* INDYCAM_RED_SATURATION */
+ INDYCAM_BLUE_SATURATION_DEFAULT,/* INDYCAM_BLUE_SATURATION */
+};
+
+/* IndyCam register handling */
+
+static int indycam_read_reg(struct i2c_client *client, unsigned char reg,
+ unsigned char *value)
+{
+ int ret;
+
+ if (reg == INDYCAM_RESET) {
+ dprintk("indycam_read_reg(): "
+ "skipping write-only register %d\n", reg);
+ *value = 0;
+ return 0;
+ }
+
+ ret = i2c_smbus_read_byte_data(client, reg);
+ if (ret < 0) {
+ printk(KERN_ERR "IndyCam: indycam_read_reg(): read failed, "
+ "register = 0x%02x\n", reg);
+ return ret;
+ }
+
+ *value = (unsigned char)ret;
+
+ return 0;
+}
+
+static int indycam_write_reg(struct i2c_client *client, unsigned char reg,
+ unsigned char value)
+{
+ int err;
+
+ if ((reg == INDYCAM_BRIGHTNESS)
+ || (reg == INDYCAM_VERSION)) {
+ dprintk("indycam_write_reg(): "
+ "skipping read-only register %d\n", reg);
+ return 0;
+ }
+
+ dprintk("Writing Reg %d = 0x%02x\n", reg, value);
+ err = i2c_smbus_write_byte_data(client, reg, value);
+ if (err) {
+ printk(KERN_ERR "IndyCam: indycam_write_reg(): write failed, "
+ "register = 0x%02x, value = 0x%02x\n", reg, value);
+ }
+ return err;
+}
+
+static int indycam_write_block(struct i2c_client *client, unsigned char reg,
+ unsigned char length, unsigned char *data)
+{
+ unsigned char i;
+ int err;
+
+ for (i = reg; i < length; i++) {
+ err = indycam_write_reg(client, reg + i, data[i]);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+/* Helper functions */
+
+#ifdef INDYCAM_DEBUG
+static void indycam_regdump_debug(struct i2c_client *client)
+{
+ int i;
+ unsigned char val;
+
+ for (i = 0; i < 9; i++) {
+ indycam_read_reg(client, i, &val);
+ dprintk("Reg %d = 0x%02x\n", i, val);
+ }
+}
+#endif
+
+static int indycam_get_controls(struct i2c_client *client,
+ struct indycam_control *ctrl)
+{
+ unsigned char ctrl_reg;
+
+ indycam_read_reg(client, INDYCAM_CONTROL, &ctrl_reg);
+ ctrl->agc = (ctrl_reg & INDYCAM_CONTROL_AGCENA)
+ ? INDYCAM_VALUE_ENABLED
+ : INDYCAM_VALUE_DISABLED;
+ ctrl->awb = (ctrl_reg & INDYCAM_CONTROL_AWBCTL)
+ ? INDYCAM_VALUE_ENABLED
+ : INDYCAM_VALUE_DISABLED;
+ indycam_read_reg(client, INDYCAM_SHUTTER,
+ (unsigned char *)&ctrl->shutter);
+ indycam_read_reg(client, INDYCAM_GAIN,
+ (unsigned char *)&ctrl->gain);
+ indycam_read_reg(client, INDYCAM_RED_BALANCE,
+ (unsigned char *)&ctrl->red_balance);
+ indycam_read_reg(client, INDYCAM_BLUE_BALANCE,
+ (unsigned char *)&ctrl->blue_balance);
+ indycam_read_reg(client, INDYCAM_RED_SATURATION,
+ (unsigned char *)&ctrl->red_saturation);
+ indycam_read_reg(client, INDYCAM_BLUE_SATURATION,
+ (unsigned char *)&ctrl->blue_saturation);
+ indycam_read_reg(client, INDYCAM_GAMMA,
+ (unsigned char *)&ctrl->gamma);
+
+ return 0;
+}
+
+static int indycam_set_controls(struct i2c_client *client,
+ struct indycam_control *ctrl)
+{
+ unsigned char ctrl_reg;
+
+ indycam_read_reg(client, INDYCAM_CONTROL, &ctrl_reg);
+ if (ctrl->agc != INDYCAM_VALUE_UNCHANGED) {
+ if (ctrl->agc)
+ ctrl_reg |= INDYCAM_CONTROL_AGCENA;
+ else
+ ctrl_reg &= ~INDYCAM_CONTROL_AGCENA;
+ }
+ if (ctrl->awb != INDYCAM_VALUE_UNCHANGED) {
+ if (ctrl->awb)
+ ctrl_reg |= INDYCAM_CONTROL_AWBCTL;
+ else
+ ctrl_reg &= ~INDYCAM_CONTROL_AWBCTL;
+ }
+ indycam_write_reg(client, INDYCAM_CONTROL, ctrl_reg);
+
+ if (ctrl->shutter >= 0)
+ indycam_write_reg(client, INDYCAM_SHUTTER, ctrl->shutter);
+ if (ctrl->gain >= 0)
+ indycam_write_reg(client, INDYCAM_GAIN, ctrl->gain);
+ if (ctrl->red_balance >= 0)
+ indycam_write_reg(client, INDYCAM_RED_BALANCE,
+ ctrl->red_balance);
+ if (ctrl->blue_balance >= 0)
+ indycam_write_reg(client, INDYCAM_BLUE_BALANCE,
+ ctrl->blue_balance);
+ if (ctrl->red_saturation >= 0)
+ indycam_write_reg(client, INDYCAM_RED_SATURATION,
+ ctrl->red_saturation);
+ if (ctrl->blue_saturation >= 0)
+ indycam_write_reg(client, INDYCAM_BLUE_SATURATION,
+ ctrl->blue_saturation);
+ if (ctrl->gamma >= 0)
+ indycam_write_reg(client, INDYCAM_GAMMA, ctrl->gamma);
+
+ return 0;
+}
+
+/* I2C-interface */
+
+static int indycam_attach(struct i2c_adapter *adap, int addr, int kind)
+{
+ int err = 0;
+ struct indycam *camera;
+ struct i2c_client *client;
+
+ printk(KERN_INFO "SGI IndyCam driver version %s\n",
+ INDYCAM_MODULE_VERSION);
+
+ client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+ if (!client)
+ return -ENOMEM;
+ camera = kmalloc(sizeof(struct indycam), GFP_KERNEL);
+ if (!camera) {
+ err = -ENOMEM;
+ goto out_free_client;
+ }
+
+ memset(client, 0, sizeof(struct i2c_client));
+ memset(camera, 0, sizeof(struct indycam));
+
+ client->addr = addr;
+ client->adapter = adap;
+ client->driver = &i2c_driver_indycam;
+ client->flags = 0;
+ strcpy(client->name, "IndyCam client");
+ i2c_set_clientdata(client, camera);
+
+ camera->client = client;
+
+ err = i2c_attach_client(client);
+ if (err)
+ goto out_free_camera;
+
+ camera->version = i2c_smbus_read_byte_data(client, INDYCAM_VERSION);
+ if (camera->version != CAMERA_VERSION_INDY &&
+ camera->version != CAMERA_VERSION_MOOSE) {
+ err = -ENODEV;
+ goto out_detach_client;
+ }
+ printk(KERN_INFO "IndyCam v%d.%d detected\n",
+ INDYCAM_VERSION_MAJOR(camera->version),
+ INDYCAM_VERSION_MINOR(camera->version));
+
+ indycam_regdump(client);
+
+ // initialize
+ err = indycam_write_block(client, 0, sizeof(initseq),
+ (unsigned char *)&initseq);
+ if (err) {
+ printk(KERN_ERR "IndyCam initalization failed\n");
+ err = -EIO;
+ goto out_detach_client;
+ }
+
+ indycam_regdump(client);
+
+ // white balance
+ err = indycam_write_reg(client, INDYCAM_CONTROL,
+ INDYCAM_CONTROL_AGCENA | INDYCAM_CONTROL_AWBCTL);
+ if (err) {
+ printk(KERN_ERR "IndyCam white balance "
+ "initialization failed\n");
+ err = -EIO;
+ goto out_detach_client;
+ }
+
+ indycam_regdump(client);
+
+ printk(KERN_INFO "IndyCam initialized\n");
+
+ return 0;
+
+out_detach_client:
+ i2c_detach_client(client);
+out_free_camera:
+ kfree(camera);
+out_free_client:
+ kfree(client);
+ return err;
+}
+
+static int indycam_probe(struct i2c_adapter *adap)
+{
+ /* Indy specific crap */
+ if (adap->id == VINO_ADAPTER)
+ return indycam_attach(adap, INDYCAM_ADDR, 0);
+ /* Feel free to add probe here :-) */
+ return -ENODEV;
+}
+
+static int indycam_detach(struct i2c_client *client)
+{
+ struct indycam *camera = i2c_get_clientdata(client);
+
+ i2c_detach_client(client);
+ kfree(camera);
+ kfree(client);
+ return 0;
+}
+
+static int indycam_command(struct i2c_client *client, unsigned int cmd,
+ void *arg)
+{
+ // struct indycam *camera = i2c_get_clientdata(client);
+
+ /* The old video_decoder interface just isn't enough,
+ * so we'll use some custom commands. */
+ switch (cmd) {
+ case DECODER_GET_CAPABILITIES: {
+ struct video_decoder_capability *cap = arg;
+
+ cap->flags = VIDEO_DECODER_NTSC;
+ cap->inputs = 1;
+ cap->outputs = 1;
+ break;
+ }
+ case DECODER_GET_STATUS: {
+ int *iarg = arg;
+
+ *iarg = DECODER_STATUS_GOOD | DECODER_STATUS_NTSC |
+ DECODER_STATUS_COLOR;
+ break;
+ }
+ case DECODER_SET_NORM: {
+ int *iarg = arg;
+
+ switch (*iarg) {
+ case VIDEO_MODE_NTSC:
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ }
+ case DECODER_SET_INPUT: {
+ int *iarg = arg;
+
+ if (*iarg != 0)
+ return -EINVAL;
+ break;
+ }
+ case DECODER_SET_OUTPUT: {
+ int *iarg = arg;
+
+ if (*iarg != 0)
+ return -EINVAL;
+ break;
+ }
+ case DECODER_ENABLE_OUTPUT: {
+ /* Always enabled */
+ break;
+ }
+ case DECODER_SET_PICTURE: {
+ // struct video_picture *pic = arg;
+ /* TODO: convert values for indycam_set_controls() */
+ break;
+ }
+ case DECODER_INDYCAM_GET_CONTROLS: {
+ struct indycam_control *ctrl = arg;
+ indycam_get_controls(client, ctrl);
+ }
+ case DECODER_INDYCAM_SET_CONTROLS: {
+ struct indycam_control *ctrl = arg;
+ indycam_set_controls(client, ctrl);
+ }
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static struct i2c_driver i2c_driver_indycam = {
+ .owner = THIS_MODULE,
+ .name = "indycam",
+ .id = I2C_DRIVERID_INDYCAM,
+ .flags = I2C_DF_NOTIFY,
+ .attach_adapter = indycam_probe,
+ .detach_client = indycam_detach,
+ .command = indycam_command,
+};
+
+static int __init indycam_init(void)
+{
+ return i2c_add_driver(&i2c_driver_indycam);
+}
+
+static void __exit indycam_exit(void)
+{
+ i2c_del_driver(&i2c_driver_indycam);
+}
+
+module_init(indycam_init);
+module_exit(indycam_exit);
diff --git a/drivers/media/video/indycam.h b/drivers/media/video/indycam.h
new file mode 100644
index 000000000000..d9ddb6b79a03
--- /dev/null
+++ b/drivers/media/video/indycam.h
@@ -0,0 +1,112 @@
+/*
+ * indycam.h - Silicon Graphics IndyCam digital camera driver
+ *
+ * Copyright (C) 2003 Ladislav Michl <ladis@linux-mips.org>
+ * Copyright (C) 2004,2005 Mikael Nousiainen <tmnousia@cc.hut.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _INDYCAM_H_
+#define _INDYCAM_H_
+
+/* I2C address for the Guinness Camera */
+#define INDYCAM_ADDR 0x56
+
+/* Camera version */
+#define CAMERA_VERSION_INDY 0x10 /* v1.0 */
+#define CAMERA_VERSION_MOOSE 0x12 /* v1.2 */
+#define INDYCAM_VERSION_MAJOR(x) (((x) & 0xf0) >> 4)
+#define INDYCAM_VERSION_MINOR(x) ((x) & 0x0f)
+
+/* Register bus addresses */
+#define INDYCAM_CONTROL 0x00
+#define INDYCAM_SHUTTER 0x01
+#define INDYCAM_GAIN 0x02
+#define INDYCAM_BRIGHTNESS 0x03 /* read-only */
+#define INDYCAM_RED_BALANCE 0x04
+#define INDYCAM_BLUE_BALANCE 0x05
+#define INDYCAM_RED_SATURATION 0x06
+#define INDYCAM_BLUE_SATURATION 0x07
+#define INDYCAM_GAMMA 0x08
+#define INDYCAM_VERSION 0x0e /* read-only */
+#define INDYCAM_RESET 0x0f /* write-only */
+
+#define INDYCAM_LED 0x46
+#define INDYCAM_ORIENTATION 0x47
+#define INDYCAM_BUTTON 0x48
+
+/* Field definitions of registers */
+#define INDYCAM_CONTROL_AGCENA (1<<0) /* automatic gain control */
+#define INDYCAM_CONTROL_AWBCTL (1<<1) /* automatic white balance */
+ /* 2-3 are reserved */
+#define INDYCAM_CONTROL_EVNFLD (1<<4) /* read-only */
+
+#define INDYCAM_SHUTTER_10000 0x02 /* 1/10000 second */
+#define INDYCAM_SHUTTER_4000 0x04 /* 1/4000 second */
+#define INDYCAM_SHUTTER_2000 0x08 /* 1/2000 second */
+#define INDYCAM_SHUTTER_1000 0x10 /* 1/1000 second */
+#define INDYCAM_SHUTTER_500 0x20 /* 1/500 second */
+#define INDYCAM_SHUTTER_250 0x3f /* 1/250 second */
+#define INDYCAM_SHUTTER_125 0x7e /* 1/125 second */
+#define INDYCAM_SHUTTER_100 0x9e /* 1/100 second */
+#define INDYCAM_SHUTTER_60 0x00 /* 1/60 second */
+
+#define INDYCAM_LED_ACTIVE 0x10
+#define INDYCAM_LED_INACTIVE 0x30
+#define INDYCAM_ORIENTATION_BOTTOM_TO_TOP 0x40
+#define INDYCAM_BUTTON_RELEASED 0x10
+
+#define INDYCAM_SHUTTER_MIN 0x00
+#define INDYCAM_SHUTTER_MAX 0xff
+#define INDYCAM_GAIN_MIN 0x00
+#define INDYCAM_GAIN_MAX 0xff
+#define INDYCAM_RED_BALANCE_MIN 0x00 /* the effect is the opposite? */
+#define INDYCAM_RED_BALANCE_MAX 0xff
+#define INDYCAM_BLUE_BALANCE_MIN 0x00 /* the effect is the opposite? */
+#define INDYCAM_BLUE_BALANCE_MAX 0xff
+#define INDYCAM_RED_SATURATION_MIN 0x00
+#define INDYCAM_RED_SATURATION_MAX 0xff
+#define INDYCAM_BLUE_SATURATION_MIN 0x00
+#define INDYCAM_BLUE_SATURATION_MAX 0xff
+#define INDYCAM_GAMMA_MIN 0x00
+#define INDYCAM_GAMMA_MAX 0xff
+
+/* Driver interface definitions */
+
+#define INDYCAM_VALUE_ENABLED 1
+#define INDYCAM_VALUE_DISABLED 0
+#define INDYCAM_VALUE_UNCHANGED -1
+
+/* When setting controls, a value of -1 leaves the control unchanged. */
+struct indycam_control {
+ int agc; /* boolean */
+ int awb; /* boolean */
+ int shutter;
+ int gain;
+ int red_balance;
+ int blue_balance;
+ int red_saturation;
+ int blue_saturation;
+ int gamma;
+};
+
+#define DECODER_INDYCAM_GET_CONTROLS _IOR('d', 193, struct indycam_control)
+#define DECODER_INDYCAM_SET_CONTROLS _IOW('d', 194, struct indycam_control)
+
+/* Default values for controls */
+
+#define INDYCAM_AGC_DEFAULT INDYCAM_VALUE_ENABLED
+#define INDYCAM_AWB_DEFAULT INDYCAM_VALUE_ENABLED
+
+#define INDYCAM_SHUTTER_DEFAULT INDYCAM_SHUTTER_60
+#define INDYCAM_GAIN_DEFAULT 0x80
+#define INDYCAM_RED_BALANCE_DEFAULT 0x18
+#define INDYCAM_BLUE_BALANCE_DEFAULT 0xa4
+#define INDYCAM_RED_SATURATION_DEFAULT 0x80
+#define INDYCAM_BLUE_SATURATION_DEFAULT 0xc0
+#define INDYCAM_GAMMA_DEFAULT 0x80
+
+#endif
diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c
index fe194012bccf..3f2a882bc20a 100644
--- a/drivers/media/video/meye.c
+++ b/drivers/media/video/meye.c
@@ -37,6 +37,7 @@
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/vmalloc.h>
+#include <linux/dma-mapping.h>
#include "meye.h"
#include <linux/meye.h>
@@ -121,7 +122,7 @@ static int ptable_alloc(void)
memset(meye.mchip_ptable, 0, sizeof(meye.mchip_ptable));
/* give only 32 bit DMA addresses */
- if (dma_set_mask(&meye.mchip_dev->dev, 0xffffffff))
+ if (dma_set_mask(&meye.mchip_dev->dev, DMA_32BIT_MASK))
return -1;
meye.mchip_ptable_toc = dma_alloc_coherent(&meye.mchip_dev->dev,
diff --git a/drivers/media/video/saa7111.c b/drivers/media/video/saa7111.c
index f18df53d98ff..fe8a5e453969 100644
--- a/drivers/media/video/saa7111.c
+++ b/drivers/media/video/saa7111.c
@@ -42,7 +42,6 @@
#include <asm/pgtable.h>
#include <asm/page.h>
#include <linux/sched.h>
-#include <asm/segment.h>
#include <linux/types.h>
#include <linux/videodev.h>
diff --git a/drivers/media/video/saa7114.c b/drivers/media/video/saa7114.c
index e0c70f54f073..d9f50e2f7b92 100644
--- a/drivers/media/video/saa7114.c
+++ b/drivers/media/video/saa7114.c
@@ -45,7 +45,6 @@
#include <asm/pgtable.h>
#include <asm/page.h>
#include <linux/sched.h>
-#include <asm/segment.h>
#include <linux/types.h>
#include <linux/videodev.h>
diff --git a/drivers/media/video/saa7185.c b/drivers/media/video/saa7185.c
index e93412f4407c..132aa7943c16 100644
--- a/drivers/media/video/saa7185.c
+++ b/drivers/media/video/saa7185.c
@@ -39,7 +39,6 @@
#include <asm/pgtable.h>
#include <asm/page.h>
#include <linux/sched.h>
-#include <asm/segment.h>
#include <linux/types.h>
#include <linux/videodev.h>
diff --git a/drivers/media/video/saa7191.c b/drivers/media/video/saa7191.c
new file mode 100644
index 000000000000..454f5c1199b4
--- /dev/null
+++ b/drivers/media/video/saa7191.c
@@ -0,0 +1,512 @@
+/*
+ * saa7191.c - Philips SAA7191 video decoder driver
+ *
+ * Copyright (C) 2003 Ladislav Michl <ladis@linux-mips.org>
+ * Copyright (C) 2004,2005 Mikael Nousiainen <tmnousia@cc.hut.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+
+#include <linux/videodev.h>
+#include <linux/video_decoder.h>
+#include <linux/i2c.h>
+
+#include "saa7191.h"
+
+#define SAA7191_MODULE_VERSION "0.0.3"
+
+MODULE_DESCRIPTION("Philips SAA7191 video decoder driver");
+MODULE_VERSION(SAA7191_MODULE_VERSION);
+MODULE_AUTHOR("Mikael Nousiainen <tmnousia@cc.hut.fi>");
+MODULE_LICENSE("GPL");
+
+#define VINO_ADAPTER (I2C_ALGO_SGI | I2C_HW_SGI_VINO)
+
+struct saa7191 {
+ struct i2c_client *client;
+
+ /* the register values are stored here as the actual
+ * I2C-registers are write-only */
+ unsigned char reg[25];
+
+ unsigned char norm;
+ unsigned char input;
+};
+
+static struct i2c_driver i2c_driver_saa7191;
+
+static const unsigned char initseq[] = {
+ 0, /* Subaddress */
+ 0x50, /* SAA7191_REG_IDEL */
+ 0x30, /* SAA7191_REG_HSYB */
+ 0x00, /* SAA7191_REG_HSYS */
+ 0xe8, /* SAA7191_REG_HCLB */
+ 0xb6, /* SAA7191_REG_HCLS */
+ 0xf4, /* SAA7191_REG_HPHI */
+ 0x01, /* SAA7191_REG_LUMA - chrominance trap active (CVBS) */
+ 0x00, /* SAA7191_REG_HUEC */
+ 0xf8, /* SAA7191_REG_CKTQ */
+ 0xf8, /* SAA7191_REG_CKTS */
+ 0x90, /* SAA7191_REG_PLSE */
+ 0x90, /* SAA7191_REG_SESE */
+ 0x00, /* SAA7191_REG_GAIN */
+ 0x0c, /* SAA7191_REG_STDC - not SECAM, slow time constant */
+ 0x78, /* SAA7191_REG_IOCK - chrominance from CVBS, GPSW1 & 2 off */
+ 0x99, /* SAA7191_REG_CTL3 - automatic field detection */
+ 0x00, /* SAA7191_REG_CTL4 */
+ 0x2c, /* SAA7191_REG_CHCV */
+ 0x00, /* unused */
+ 0x00, /* unused */
+ 0x34, /* SAA7191_REG_HS6B */
+ 0x0a, /* SAA7191_REG_HS6S */
+ 0xf4, /* SAA7191_REG_HC6B */
+ 0xce, /* SAA7191_REG_HC6S */
+ 0xf4, /* SAA7191_REG_HP6I */
+};
+
+/* SAA7191 register handling */
+
+static unsigned char saa7191_read_reg(struct i2c_client *client,
+ unsigned char reg)
+{
+ return ((struct saa7191 *)i2c_get_clientdata(client))->reg[reg];
+}
+
+static int saa7191_read_status(struct i2c_client *client,
+ unsigned char *value)
+{
+ int ret;
+
+ ret = i2c_master_recv(client, value, 1);
+ if (ret < 0) {
+ printk(KERN_ERR "SAA7191: saa7191_read_status(): read failed");
+ return ret;
+ }
+
+ return 0;
+}
+
+
+static int saa7191_write_reg(struct i2c_client *client, unsigned char reg,
+ unsigned char value)
+{
+
+ ((struct saa7191 *)i2c_get_clientdata(client))->reg[reg] = value;
+ return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+/* the first byte of data must be the first subaddress number (register) */
+static int saa7191_write_block(struct i2c_client *client,
+ unsigned char length, unsigned char *data)
+{
+ int i;
+ int ret;
+
+ struct saa7191 *decoder = (struct saa7191 *)i2c_get_clientdata(client);
+ for (i = 0; i < (length - 1); i++) {
+ decoder->reg[data[0] + i] = data[i + 1];
+ }
+
+ ret = i2c_master_send(client, data, length);
+ if (ret < 0) {
+ printk(KERN_ERR "SAA7191: saa7191_write_block(): "
+ "write failed");
+ return ret;
+ }
+
+ return 0;
+}
+
+/* Helper functions */
+
+static int saa7191_set_input(struct i2c_client *client, int input)
+{
+ unsigned char luma = saa7191_read_reg(client, SAA7191_REG_LUMA);
+ unsigned char iock = saa7191_read_reg(client, SAA7191_REG_IOCK);
+ int err;
+
+ switch (input) {
+ case SAA7191_INPUT_COMPOSITE: /* Set Composite input */
+ iock &= ~(SAA7191_IOCK_CHRS | SAA7191_IOCK_GPSW1
+ | SAA7191_IOCK_GPSW2);
+ /* Chrominance trap active */
+ luma &= ~SAA7191_LUMA_BYPS;
+ break;
+ case SAA7191_INPUT_SVIDEO: /* Set S-Video input */
+ iock |= SAA7191_IOCK_CHRS | SAA7191_IOCK_GPSW2;
+ /* Chrominance trap bypassed */
+ luma |= SAA7191_LUMA_BYPS;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ err = saa7191_write_reg(client, SAA7191_REG_LUMA, luma);
+ if (err)
+ return -EIO;
+ err = saa7191_write_reg(client, SAA7191_REG_IOCK, iock);
+ if (err)
+ return -EIO;
+
+ return 0;
+}
+
+static int saa7191_set_norm(struct i2c_client *client, int norm)
+{
+ struct saa7191 *decoder = i2c_get_clientdata(client);
+ unsigned char stdc = saa7191_read_reg(client, SAA7191_REG_STDC);
+ unsigned char ctl3 = saa7191_read_reg(client, SAA7191_REG_CTL3);
+ unsigned char chcv = saa7191_read_reg(client, SAA7191_REG_CHCV);
+ int err;
+
+ switch(norm) {
+ case SAA7191_NORM_AUTO: {
+ unsigned char status;
+
+ // does status depend on current norm ?
+ if (saa7191_read_status(client, &status))
+ return -EIO;
+
+ stdc &= ~SAA7191_STDC_SECS;
+ ctl3 &= ~SAA7191_CTL3_FSEL;
+ ctl3 |= SAA7191_CTL3_AUFD;
+ chcv = (status & SAA7191_STATUS_FIDT)
+ ? SAA7191_CHCV_NTSC : SAA7191_CHCV_PAL;
+ break;
+ }
+ case SAA7191_NORM_PAL:
+ stdc &= ~SAA7191_STDC_SECS;
+ ctl3 &= ~(SAA7191_CTL3_AUFD | SAA7191_CTL3_FSEL);
+ chcv = SAA7191_CHCV_PAL;
+ break;
+ case SAA7191_NORM_NTSC:
+ stdc &= ~SAA7191_STDC_SECS;
+ ctl3 &= ~SAA7191_CTL3_AUFD;
+ ctl3 |= SAA7191_CTL3_FSEL;
+ chcv = SAA7191_CHCV_NTSC;
+ break;
+ case SAA7191_NORM_SECAM:
+ stdc |= SAA7191_STDC_SECS;
+ ctl3 &= ~(SAA7191_CTL3_AUFD | SAA7191_CTL3_FSEL);
+ chcv = SAA7191_CHCV_PAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ err = saa7191_write_reg(client, SAA7191_REG_CTL3, ctl3);
+ if (err)
+ return -EIO;
+ err = saa7191_write_reg(client, SAA7191_REG_STDC, stdc);
+ if (err)
+ return -EIO;
+ err = saa7191_write_reg(client, SAA7191_REG_CHCV, chcv);
+ if (err)
+ return -EIO;
+
+ decoder->norm = norm;
+
+ return 0;
+}
+
+static int saa7191_get_controls(struct i2c_client *client,
+ struct saa7191_control *ctrl)
+{
+ unsigned char hue = saa7191_read_reg(client, SAA7191_REG_HUEC);
+ unsigned char stdc = saa7191_read_reg(client, SAA7191_REG_STDC);
+
+ if (hue < 0x80) {
+ hue += 0x80;
+ } else {
+ hue -= 0x80;
+ }
+ ctrl->hue = hue;
+
+ ctrl->vtrc = (stdc & SAA7191_STDC_VTRC)
+ ? SAA7191_VALUE_ENABLED : SAA7191_VALUE_DISABLED;
+
+ return 0;
+}
+
+static int saa7191_set_controls(struct i2c_client *client,
+ struct saa7191_control *ctrl)
+{
+ int err;
+
+ if (ctrl->hue >= 0) {
+ unsigned char hue = ctrl->hue & 0xff;
+ if (hue < 0x80) {
+ hue += 0x80;
+ } else {
+ hue -= 0x80;
+ }
+ err = saa7191_write_reg(client, SAA7191_REG_HUEC, hue);
+ if (err)
+ return -EIO;
+ }
+ if (ctrl->vtrc >= 0) {
+ unsigned char stdc =
+ saa7191_read_reg(client, SAA7191_REG_STDC);
+
+ if (ctrl->vtrc) {
+ stdc |= SAA7191_STDC_VTRC;
+ } else {
+ stdc &= ~SAA7191_STDC_VTRC;
+ }
+
+ err = saa7191_write_reg(client, SAA7191_REG_STDC, stdc);
+ if (err)
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/* I2C-interface */
+
+static int saa7191_attach(struct i2c_adapter *adap, int addr, int kind)
+{
+ int err = 0;
+ struct saa7191 *decoder;
+ struct i2c_client *client;
+
+ printk(KERN_INFO "Philips SAA7191 driver version %s\n",
+ SAA7191_MODULE_VERSION);
+
+ client = kmalloc(sizeof(*client), GFP_KERNEL);
+ if (!client)
+ return -ENOMEM;
+ decoder = kmalloc(sizeof(*decoder), GFP_KERNEL);
+ if (!decoder) {
+ err = -ENOMEM;
+ goto out_free_client;
+ }
+
+ memset(client, 0, sizeof(struct i2c_client));
+ memset(decoder, 0, sizeof(struct saa7191));
+
+ client->addr = addr;
+ client->adapter = adap;
+ client->driver = &i2c_driver_saa7191;
+ client->flags = 0;
+ strcpy(client->name, "saa7191 client");
+ i2c_set_clientdata(client, decoder);
+
+ decoder->client = client;
+
+ err = i2c_attach_client(client);
+ if (err)
+ goto out_free_decoder;
+
+ decoder->input = SAA7191_INPUT_COMPOSITE;
+ decoder->norm = SAA7191_NORM_AUTO;
+
+ err = saa7191_write_block(client, sizeof(initseq),
+ (unsigned char *)initseq);
+ if (err) {
+ printk(KERN_ERR "SAA7191 initialization failed\n");
+ goto out_detach_client;
+ }
+
+ printk(KERN_INFO "SAA7191 initialized\n");
+
+ return 0;
+
+out_detach_client:
+ i2c_detach_client(client);
+out_free_decoder:
+ kfree(decoder);
+out_free_client:
+ kfree(client);
+ return err;
+}
+
+static int saa7191_probe(struct i2c_adapter *adap)
+{
+ /* Always connected to VINO */
+ if (adap->id == VINO_ADAPTER)
+ return saa7191_attach(adap, SAA7191_ADDR, 0);
+ /* Feel free to add probe here :-) */
+ return -ENODEV;
+}
+
+static int saa7191_detach(struct i2c_client *client)
+{
+ struct saa7191 *decoder = i2c_get_clientdata(client);
+
+ i2c_detach_client(client);
+ kfree(decoder);
+ kfree(client);
+ return 0;
+}
+
+static int saa7191_command(struct i2c_client *client, unsigned int cmd,
+ void *arg)
+{
+ struct saa7191 *decoder = i2c_get_clientdata(client);
+
+ switch (cmd) {
+ case DECODER_GET_CAPABILITIES: {
+ struct video_decoder_capability *cap = arg;
+
+ cap->flags = VIDEO_DECODER_PAL | VIDEO_DECODER_NTSC |
+ VIDEO_DECODER_SECAM | VIDEO_DECODER_AUTO;
+ cap->inputs = (client->adapter->id == VINO_ADAPTER) ? 2 : 1;
+ cap->outputs = 1;
+ break;
+ }
+ case DECODER_GET_STATUS: {
+ int *iarg = arg;
+ unsigned char status;
+ int res = 0;
+
+ if (saa7191_read_status(client, &status)) {
+ return -EIO;
+ }
+ if ((status & SAA7191_STATUS_HLCK) == 0)
+ res |= DECODER_STATUS_GOOD;
+ if (status & SAA7191_STATUS_CODE)
+ res |= DECODER_STATUS_COLOR;
+ switch (decoder->norm) {
+ case SAA7191_NORM_NTSC:
+ res |= DECODER_STATUS_NTSC;
+ break;
+ case SAA7191_NORM_PAL:
+ res |= DECODER_STATUS_PAL;
+ break;
+ case SAA7191_NORM_SECAM:
+ res |= DECODER_STATUS_SECAM;
+ break;
+ case SAA7191_NORM_AUTO:
+ default:
+ if (status & SAA7191_STATUS_FIDT)
+ res |= DECODER_STATUS_NTSC;
+ else
+ res |= DECODER_STATUS_PAL;
+ break;
+ }
+ *iarg = res;
+ break;
+ }
+ case DECODER_SET_NORM: {
+ int *iarg = arg;
+
+ switch (*iarg) {
+ case VIDEO_MODE_AUTO:
+ return saa7191_set_norm(client, SAA7191_NORM_AUTO);
+ case VIDEO_MODE_PAL:
+ return saa7191_set_norm(client, SAA7191_NORM_PAL);
+ case VIDEO_MODE_NTSC:
+ return saa7191_set_norm(client, SAA7191_NORM_NTSC);
+ case VIDEO_MODE_SECAM:
+ return saa7191_set_norm(client, SAA7191_NORM_SECAM);
+ default:
+ return -EINVAL;
+ }
+ break;
+ }
+ case DECODER_SET_INPUT: {
+ int *iarg = arg;
+
+ switch (client->adapter->id) {
+ case VINO_ADAPTER:
+ return saa7191_set_input(client, *iarg);
+ default:
+ if (*iarg != 0)
+ return -EINVAL;
+ }
+ break;
+ }
+ case DECODER_SET_OUTPUT: {
+ int *iarg = arg;
+
+ /* not much choice of outputs */
+ if (*iarg != 0)
+ return -EINVAL;
+ break;
+ }
+ case DECODER_ENABLE_OUTPUT: {
+ /* Always enabled */
+ break;
+ }
+ case DECODER_SET_PICTURE: {
+ struct video_picture *pic = arg;
+ unsigned val;
+ int err;
+
+ val = (pic->hue >> 8) - 0x80;
+ err = saa7191_write_reg(client, SAA7191_REG_HUEC, val);
+ if (err)
+ return -EIO;
+ break;
+ }
+ case DECODER_SAA7191_GET_STATUS: {
+ struct saa7191_status *status = arg;
+ unsigned char status_reg;
+
+ if (saa7191_read_status(client, &status_reg))
+ return -EIO;
+ status->signal = ((status_reg & SAA7191_STATUS_HLCK) == 0)
+ ? SAA7191_VALUE_ENABLED : SAA7191_VALUE_DISABLED;
+ status->ntsc = (status_reg & SAA7191_STATUS_FIDT)
+ ? SAA7191_VALUE_ENABLED : SAA7191_VALUE_DISABLED;
+ status->color = (status_reg & SAA7191_STATUS_CODE)
+ ? SAA7191_VALUE_ENABLED : SAA7191_VALUE_DISABLED;
+
+ status->input = decoder->input;
+ status->norm = decoder->norm;
+ }
+ case DECODER_SAA7191_SET_NORM: {
+ int *norm = arg;
+ return saa7191_set_norm(client, *norm);
+ }
+ case DECODER_SAA7191_GET_CONTROLS: {
+ struct saa7191_control *ctrl = arg;
+ return saa7191_get_controls(client, ctrl);
+ }
+ case DECODER_SAA7191_SET_CONTROLS: {
+ struct saa7191_control *ctrl = arg;
+ return saa7191_set_controls(client, ctrl);
+ }
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static struct i2c_driver i2c_driver_saa7191 = {
+ .owner = THIS_MODULE,
+ .name = "saa7191",
+ .id = I2C_DRIVERID_SAA7191,
+ .flags = I2C_DF_NOTIFY,
+ .attach_adapter = saa7191_probe,
+ .detach_client = saa7191_detach,
+ .command = saa7191_command
+};
+
+static int saa7191_init(void)
+{
+ return i2c_add_driver(&i2c_driver_saa7191);
+}
+
+static void saa7191_exit(void)
+{
+ i2c_del_driver(&i2c_driver_saa7191);
+}
+
+module_init(saa7191_init);
+module_exit(saa7191_exit);
diff --git a/drivers/media/video/saa7191.h b/drivers/media/video/saa7191.h
new file mode 100644
index 000000000000..272045031435
--- /dev/null
+++ b/drivers/media/video/saa7191.h
@@ -0,0 +1,139 @@
+/*
+ * saa7191.h - Philips SAA7191 video decoder driver
+ *
+ * Copyright (C) 2003 Ladislav Michl <ladis@linux-mips.org>
+ * Copyright (C) 2004,2005 Mikael Nousiainen <tmnousia@cc.hut.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _SAA7191_H_
+#define _SAA7191_H_
+
+/* Philips SAA7191 DMSD I2C bus address */
+#define SAA7191_ADDR 0x8a
+
+/* Register subaddresses. */
+#define SAA7191_REG_IDEL 0x00
+#define SAA7191_REG_HSYB 0x01
+#define SAA7191_REG_HSYS 0x02
+#define SAA7191_REG_HCLB 0x03
+#define SAA7191_REG_HCLS 0x04
+#define SAA7191_REG_HPHI 0x05
+#define SAA7191_REG_LUMA 0x06
+#define SAA7191_REG_HUEC 0x07
+#define SAA7191_REG_CKTQ 0x08
+#define SAA7191_REG_CKTS 0x09
+#define SAA7191_REG_PLSE 0x0a
+#define SAA7191_REG_SESE 0x0b
+#define SAA7191_REG_GAIN 0x0c
+#define SAA7191_REG_STDC 0x0d
+#define SAA7191_REG_IOCK 0x0e
+#define SAA7191_REG_CTL3 0x0f
+#define SAA7191_REG_CTL4 0x10
+#define SAA7191_REG_CHCV 0x11
+#define SAA7191_REG_HS6B 0x14
+#define SAA7191_REG_HS6S 0x15
+#define SAA7191_REG_HC6B 0x16
+#define SAA7191_REG_HC6S 0x17
+#define SAA7191_REG_HP6I 0x18
+#define SAA7191_REG_STATUS 0xff /* not really a subaddress */
+
+/* Status Register definitions */
+#define SAA7191_STATUS_CODE 0x01 /* color detected flag */
+#define SAA7191_STATUS_FIDT 0x20 /* format type NTSC/PAL */
+#define SAA7191_STATUS_HLCK 0x40 /* PLL unlocked/locked */
+#define SAA7191_STATUS_STTC 0x80 /* tv/vtr time constant */
+
+/* Luminance Control Register definitions */
+#define SAA7191_LUMA_BYPS 0x80
+
+/* Chroma Gain Control Settings Register definitions */
+/* 0=automatic colour-killer enabled, 1=forced colour on */
+#define SAA7191_GAIN_COLO 0x80
+
+/* Standard/Mode Control Register definitions */
+/* tv/vtr mode bit: 0=TV mode (slow time constant),
+ * 1=VTR mode (fast time constant) */
+#define SAA7191_STDC_VTRC 0x80
+/* SECAM mode bit: 0=other standards, 1=SECAM */
+#define SAA7191_STDC_SECS 0x01
+/* the bit fields above must be or'd with this value */
+#define SAA7191_STDC_VALUE 0x0c
+
+/* I/O and Clock Control Register definitions */
+/* horizontal clock PLL: 0=PLL closed,
+ * 1=PLL circuit open and horizontal freq fixed */
+#define SAA7191_IOCK_HPLL 0x80
+/* S-VHS bit (chrominance from CVBS or from chrominance input):
+ * 0=controlled by BYPS-bit, 1=from chrominance input */
+#define SAA7191_IOCK_CHRS 0x04
+/* general purpose switch 2
+ * VINO-specific: 0=used with CVBS, 1=used with S-Video */
+#define SAA7191_IOCK_GPSW2 0x02
+/* general purpose switch 1 */
+/* VINO-specific: 0=always, 1=not used!*/
+#define SAA7191_IOCK_GPSW1 0x01
+
+/* Miscellaneous Control #1 Register definitions */
+/* automatic field detection (50/60Hz standard) */
+#define SAA7191_CTL3_AUFD 0x80
+/* field select: (if AUFD=0)
+ * 0=50Hz (625 lines), 1=60Hz (525 lines) */
+#define SAA7191_CTL3_FSEL 0x40
+/* the bit fields above must be or'd with this value */
+#define SAA7191_CTL3_VALUE 0x19
+
+/* Chrominance Gain Control Register definitions
+ * (nominal value for UV CCIR level) */
+#define SAA7191_CHCV_NTSC 0x2c
+#define SAA7191_CHCV_PAL 0x59
+
+/* Driver interface definitions */
+#define SAA7191_INPUT_COMPOSITE 0
+#define SAA7191_INPUT_SVIDEO 1
+
+#define SAA7191_NORM_AUTO 0
+#define SAA7191_NORM_PAL 1
+#define SAA7191_NORM_NTSC 2
+#define SAA7191_NORM_SECAM 3
+
+#define SAA7191_VALUE_ENABLED 1
+#define SAA7191_VALUE_DISABLED 0
+#define SAA7191_VALUE_UNCHANGED -1
+
+struct saa7191_status {
+ /* 0=no signal, 1=signal active*/
+ int signal;
+ /* 0=50hz (pal) signal, 1=60hz (ntsc) signal */
+ int ntsc;
+ /* 0=no color detected, 1=color detected */
+ int color;
+
+ /* current SAA7191_INPUT_ */
+ int input;
+ /* current SAA7191_NORM_ */
+ int norm;
+};
+
+#define SAA7191_HUE_MIN 0x00
+#define SAA7191_HUE_MAX 0xff
+#define SAA7191_HUE_DEFAULT 0x80
+
+#define SAA7191_VTRC_MIN 0x00
+#define SAA7191_VTRC_MAX 0x01
+#define SAA7191_VTRC_DEFAULT 0x00
+
+struct saa7191_control {
+ int hue;
+ int vtrc;
+};
+
+#define DECODER_SAA7191_GET_STATUS _IOR('d', 195, struct saa7191_status)
+#define DECODER_SAA7191_SET_NORM _IOW('d', 196, int)
+#define DECODER_SAA7191_GET_CONTROLS _IOR('d', 197, struct saa7191_control)
+#define DECODER_SAA7191_SET_CONTROLS _IOW('d', 198, struct saa7191_control)
+
+#endif
diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c
index 76e8681d65c6..d8a0f763ca10 100644
--- a/drivers/media/video/vino.c
+++ b/drivers/media/video/vino.c
@@ -1,80 +1,606 @@
/*
- * (incomplete) Driver for the VINO (Video In No Out) system found in SGI Indys.
+ * Driver for the VINO (Video In No Out) system found in SGI Indys.
*
* This file is subject to the terms and conditions of the GNU General Public
* License version 2 as published by the Free Software Foundation.
*
+ * Copyright (C) 2004,2005 Mikael Nousiainen <tmnousia@cc.hut.fi>
+ *
+ * Based on the previous version of the driver for 2.4 kernels by:
* Copyright (C) 2003 Ladislav Michl <ladis@linux-mips.org>
*/
-#include <linux/module.h>
+/*
+ * TODO:
+ * - remove "hacks" from memory allocation code and implement nopage()
+ * - check decimation, calculating and reporting image size when
+ * using decimation
+ * - check vino_acquire_input(), vino_set_input() and channel
+ * ownership handling
+ * - report VINO error-interrupts via ioctls ?
+ * - implement picture controls (all implemented?)
+ * - use macros for boolean values (?)
+ * - implement user mode buffers and overlay (?)
+ */
+
#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/wrapper.h>
-#include <linux/errno.h>
-#include <linux/irq.h>
+#include <linux/module.h>
#include <linux/delay.h>
-#include <linux/videodev.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/time.h>
+#include <linux/moduleparam.h>
+
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
+#endif
+
#include <linux/i2c.h>
#include <linux/i2c-algo-sgi.h>
-#include <asm/addrspace.h>
-#include <asm/system.h>
-#include <asm/bootinfo.h>
-#include <asm/pgtable.h>
+#include <linux/videodev.h>
+#include <linux/videodev2.h>
+#include <linux/video_decoder.h>
+
#include <asm/paccess.h>
#include <asm/io.h>
#include <asm/sgi/ip22.h>
-#include <asm/sgi/hpc3.h>
#include <asm/sgi/mc.h>
#include "vino.h"
+#include "saa7191.h"
+#include "indycam.h"
+
+/* Uncomment the following line to get lots and lots of (mostly useless)
+ * debug info.
+ * Note that the debug output also slows down the driver significantly */
+// #define VINO_DEBUG
+
+#define VINO_MODULE_VERSION "0.0.3"
+#define VINO_VERSION_CODE KERNEL_VERSION(0, 0, 3)
+
+MODULE_DESCRIPTION("SGI VINO Video4Linux2 driver");
+MODULE_VERSION(VINO_MODULE_VERSION);
+MODULE_AUTHOR("Mikael Nousiainen <tmnousia@cc.hut.fi>");
+MODULE_LICENSE("GPL");
-/* debugging? */
-#if 1
-#define DEBUG(x...) printk(x);
+#define mem_map_reserve(p) set_bit(PG_reserved, &((p)->flags))
+#define mem_map_unreserve(p) clear_bit(PG_reserved, &((p)->flags))
+
+#ifdef VINO_DEBUG
+#define dprintk(x...) printk("VINO: " x);
#else
-#define DEBUG(x...)
+#define dprintk(x...)
#endif
+#define VINO_NO_CHANNEL 0
+#define VINO_CHANNEL_A 1
+#define VINO_CHANNEL_B 2
+
+#define VINO_PAL_WIDTH 768
+#define VINO_PAL_HEIGHT 576
+#define VINO_NTSC_WIDTH 640
+#define VINO_NTSC_HEIGHT 480
+
+#define VINO_MIN_WIDTH 32
+#define VINO_MIN_HEIGHT 32
+
+#define VINO_CLIPPING_START_ODD_D1 1
+#define VINO_CLIPPING_START_ODD_PAL 1
+#define VINO_CLIPPING_START_ODD_NTSC 1
+
+#define VINO_CLIPPING_START_EVEN_D1 2
+#define VINO_CLIPPING_START_EVEN_PAL 2
+#define VINO_CLIPPING_START_EVEN_NTSC 2
+
+#define VINO_INPUT_CHANNEL_COUNT 3
+
+#define VINO_INPUT_NONE -1
+#define VINO_INPUT_COMPOSITE 0
+#define VINO_INPUT_SVIDEO 1
+#define VINO_INPUT_D1 2
+
+#define VINO_PAGE_RATIO (PAGE_SIZE / VINO_PAGE_SIZE)
+
+#define VINO_FIFO_THRESHOLD_DEFAULT 512
+
+/*#define VINO_FRAMEBUFFER_SIZE (VINO_PAL_WIDTH * VINO_PAL_HEIGHT * 4 \
+ + 2 * PAGE_SIZE)*/
+#define VINO_FRAMEBUFFER_SIZE ((VINO_PAL_WIDTH \
+ * VINO_PAL_HEIGHT * 4 \
+ + 3 * PAGE_SIZE) & ~(PAGE_SIZE - 1))
+
+#define VINO_FRAMEBUFFER_MAX_COUNT 8
+
+#define VINO_FRAMEBUFFER_UNUSED 0
+#define VINO_FRAMEBUFFER_IN_USE 1
+#define VINO_FRAMEBUFFER_READY 2
+
+#define VINO_QUEUE_ERROR -1
+#define VINO_QUEUE_MAGIC 0x20050125
+
+#define VINO_MEMORY_NONE 0
+#define VINO_MEMORY_MMAP 1
+#define VINO_MEMORY_USERPTR 2
+
+#define VINO_DUMMY_DESC_COUNT 4
+#define VINO_DESC_FETCH_DELAY 5 /* microseconds */
+
+/* the number is the index for vino_data_formats */
+#define VINO_DATA_FMT_NONE -1
+#define VINO_DATA_FMT_GREY 0
+#define VINO_DATA_FMT_RGB332 1
+#define VINO_DATA_FMT_RGB32 2
+#define VINO_DATA_FMT_YUV 3
+//#define VINO_DATA_FMT_RGB24 4
+
+#define VINO_DATA_FMT_COUNT 4
+
+#define VINO_DATA_NORM_NONE -1
+#define VINO_DATA_NORM_NTSC 0
+#define VINO_DATA_NORM_PAL 1
+#define VINO_DATA_NORM_SECAM 2
+#define VINO_DATA_NORM_D1 3
+/* The following is a special entry that can be used to
+ * autodetect the norm. */
+#define VINO_DATA_NORM_AUTO 0xff
+
+#define VINO_DATA_NORM_COUNT 4
-/* VINO ASIC registers */
-struct sgi_vino *vino;
+/* Internal data structure definitions */
-static const char *vinostr = "VINO IndyCam/TV";
-static int threshold_a = 512;
-static int threshold_b = 512;
+struct vino_input {
+ char *name;
+ v4l2_std_id std;
+};
+
+struct vino_clipping {
+ unsigned int left, right, top, bottom;
+};
+
+struct vino_data_format {
+ /* the description */
+ char *description;
+ /* bytes per pixel */
+ unsigned int bpp;
+ /* V4L2 fourcc code */
+ __u32 pixelformat;
+ /* V4L2 colorspace (duh!) */
+ enum v4l2_colorspace colorspace;
+};
+
+struct vino_data_norm {
+ char *description;
+ unsigned int width, height;
+ struct vino_clipping odd;
+ struct vino_clipping even;
+
+ v4l2_std_id std;
+ unsigned int fps_min, fps_max;
+ __u32 framelines;
+};
+
+struct vino_descriptor_table {
+ /* the number of PAGE_SIZE sized pages in the buffer */
+ unsigned int page_count;
+ /* virtual (kmalloc'd) pointers to the actual data
+ * (in PAGE_SIZE chunks, used with mmap streaming) */
+ unsigned long *virtual;
+
+ /* cpu address for the VINO descriptor table
+ * (contains DMA addresses, VINO_PAGE_SIZE chunks) */
+ unsigned long *dma_cpu;
+ /* dma address for the VINO descriptor table
+ * (contains DMA addresses, VINO_PAGE_SIZE chunks) */
+ dma_addr_t dma;
+};
+
+struct vino_framebuffer {
+ /* identifier nubmer */
+ unsigned int id;
+ /* the length of the whole buffer */
+ unsigned int size;
+ /* the length of actual data in buffer */
+ unsigned int data_size;
+ /* the data format */
+ unsigned int data_format;
+ /* the state of buffer data */
+ unsigned int state;
+ /* is the buffer mapped in user space? */
+ unsigned int map_count;
+ /* memory offset for mmap() */
+ unsigned int offset;
+ /* frame counter */
+ unsigned int frame_counter;
+ /* timestamp (written when image capture finishes) */
+ struct timeval timestamp;
+
+ struct vino_descriptor_table desc_table;
+
+ spinlock_t state_lock;
+};
-struct vino_device {
- struct video_device vdev;
-#define VINO_CHAN_A 1
-#define VINO_CHAN_B 2
- int chan;
+struct vino_framebuffer_fifo {
+ unsigned int length;
+
+ unsigned int used;
+ unsigned int head;
+ unsigned int tail;
+
+ unsigned int data[VINO_FRAMEBUFFER_MAX_COUNT];
+};
+
+struct vino_framebuffer_queue {
+ unsigned int magic;
+
+ /* VINO_MEMORY_NONE, VINO_MEMORY_MMAP or VINO_MEMORY_USERPTR */
+ unsigned int type;
+ unsigned int length;
+
+ /* data field of in and out contain index numbers for buffer */
+ struct vino_framebuffer_fifo in;
+ struct vino_framebuffer_fifo out;
+
+ struct vino_framebuffer *buffer[VINO_FRAMEBUFFER_MAX_COUNT];
+
+ spinlock_t queue_lock;
+ struct semaphore queue_sem;
+ wait_queue_head_t frame_wait_queue;
+};
+
+struct vino_channel_settings {
+ unsigned int channel;
+
+ int input;
+ unsigned int data_format;
+ unsigned int data_norm;
+ struct vino_clipping clipping;
+ unsigned int decimation;
+ unsigned int line_size;
+ unsigned int alpha;
+ unsigned int fps;
+ unsigned int framert_reg;
+
+ unsigned int fifo_threshold;
+
+ struct vino_framebuffer_queue fb_queue;
+
+ /* number of the current field */
+ unsigned int field;
+
+ /* read in progress */
+ int reading;
+ /* streaming is active */
+ int streaming;
+ /* the driver is currently processing the queue */
+ int capturing;
+
+ struct semaphore sem;
+ spinlock_t capture_lock;
+
+ unsigned int users;
+
+ /* V4L support */
+ struct video_device *v4l_device;
};
struct vino_client {
+ /* the channel which owns this client:
+ * VINO_NO_CHANNEL, VINO_CHANNEL_A or VINO_CHANNEL_B */
+ unsigned int owner;
struct i2c_client *driver;
- int owner;
};
-struct vino_video {
- struct vino_device chA;
- struct vino_device chB;
+struct vino_settings {
+ struct vino_channel_settings a;
+ struct vino_channel_settings b;
struct vino_client decoder;
struct vino_client camera;
- struct semaphore input_lock;
+ /* a lock for vino register access */
+ spinlock_t vino_lock;
+ /* a lock for channel input changes */
+ spinlock_t input_lock;
- /* Loaded into VINO descriptors to clear End Of Descriptors table
- * interupt condition */
unsigned long dummy_page;
- unsigned int dummy_buf[4] __attribute__((aligned(8)));
+ struct vino_descriptor_table dummy_desc_table;
};
-static struct vino_video *Vino;
+/* Module parameters */
+
+/*
+ * Using vino_pixel_conversion the ARGB32-format pixels supplied
+ * by the VINO chip can be converted to more common formats
+ * like RGBA32 (or probably RGB24 in the future). This way we
+ * can give out data that can be specified correctly with
+ * the V4L2-definitions.
+ *
+ * The pixel format is specified as RGBA32 when no conversion
+ * is used.
+ *
+ * Note that this only affects the 32-bit bit depth.
+ *
+ * Use non-zero value to enable conversion.
+ */
+static int vino_pixel_conversion = 0;
+module_param_named(pixelconv, vino_pixel_conversion, int, 0);
+MODULE_PARM_DESC(pixelconv,
+ "enable pixel conversion (non-zero value enables)");
+
+/* Internal data structures */
+
+static struct sgi_vino *vino;
+
+static struct vino_settings *vino_drvdata;
+
+static const char *vino_driver_name = "vino";
+static const char *vino_driver_description = "SGI VINO";
+static const char *vino_bus_name = "GIO64 bus";
+static const char *vino_v4l_device_name_a = "SGI VINO Channel A";
+static const char *vino_v4l_device_name_b = "SGI VINO Channel B";
+
+static const struct vino_input vino_inputs[] = {
+ {
+ .name = "Composite",
+ .std = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM,
+ },{
+ .name = "S-Video",
+ .std = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM,
+ },{
+ .name = "D1 (IndyCam)",
+ .std = V4L2_STD_NTSC,
+ }
+};
+
+static const struct vino_data_format vino_data_formats[] = {
+ {
+ .description = "8-bit greyscale",
+ .bpp = 1,
+ .pixelformat = V4L2_PIX_FMT_GREY,
+ .colorspace = V4L2_COLORSPACE_SMPTE170M,
+ },{
+ .description = "8-bit dithered RGB 3-3-2",
+ .bpp = 1,
+ .pixelformat = V4L2_PIX_FMT_RGB332,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ },{
+ .description = "32-bit RGB",
+ .bpp = 4,
+ .pixelformat = V4L2_PIX_FMT_RGB32,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ },{
+ .description = "YUV 4:2:2",
+ .bpp = 4,
+ .pixelformat = V4L2_PIX_FMT_YUYV, // XXX: swapped?
+ .colorspace = V4L2_COLORSPACE_SMPTE170M,
+ }/*,{
+ .description = "24-bit RGB",
+ .bpp = 3,
+ .pixelformat = V4L2_PIX_FMT_RGB24,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ }*/
+};
+
+static const struct vino_data_norm vino_data_norms[] = {
+ {
+ .description = "NTSC",
+ .std = V4L2_STD_NTSC,
+ .fps_min = 6,
+ .fps_max = 30,
+ .framelines = 525,
+ .width = VINO_NTSC_WIDTH,
+ .height = VINO_NTSC_HEIGHT,
+ .odd = {
+ .top = VINO_CLIPPING_START_ODD_NTSC,
+ .left = 0,
+ .bottom = VINO_CLIPPING_START_ODD_NTSC
+ + VINO_NTSC_HEIGHT / 2 - 1,
+ .right = VINO_NTSC_WIDTH,
+ },
+ .even = {
+ .top = VINO_CLIPPING_START_EVEN_NTSC,
+ .left = 0,
+ .bottom = VINO_CLIPPING_START_EVEN_NTSC
+ + VINO_NTSC_HEIGHT / 2 - 1,
+ .right = VINO_NTSC_WIDTH,
+ },
+ },{
+ .description = "PAL",
+ .std = V4L2_STD_PAL,
+ .fps_min = 5,
+ .fps_max = 25,
+ .framelines = 625,
+ .width = VINO_PAL_WIDTH,
+ .height = VINO_PAL_HEIGHT,
+ .odd = {
+ .top = VINO_CLIPPING_START_ODD_PAL,
+ .left = 0,
+ .bottom = VINO_CLIPPING_START_ODD_PAL
+ + VINO_PAL_HEIGHT / 2 - 1,
+ .right = VINO_PAL_WIDTH,
+ },
+ .even = {
+ .top = VINO_CLIPPING_START_EVEN_PAL,
+ .left = 0,
+ .bottom = VINO_CLIPPING_START_EVEN_PAL
+ + VINO_PAL_HEIGHT / 2 - 1,
+ .right = VINO_PAL_WIDTH,
+ },
+ },{
+ .description = "SECAM",
+ .std = V4L2_STD_SECAM,
+ .fps_min = 5,
+ .fps_max = 25,
+ .framelines = 625,
+ .width = VINO_PAL_WIDTH,
+ .height = VINO_PAL_HEIGHT,
+ .odd = {
+ .top = VINO_CLIPPING_START_ODD_PAL,
+ .left = 0,
+ .bottom = VINO_CLIPPING_START_ODD_PAL
+ + VINO_PAL_HEIGHT / 2 - 1,
+ .right = VINO_PAL_WIDTH,
+ },
+ .even = {
+ .top = VINO_CLIPPING_START_EVEN_PAL,
+ .left = 0,
+ .bottom = VINO_CLIPPING_START_EVEN_PAL
+ + VINO_PAL_HEIGHT / 2 - 1,
+ .right = VINO_PAL_WIDTH,
+ },
+ },{
+ .description = "NTSC (D1 input)",
+ .std = V4L2_STD_NTSC,
+ .fps_min = 6,
+ .fps_max = 30,
+ .framelines = 525,
+ .width = VINO_NTSC_WIDTH,
+ .height = VINO_NTSC_HEIGHT,
+ .odd = {
+ .top = VINO_CLIPPING_START_ODD_D1,
+ .left = 0,
+ .bottom = VINO_CLIPPING_START_ODD_D1
+ + VINO_NTSC_HEIGHT / 2 - 1,
+ .right = VINO_NTSC_WIDTH,
+ },
+ .even = {
+ .top = VINO_CLIPPING_START_EVEN_D1,
+ .left = 0,
+ .bottom = VINO_CLIPPING_START_EVEN_D1
+ + VINO_NTSC_HEIGHT / 2 - 1,
+ .right = VINO_NTSC_WIDTH,
+ },
+ }
+};
+
+#define VINO_INDYCAM_V4L2_CONTROL_COUNT 9
+
+struct v4l2_queryctrl vino_indycam_v4l2_controls[] = {
+ {
+ .id = V4L2_CID_AUTOGAIN,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Automatic Gain Control",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = INDYCAM_AGC_DEFAULT,
+ .flags = 0,
+ .reserved = { 0, 0 },
+ },{
+ .id = V4L2_CID_AUTO_WHITE_BALANCE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Automatic White Balance",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = INDYCAM_AWB_DEFAULT,
+ .flags = 0,
+ .reserved = { 0, 0 },
+ },{
+ .id = V4L2_CID_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Gain",
+ .minimum = INDYCAM_GAIN_MIN,
+ .maximum = INDYCAM_GAIN_MAX,
+ .step = 1,
+ .default_value = INDYCAM_GAIN_DEFAULT,
+ .flags = 0,
+ .reserved = { 0, 0 },
+ },{
+ .id = V4L2_CID_PRIVATE_BASE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Red Saturation",
+ .minimum = INDYCAM_RED_SATURATION_MIN,
+ .maximum = INDYCAM_RED_SATURATION_MAX,
+ .step = 1,
+ .default_value = INDYCAM_RED_SATURATION_DEFAULT,
+ .flags = 0,
+ .reserved = { 0, 0 },
+ },{
+ .id = V4L2_CID_PRIVATE_BASE + 1,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Blue Saturation",
+ .minimum = INDYCAM_BLUE_SATURATION_MIN,
+ .maximum = INDYCAM_BLUE_SATURATION_MAX,
+ .step = 1,
+ .default_value = INDYCAM_BLUE_SATURATION_DEFAULT,
+ .flags = 0,
+ .reserved = { 0, 0 },
+ },{
+ .id = V4L2_CID_RED_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Red Balance",
+ .minimum = INDYCAM_RED_BALANCE_MIN,
+ .maximum = INDYCAM_RED_BALANCE_MAX,
+ .step = 1,
+ .default_value = INDYCAM_RED_BALANCE_DEFAULT,
+ .flags = 0,
+ .reserved = { 0, 0 },
+ },{
+ .id = V4L2_CID_BLUE_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Blue Balance",
+ .minimum = INDYCAM_BLUE_BALANCE_MIN,
+ .maximum = INDYCAM_BLUE_BALANCE_MAX,
+ .step = 1,
+ .default_value = INDYCAM_BLUE_BALANCE_DEFAULT,
+ .flags = 0,
+ .reserved = { 0, 0 },
+ },{
+ .id = V4L2_CID_EXPOSURE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Shutter Control",
+ .minimum = INDYCAM_SHUTTER_MIN,
+ .maximum = INDYCAM_SHUTTER_MAX,
+ .step = 1,
+ .default_value = INDYCAM_SHUTTER_DEFAULT,
+ .flags = 0,
+ .reserved = { 0, 0 },
+ },{
+ .id = V4L2_CID_GAMMA,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Gamma",
+ .minimum = INDYCAM_GAMMA_MIN,
+ .maximum = INDYCAM_GAMMA_MAX,
+ .step = 1,
+ .default_value = INDYCAM_GAMMA_DEFAULT,
+ .flags = 0,
+ .reserved = { 0, 0 },
+ }
+};
+
+#define VINO_SAA7191_V4L2_CONTROL_COUNT 2
+
+struct v4l2_queryctrl vino_saa7191_v4l2_controls[] = {
+ {
+ .id = V4L2_CID_HUE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Hue",
+ .minimum = SAA7191_HUE_MIN,
+ .maximum = SAA7191_HUE_MAX,
+ .step = 1,
+ .default_value = SAA7191_HUE_DEFAULT,
+ .flags = 0,
+ .reserved = { 0, 0 },
+ },{
+ .id = V4L2_CID_PRIVATE_BASE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "VTR Time Constant",
+ .minimum = SAA7191_VTRC_MIN,
+ .maximum = SAA7191_VTRC_MAX,
+ .step = 1,
+ .default_value = SAA7191_VTRC_DEFAULT,
+ .flags = 0,
+ .reserved = { 0, 0 },
+ }
+};
+
+/* VINO I2C bus functions */
unsigned i2c_vino_getctrl(void *data)
{
@@ -112,49 +638,49 @@ static struct i2c_algo_sgi_data i2c_sgi_vino_data =
*/
static int i2c_vino_client_reg(struct i2c_client *client)
{
- int res = 0;
+ int ret = 0;
- down(&Vino->input_lock);
+ spin_lock(&vino_drvdata->input_lock);
switch (client->driver->id) {
case I2C_DRIVERID_SAA7191:
- if (Vino->decoder.driver)
- res = -EBUSY;
+ if (vino_drvdata->decoder.driver)
+ ret = -EBUSY;
else
- Vino->decoder.driver = client;
+ vino_drvdata->decoder.driver = client;
break;
case I2C_DRIVERID_INDYCAM:
- if (Vino->camera.driver)
- res = -EBUSY;
+ if (vino_drvdata->camera.driver)
+ ret = -EBUSY;
else
- Vino->camera.driver = client;
+ vino_drvdata->camera.driver = client;
break;
default:
- res = -ENODEV;
+ ret = -ENODEV;
}
- up(&Vino->input_lock);
+ spin_unlock(&vino_drvdata->input_lock);
- return res;
+ return ret;
}
static int i2c_vino_client_unreg(struct i2c_client *client)
{
- int res = 0;
+ int ret = 0;
- down(&Vino->input_lock);
- if (client == Vino->decoder.driver) {
- if (Vino->decoder.owner)
- res = -EBUSY;
+ spin_lock(&vino_drvdata->input_lock);
+ if (client == vino_drvdata->decoder.driver) {
+ if (vino_drvdata->decoder.owner != VINO_NO_CHANNEL)
+ ret = -EBUSY;
else
- Vino->decoder.driver = NULL;
- } else if (client == Vino->camera.driver) {
- if (Vino->camera.owner)
- res = -EBUSY;
+ vino_drvdata->decoder.driver = NULL;
+ } else if (client == vino_drvdata->camera.driver) {
+ if (vino_drvdata->camera.owner != VINO_NO_CHANNEL)
+ ret = -EBUSY;
else
- Vino->camera.driver = NULL;
+ vino_drvdata->camera.driver = NULL;
}
- up(&Vino->input_lock);
+ spin_unlock(&vino_drvdata->input_lock);
- return res;
+ return ret;
}
static struct i2c_adapter vino_i2c_adapter =
@@ -176,172 +702,3591 @@ static int vino_i2c_del_bus(void)
return i2c_sgi_del_bus(&vino_i2c_adapter);
}
+static int i2c_camera_command(unsigned int cmd, void *arg)
+{
+ return vino_drvdata->camera.driver->
+ driver->command(vino_drvdata->camera.driver,
+ cmd, arg);
+}
+
+static int i2c_decoder_command(unsigned int cmd, void *arg)
+{
+ return vino_drvdata->decoder.driver->
+ driver->command(vino_drvdata->decoder.driver,
+ cmd, arg);
+}
+
+/* VINO framebuffer/DMA descriptor management */
+
+static void vino_free_buffer_with_count(struct vino_framebuffer *fb,
+ unsigned int count)
+{
+ unsigned int i;
+
+ dprintk("vino_free_buffer_with_count(): count = %d\n", count);
+
+ for (i = 0; i < count; i++) {
+ mem_map_unreserve(virt_to_page(fb->desc_table.virtual[i]));
+ dma_unmap_single(NULL,
+ fb->desc_table.dma_cpu[VINO_PAGE_RATIO * i],
+ PAGE_SIZE, DMA_FROM_DEVICE);
+ free_page(fb->desc_table.virtual[i]);
+ }
+
+ dma_free_coherent(NULL,
+ VINO_PAGE_RATIO * (fb->desc_table.page_count + 4) *
+ sizeof(dma_addr_t), (void *)fb->desc_table.dma_cpu,
+ fb->desc_table.dma);
+ kfree(fb->desc_table.virtual);
+
+ memset(fb, 0, sizeof(struct vino_framebuffer));
+}
+
+static void vino_free_buffer(struct vino_framebuffer *fb)
+{
+ vino_free_buffer_with_count(fb, fb->desc_table.page_count);
+}
+
+static int vino_allocate_buffer(struct vino_framebuffer *fb,
+ unsigned int size)
+{
+ unsigned int count, i, j;
+ int ret = 0;
+
+ dprintk("vino_allocate_buffer():\n");
+
+ if (size < 1)
+ return -EINVAL;
+
+ memset(fb, 0, sizeof(struct vino_framebuffer));
+
+ count = ((size / PAGE_SIZE) + 4) & ~3;
+
+ dprintk("vino_allocate_buffer(): size = %d, count = %d\n",
+ size, count);
+
+ /* allocate memory for table with virtual (page) addresses */
+ fb->desc_table.virtual = (unsigned long *)
+ kmalloc(count * sizeof(unsigned long), GFP_KERNEL);
+ if (!fb->desc_table.virtual)
+ return -ENOMEM;
+
+ /* allocate memory for table with dma addresses
+ * (has space for four extra descriptors) */
+ fb->desc_table.dma_cpu =
+ dma_alloc_coherent(NULL, VINO_PAGE_RATIO * (count + 4) *
+ sizeof(dma_addr_t), &fb->desc_table.dma,
+ GFP_KERNEL | GFP_DMA);
+ if (!fb->desc_table.dma_cpu) {
+ ret = -ENOMEM;
+ goto out_free_virtual;
+ }
+
+ /* allocate pages for the buffer and acquire the according
+ * dma addresses */
+ for (i = 0; i < count; i++) {
+ dma_addr_t dma_data_addr;
+
+ fb->desc_table.virtual[i] =
+ get_zeroed_page(GFP_KERNEL | GFP_DMA);
+ if (!fb->desc_table.virtual[i]) {
+ ret = -ENOBUFS;
+ break;
+ }
+
+ dma_data_addr =
+ dma_map_single(NULL,
+ (void *)fb->desc_table.virtual[i],
+ PAGE_SIZE, DMA_FROM_DEVICE);
+
+ for (j = 0; j < VINO_PAGE_RATIO; j++) {
+ fb->desc_table.dma_cpu[VINO_PAGE_RATIO * i + j] =
+ dma_data_addr + VINO_PAGE_SIZE * j;
+ }
+
+ mem_map_reserve(virt_to_page(fb->desc_table.virtual[i]));
+ }
+
+ /* page_count needs to be set anyway, because the descriptor table has
+ * been allocated according to this number */
+ fb->desc_table.page_count = count;
+
+ if (ret) {
+ /* the descriptor with index i doesn't contain
+ * a valid address yet */
+ vino_free_buffer_with_count(fb, i);
+ return ret;
+ }
+
+ //fb->size = size;
+ fb->size = count * PAGE_SIZE;
+ fb->data_format = VINO_DATA_FMT_NONE;
+
+ /* set the dma stop-bit for the last (count+1)th descriptor */
+ fb->desc_table.dma_cpu[VINO_PAGE_RATIO * count] = VINO_DESC_STOP;
+ return 0;
+
+ out_free_virtual:
+ kfree(fb->desc_table.virtual);
+ return ret;
+}
+
+#if 0
+/* user buffers not fully implemented yet */
+static int vino_prepare_user_buffer(struct vino_framebuffer *fb,
+ void *user,
+ unsigned int size)
+{
+ unsigned int count, i, j;
+ int ret = 0;
+
+ dprintk("vino_prepare_user_buffer():\n");
+
+ if (size < 1)
+ return -EINVAL;
+
+ memset(fb, 0, sizeof(struct vino_framebuffer));
+
+ count = ((size / PAGE_SIZE)) & ~3;
+
+ dprintk("vino_prepare_user_buffer(): size = %d, count = %d\n",
+ size, count);
+
+ /* allocate memory for table with virtual (page) addresses */
+ fb->desc_table.virtual = (unsigned long *)
+ kmalloc(count * sizeof(unsigned long), GFP_KERNEL);
+ if (!fb->desc_table.virtual)
+ return -ENOMEM;
+
+ /* allocate memory for table with dma addresses
+ * (has space for four extra descriptors) */
+ fb->desc_table.dma_cpu =
+ dma_alloc_coherent(NULL, VINO_PAGE_RATIO * (count + 4) *
+ sizeof(dma_addr_t), &fb->desc_table.dma,
+ GFP_KERNEL | GFP_DMA);
+ if (!fb->desc_table.dma_cpu) {
+ ret = -ENOMEM;
+ goto out_free_virtual;
+ }
+
+ /* allocate pages for the buffer and acquire the according
+ * dma addresses */
+ for (i = 0; i < count; i++) {
+ dma_addr_t dma_data_addr;
+
+ fb->desc_table.virtual[i] =
+ get_zeroed_page(GFP_KERNEL | GFP_DMA);
+ if (!fb->desc_table.virtual[i]) {
+ ret = -ENOBUFS;
+ break;
+ }
+
+ dma_data_addr =
+ dma_map_single(NULL,
+ (void *)fb->desc_table.virtual[i],
+ PAGE_SIZE, DMA_FROM_DEVICE);
+
+ for (j = 0; j < VINO_PAGE_RATIO; j++) {
+ fb->desc_table.dma_cpu[VINO_PAGE_RATIO * i + j] =
+ dma_data_addr + VINO_PAGE_SIZE * j;
+ }
+
+ mem_map_reserve(virt_to_page(fb->desc_table.virtual[i]));
+ }
+
+ /* page_count needs to be set anyway, because the descriptor table has
+ * been allocated according to this number */
+ fb->desc_table.page_count = count;
+
+ if (ret) {
+ /* the descriptor with index i doesn't contain
+ * a valid address yet */
+ vino_free_buffer_with_count(fb, i);
+ return ret;
+ }
+
+ //fb->size = size;
+ fb->size = count * PAGE_SIZE;
+
+ /* set the dma stop-bit for the last (count+1)th descriptor */
+ fb->desc_table.dma_cpu[VINO_PAGE_RATIO * count] = VINO_DESC_STOP;
+ return 0;
+
+ out_free_virtual:
+ kfree(fb->desc_table.virtual);
+ return ret;
+}
+#endif
+
+static void vino_sync_buffer(struct vino_framebuffer *fb)
+{
+ int i;
+
+ dprintk("vino_sync_buffer():\n");
+
+ for (i = 0; i < fb->desc_table.page_count; i++)
+ dma_sync_single(NULL,
+ fb->desc_table.dma_cpu[VINO_PAGE_RATIO * i],
+ PAGE_SIZE, DMA_FROM_DEVICE);
+}
+
+/* Framebuffer fifo functions (need to be locked externally) */
+
+static void vino_fifo_init(struct vino_framebuffer_fifo *f,
+ unsigned int length)
+{
+ f->length = 0;
+ f->used = 0;
+ f->head = 0;
+ f->tail = 0;
+
+ if (length > VINO_FRAMEBUFFER_MAX_COUNT)
+ length = VINO_FRAMEBUFFER_MAX_COUNT;
+
+ f->length = length;
+}
+
+/* returns true/false */
+static int vino_fifo_has_id(struct vino_framebuffer_fifo *f, unsigned int id)
+{
+ unsigned int i;
+ for (i = f->head; i == (f->tail - 1); i = (i + 1) % f->length) {
+ if (f->data[i] == id)
+ return 1;
+ }
+
+ return 0;
+}
+
+/* returns true/false */
+static int vino_fifo_full(struct vino_framebuffer_fifo *f)
+{
+ return (f->used == f->length);
+}
+
+static unsigned int vino_fifo_get_used(struct vino_framebuffer_fifo *f)
+{
+ return f->used;
+}
-static void vino_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static int vino_fifo_enqueue(struct vino_framebuffer_fifo *f, unsigned int id)
{
+ if (id >= f->length) {
+ return VINO_QUEUE_ERROR;
+ }
+
+ if (vino_fifo_has_id(f, id)) {
+ return VINO_QUEUE_ERROR;
+ }
+
+ if (f->used < f->length) {
+ f->data[f->tail] = id;
+ f->tail = (f->tail + 1) % f->length;
+ f->used++;
+ } else {
+ return VINO_QUEUE_ERROR;
+ }
+
+ return 0;
}
-static int vino_open(struct video_device *dev, int flags)
+static int vino_fifo_peek(struct vino_framebuffer_fifo *f, unsigned int *id)
{
- struct vino_device *videv = (struct vino_device *)dev;
+ if (f->used > 0) {
+ *id = f->data[f->head];
+ } else {
+ return VINO_QUEUE_ERROR;
+ }
return 0;
}
-static void vino_close(struct video_device *dev)
+static int vino_fifo_dequeue(struct vino_framebuffer_fifo *f, unsigned int *id)
{
- struct vino_device *videv = (struct vino_device *)dev;
+ if (f->used > 0) {
+ *id = f->data[f->head];
+ f->head = (f->head + 1) % f->length;
+ f->used--;
+ } else {
+ return VINO_QUEUE_ERROR;
+ }
+
+ return 0;
}
-static int vino_mmap(struct video_device *dev, const char *adr,
- unsigned long size)
+/* Framebuffer queue functions */
+
+/* execute with queue_lock locked */
+static void vino_queue_free_with_count(struct vino_framebuffer_queue *q,
+ unsigned int length)
{
- struct vino_device *videv = (struct vino_device *)dev;
+ unsigned int i;
- return -EINVAL;
+ q->length = 0;
+ memset(&q->in, 0, sizeof(struct vino_framebuffer_fifo));
+ memset(&q->out, 0, sizeof(struct vino_framebuffer_fifo));
+ for (i = 0; i < length; i++) {
+ dprintk("vino_queue_free_with_count(): freeing buffer %d\n",
+ i);
+ vino_free_buffer(q->buffer[i]);
+ kfree(q->buffer[i]);
+ }
+
+ q->type = VINO_MEMORY_NONE;
+ q->magic = 0;
}
-static int vino_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
+static void vino_queue_free(struct vino_framebuffer_queue *q)
{
- struct vino_device *videv = (struct vino_device *)dev;
+ dprintk("vino_queue_free():\n");
+
+ if (q->magic != VINO_QUEUE_MAGIC)
+ return;
+ if (q->type != VINO_MEMORY_MMAP)
+ return;
+
+ down(&q->queue_sem);
+
+ vino_queue_free_with_count(q, q->length);
+
+ up(&q->queue_sem);
+}
+
+static int vino_queue_init(struct vino_framebuffer_queue *q,
+ unsigned int *length)
+{
+ unsigned int i;
+ int ret = 0;
+
+ dprintk("vino_queue_init(): length = %d\n", *length);
+
+ if (q->magic == VINO_QUEUE_MAGIC) {
+ dprintk("vino_queue_init(): queue already initialized!\n");
+ return -EINVAL;
+ }
+
+ if (q->type != VINO_MEMORY_NONE) {
+ dprintk("vino_queue_init(): queue already initialized!\n");
+ return -EINVAL;
+ }
+
+ if (*length < 1)
+ return -EINVAL;
+
+ down(&q->queue_sem);
+
+ if (*length > VINO_FRAMEBUFFER_MAX_COUNT)
+ *length = VINO_FRAMEBUFFER_MAX_COUNT;
+
+ q->length = 0;
+
+ for (i = 0; i < *length; i++) {
+ dprintk("vino_queue_init(): allocating buffer %d\n", i);
+ q->buffer[i] = kmalloc(sizeof(struct vino_framebuffer),
+ GFP_KERNEL);
+ if (!q->buffer[i]) {
+ dprintk("vino_queue_init(): kmalloc() failed\n");
+ ret = -ENOMEM;
+ break;
+ }
+
+ ret = vino_allocate_buffer(q->buffer[i],
+ VINO_FRAMEBUFFER_SIZE);
+ if (ret) {
+ kfree(q->buffer[i]);
+ dprintk("vino_queue_init(): "
+ "vino_allocate_buffer() failed\n");
+ break;
+ }
+
+ q->buffer[i]->id = i;
+ if (i > 0) {
+ q->buffer[i]->offset = q->buffer[i - 1]->offset +
+ q->buffer[i - 1]->size;
+ } else {
+ q->buffer[i]->offset = 0;
+ }
+
+ spin_lock_init(&q->buffer[i]->state_lock);
+
+ dprintk("vino_queue_init(): buffer = %d, offset = %d, "
+ "size = %d\n", i, q->buffer[i]->offset,
+ q->buffer[i]->size);
+ }
+
+ if (ret) {
+ vino_queue_free_with_count(q, i);
+ *length = 0;
+ } else {
+ q->length = *length;
+ vino_fifo_init(&q->in, q->length);
+ vino_fifo_init(&q->out, q->length);
+ q->type = VINO_MEMORY_MMAP;
+ q->magic = VINO_QUEUE_MAGIC;
+ }
+
+ up(&q->queue_sem);
+
+ return ret;
+}
+
+static struct vino_framebuffer *vino_queue_add(struct
+ vino_framebuffer_queue *q,
+ unsigned int id)
+{
+ struct vino_framebuffer *ret = NULL;
+ unsigned int total;
+ unsigned long flags;
+
+ dprintk("vino_queue_add(): id = %d\n", id);
+
+ if (q->magic != VINO_QUEUE_MAGIC) {
+ return ret;
+ }
+
+ spin_lock_irqsave(&q->queue_lock, flags);
+
+ if (q->length == 0)
+ goto out;
+
+ if (id >= q->length)
+ goto out;
+
+ /* not needed?: if (vino_fifo_full(&q->out)) {
+ goto out;
+ }*/
+ /* check that outgoing queue isn't already full
+ * (or that it won't become full) */
+ total = vino_fifo_get_used(&q->in) +
+ vino_fifo_get_used(&q->out);
+ if (total >= q->length)
+ goto out;
+
+ if (vino_fifo_enqueue(&q->in, id))
+ goto out;
+
+ ret = q->buffer[id];
+
+out:
+ spin_unlock_irqrestore(&q->queue_lock, flags);
+
+ return ret;
+}
+
+static struct vino_framebuffer *vino_queue_transfer(struct
+ vino_framebuffer_queue *q)
+{
+ struct vino_framebuffer *ret = NULL;
+ struct vino_framebuffer *fb;
+ int id;
+ unsigned long flags;
+
+ dprintk("vino_queue_transfer():\n");
+
+ if (q->magic != VINO_QUEUE_MAGIC) {
+ return ret;
+ }
+
+ spin_lock_irqsave(&q->queue_lock, flags);
+
+ if (q->length == 0)
+ goto out;
+
+ // now this actually removes an entry from the incoming queue
+ if (vino_fifo_dequeue(&q->in, &id)) {
+ goto out;
+ }
+
+ dprintk("vino_queue_transfer(): id = %d\n", id);
+ fb = q->buffer[id];
+
+ // we have already checked that the outgoing queue is not full, but...
+ if (vino_fifo_enqueue(&q->out, id)) {
+ printk(KERN_ERR "vino_queue_transfer(): "
+ "outgoing queue is full, this shouldn't happen!\n");
+ goto out;
+ }
+
+ ret = fb;
+out:
+ spin_unlock_irqrestore(&q->queue_lock, flags);
+
+ return ret;
+}
+
+/* returns true/false */
+static int vino_queue_incoming_contains(struct vino_framebuffer_queue *q,
+ unsigned int id)
+{
+ int ret = 0;
+ unsigned long flags;
+
+ if (q->magic != VINO_QUEUE_MAGIC) {
+ return ret;
+ }
+
+ spin_lock_irqsave(&q->queue_lock, flags);
+
+ if (q->length == 0)
+ goto out;
+
+ ret = vino_fifo_has_id(&q->in, id);
+
+out:
+ spin_unlock_irqrestore(&q->queue_lock, flags);
+
+ return ret;
+}
+
+/* returns true/false */
+static int vino_queue_outgoing_contains(struct vino_framebuffer_queue *q,
+ unsigned int id)
+{
+ int ret = 0;
+ unsigned long flags;
+
+ if (q->magic != VINO_QUEUE_MAGIC) {
+ return ret;
+ }
+
+ spin_lock_irqsave(&q->queue_lock, flags);
+
+ if (q->length == 0)
+ goto out;
+
+ ret = vino_fifo_has_id(&q->out, id);
+
+out:
+ spin_unlock_irqrestore(&q->queue_lock, flags);
+
+ return ret;
+}
+
+static int vino_queue_get_incoming(struct vino_framebuffer_queue *q,
+ unsigned int *used)
+{
+ int ret = 0;
+ unsigned long flags;
+
+ if (q->magic != VINO_QUEUE_MAGIC) {
+ return VINO_QUEUE_ERROR;
+ }
+
+ spin_lock_irqsave(&q->queue_lock, flags);
+
+ if (q->length == 0) {
+ ret = VINO_QUEUE_ERROR;
+ goto out;
+ }
+
+ *used = vino_fifo_get_used(&q->in);
+
+out:
+ spin_unlock_irqrestore(&q->queue_lock, flags);
+
+ return ret;
+}
+
+static int vino_queue_get_outgoing(struct vino_framebuffer_queue *q,
+ unsigned int *used)
+{
+ int ret = 0;
+ unsigned long flags;
+
+ if (q->magic != VINO_QUEUE_MAGIC) {
+ return VINO_QUEUE_ERROR;
+ }
+
+ spin_lock_irqsave(&q->queue_lock, flags);
+
+ if (q->length == 0) {
+ ret = VINO_QUEUE_ERROR;
+ goto out;
+ }
+
+ *used = vino_fifo_get_used(&q->out);
+
+out:
+ spin_unlock_irqrestore(&q->queue_lock, flags);
+
+ return ret;
+}
+
+static int vino_queue_get_total(struct vino_framebuffer_queue *q,
+ unsigned int *total)
+{
+ int ret = 0;
+ unsigned long flags;
+
+ if (q->magic != VINO_QUEUE_MAGIC) {
+ return VINO_QUEUE_ERROR;
+ }
+
+ spin_lock_irqsave(&q->queue_lock, flags);
+
+ if (q->length == 0) {
+ ret = VINO_QUEUE_ERROR;
+ goto out;
+ }
+
+ *total = vino_fifo_get_used(&q->in) +
+ vino_fifo_get_used(&q->out);
+
+out:
+ spin_unlock_irqrestore(&q->queue_lock, flags);
+
+ return ret;
+}
+
+static struct vino_framebuffer *vino_queue_peek(struct
+ vino_framebuffer_queue *q,
+ unsigned int *id)
+{
+ struct vino_framebuffer *ret = NULL;
+ unsigned long flags;
+
+ if (q->magic != VINO_QUEUE_MAGIC) {
+ return ret;
+ }
+
+ spin_lock_irqsave(&q->queue_lock, flags);
+
+ if (q->length == 0)
+ goto out;
+
+ if (vino_fifo_peek(&q->in, id)) {
+ goto out;
+ }
+
+ ret = q->buffer[*id];
+out:
+ spin_unlock_irqrestore(&q->queue_lock, flags);
+
+ return ret;
+}
+
+static struct vino_framebuffer *vino_queue_remove(struct
+ vino_framebuffer_queue *q,
+ unsigned int *id)
+{
+ struct vino_framebuffer *ret = NULL;
+ unsigned long flags;
+ dprintk("vino_queue_remove():\n");
+
+ if (q->magic != VINO_QUEUE_MAGIC) {
+ return ret;
+ }
+
+ spin_lock_irqsave(&q->queue_lock, flags);
+
+ if (q->length == 0)
+ goto out;
+
+ if (vino_fifo_dequeue(&q->out, id)) {
+ goto out;
+ }
+
+ dprintk("vino_queue_remove(): id = %d\n", *id);
+ ret = q->buffer[*id];
+out:
+ spin_unlock_irqrestore(&q->queue_lock, flags);
+
+ return ret;
+}
+
+static struct
+vino_framebuffer *vino_queue_get_buffer(struct vino_framebuffer_queue *q,
+ unsigned int id)
+{
+ struct vino_framebuffer *ret = NULL;
+ unsigned long flags;
+
+ if (q->magic != VINO_QUEUE_MAGIC) {
+ return ret;
+ }
+
+ spin_lock_irqsave(&q->queue_lock, flags);
+
+ if (q->length == 0)
+ goto out;
+
+ if (id >= q->length)
+ goto out;
+
+ ret = q->buffer[id];
+ out:
+ spin_unlock_irqrestore(&q->queue_lock, flags);
+
+ return ret;
+}
+
+static unsigned int vino_queue_get_length(struct vino_framebuffer_queue *q)
+{
+ unsigned int length = 0;
+ unsigned long flags;
+
+ if (q->magic != VINO_QUEUE_MAGIC) {
+ return length;
+ }
+
+ spin_lock_irqsave(&q->queue_lock, flags);
+ length = q->length;
+ spin_unlock_irqrestore(&q->queue_lock, flags);
+
+ return length;
+}
+
+static int vino_queue_has_mapped_buffers(struct vino_framebuffer_queue *q)
+{
+ unsigned int i;
+ int ret = 0;
+ unsigned long flags;
+
+ if (q->magic != VINO_QUEUE_MAGIC) {
+ return ret;
+ }
+
+ spin_lock_irqsave(&q->queue_lock, flags);
+ for (i = 0; i < q->length; i++) {
+ if (q->buffer[i]->map_count > 0) {
+ ret = 1;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&q->queue_lock, flags);
+
+ return ret;
+}
+
+/* VINO functions */
+
+/* execute with input_lock locked */
+static void vino_update_line_size(struct vino_channel_settings *vcs)
+{
+ unsigned int w = vcs->clipping.right - vcs->clipping.left;
+ unsigned int d = vcs->decimation;
+ unsigned int bpp = vino_data_formats[vcs->data_format].bpp;
+ unsigned int lsize;
+
+ dprintk("update_line_size(): before: w = %d, d = %d, "
+ "line_size = %d\n", w, d, vcs->line_size);
+ /* line size must be multiple of 8 bytes */
+ lsize = (bpp * (w / d)) & ~7;
+ w = (lsize / bpp) * d;
+
+ vcs->clipping.right = vcs->clipping.left + w;
+ vcs->line_size = lsize;
+ dprintk("update_line_size(): after: w = %d, d = %d, "
+ "line_size = %d\n", w, d, vcs->line_size);
+}
+
+/* execute with input_lock locked */
+static void vino_set_clipping(struct vino_channel_settings *vcs,
+ unsigned int x, unsigned int y,
+ unsigned int w, unsigned int h)
+{
+ unsigned int maxwidth, maxheight;
+ unsigned int d;
+
+ maxwidth = vino_data_norms[vcs->data_norm].width;
+ maxheight = vino_data_norms[vcs->data_norm].height;
+ d = vcs->decimation;
+
+ y &= ~1; /* odd/even fields */
+
+ if (x > maxwidth) {
+ x = 0;
+ }
+ if (y > maxheight) {
+ y = 0;
+ }
+
+ if (((w / d) < VINO_MIN_WIDTH)
+ || ((h / d) < VINO_MIN_HEIGHT)) {
+ w = VINO_MIN_WIDTH * d;
+ h = VINO_MIN_HEIGHT * d;
+ }
+
+ if ((x + w) > maxwidth) {
+ w = maxwidth - x;
+ if ((w / d) < VINO_MIN_WIDTH)
+ x = maxwidth - VINO_MIN_WIDTH * d;
+ }
+ if ((y + h) > maxheight) {
+ h = maxheight - y;
+ if ((h / d) < VINO_MIN_HEIGHT)
+ y = maxheight - VINO_MIN_HEIGHT * d;
+ }
+
+ vcs->clipping.left = x;
+ vcs->clipping.top = y;
+ vcs->clipping.right = x + w;
+ vcs->clipping.bottom = y + h;
+
+ vino_update_line_size(vcs);
+
+ dprintk("clipping %d, %d, %d, %d / %d - %d\n",
+ vcs->clipping.left, vcs->clipping.top, vcs->clipping.right,
+ vcs->clipping.bottom, vcs->decimation, vcs->line_size);
+}
+
+/* execute with input_lock locked */
+static void vino_set_default_clipping(struct vino_channel_settings *vcs)
+{
+ vino_set_clipping(vcs, 0, 0, vino_data_norms[vcs->data_norm].width,
+ vino_data_norms[vcs->data_norm].height);
+}
+
+/* execute with input_lock locked */
+static void vino_set_scaling(struct vino_channel_settings *vcs,
+ unsigned int w, unsigned int h)
+{
+ unsigned int x, y, curw, curh, d;
+
+ x = vcs->clipping.left;
+ y = vcs->clipping.top;
+ curw = vcs->clipping.right - vcs->clipping.left;
+ curh = vcs->clipping.bottom - vcs->clipping.top;
+
+ d = max(curw / w, curh / h);
+
+ dprintk("scaling w: %d, h: %d, curw: %d, curh: %d, d: %d\n",
+ w, h, curw, curh, d);
+
+ if (d < 1) {
+ d = 1;
+ }
+ if (d > 8) {
+ d = 8;
+ }
+
+ vcs->decimation = d;
+ vino_set_clipping(vcs, x, y, w * d, h * d);
+
+ dprintk("scaling %d, %d, %d, %d / %d - %d\n", vcs->clipping.left,
+ vcs->clipping.top, vcs->clipping.right, vcs->clipping.bottom,
+ vcs->decimation, vcs->line_size);
+}
+
+/* execute with input_lock locked */
+static void vino_reset_scaling(struct vino_channel_settings *vcs)
+{
+ vino_set_scaling(vcs, vcs->clipping.right - vcs->clipping.left,
+ vcs->clipping.bottom - vcs->clipping.top);
+}
+
+/* execute with input_lock locked */
+static void vino_set_framerate(struct vino_channel_settings *vcs,
+ unsigned int fps)
+{
+ unsigned int mask;
+
+ switch (vcs->data_norm) {
+ case VINO_DATA_NORM_NTSC:
+ case VINO_DATA_NORM_D1:
+ fps = (unsigned int)(fps / 6) * 6; // FIXME: round!
+
+ if (fps < vino_data_norms[vcs->data_norm].fps_min)
+ fps = vino_data_norms[vcs->data_norm].fps_min;
+ if (fps > vino_data_norms[vcs->data_norm].fps_max)
+ fps = vino_data_norms[vcs->data_norm].fps_max;
+
+ switch (fps) {
+ case 6:
+ mask = 0x003;
+ break;
+ case 12:
+ mask = 0x0c3;
+ break;
+ case 18:
+ mask = 0x333;
+ break;
+ case 24:
+ mask = 0x3ff;
+ break;
+ case 30:
+ mask = 0xfff;
+ break;
+ default:
+ mask = VINO_FRAMERT_FULL;
+ }
+ vcs->framert_reg = VINO_FRAMERT_RT(mask);
+ break;
+ case VINO_DATA_NORM_PAL:
+ case VINO_DATA_NORM_SECAM:
+ fps = (unsigned int)(fps / 5) * 5; // FIXME: round!
+
+ if (fps < vino_data_norms[vcs->data_norm].fps_min)
+ fps = vino_data_norms[vcs->data_norm].fps_min;
+ if (fps > vino_data_norms[vcs->data_norm].fps_max)
+ fps = vino_data_norms[vcs->data_norm].fps_max;
+
+ switch (fps) {
+ case 5:
+ mask = 0x003;
+ break;
+ case 10:
+ mask = 0x0c3;
+ break;
+ case 15:
+ mask = 0x333;
+ break;
+ case 20:
+ mask = 0x0ff;
+ break;
+ case 25:
+ mask = 0x3ff;
+ break;
+ default:
+ mask = VINO_FRAMERT_FULL;
+ }
+ vcs->framert_reg = VINO_FRAMERT_RT(mask) | VINO_FRAMERT_PAL;
+ break;
+ }
+
+ vcs->fps = fps;
+}
+
+/* execute with input_lock locked */
+static void vino_set_default_framerate(struct vino_channel_settings *vcs)
+{
+ vino_set_framerate(vcs, vino_data_norms[vcs->data_norm].fps_max);
+}
+
+/*
+ * Prepare VINO for DMA transfer...
+ * (execute only with vino_lock and input_lock locked)
+ */
+static int vino_dma_setup(struct vino_channel_settings *vcs,
+ struct vino_framebuffer *fb)
+{
+ u32 ctrl, intr;
+ struct sgi_vino_channel *ch;
+ const struct vino_data_norm *norm;
+
+ dprintk("vino_dma_setup():\n");
+
+ vcs->field = 0;
+ fb->frame_counter = 0;
+
+ ch = (vcs->channel == VINO_CHANNEL_A) ? &vino->a : &vino->b;
+ norm = &vino_data_norms[vcs->data_norm];
+
+ ch->page_index = 0;
+ ch->line_count = 0;
+
+ /* VINO line size register is set 8 bytes less than actual */
+ ch->line_size = vcs->line_size - 8;
+
+ /* let VINO know where to transfer data */
+ ch->start_desc_tbl = fb->desc_table.dma;
+ ch->next_4_desc = fb->desc_table.dma;
+
+ /* give vino time to fetch the first four descriptors, 5 usec
+ * should be more than enough time */
+ udelay(VINO_DESC_FETCH_DELAY);
+
+ /* set the alpha register */
+ ch->alpha = vcs->alpha;
+
+ /* set clipping registers */
+ ch->clip_start = VINO_CLIP_ODD(norm->odd.top + vcs->clipping.top / 2) |
+ VINO_CLIP_EVEN(norm->even.top +
+ vcs->clipping.top / 2) |
+ VINO_CLIP_X(vcs->clipping.left);
+ ch->clip_end = VINO_CLIP_ODD(norm->odd.top +
+ vcs->clipping.bottom / 2 - 1) |
+ VINO_CLIP_EVEN(norm->even.top +
+ vcs->clipping.bottom / 2 - 1) |
+ VINO_CLIP_X(vcs->clipping.right);
+ /* FIXME: end-of-field bug workaround
+ VINO_CLIP_X(VINO_PAL_WIDTH);
+ */
+
+ /* set the size of actual content in the buffer (DECIMATION !) */
+ fb->data_size = ((vcs->clipping.right - vcs->clipping.left) /
+ vcs->decimation) *
+ ((vcs->clipping.bottom - vcs->clipping.top) /
+ vcs->decimation) *
+ vino_data_formats[vcs->data_format].bpp;
+
+ ch->frame_rate = vcs->framert_reg;
+
+ ctrl = vino->control;
+ intr = vino->intr_status;
+
+ if (vcs->channel == VINO_CHANNEL_A) {
+ /* All interrupt conditions for this channel was cleared
+ * so clear the interrupt status register and enable
+ * interrupts */
+ intr &= ~VINO_INTSTAT_A;
+ ctrl |= VINO_CTRL_A_INT;
+
+ /* enable synchronization */
+ ctrl |= VINO_CTRL_A_SYNC_ENBL;
+
+ /* enable frame assembly */
+ ctrl |= VINO_CTRL_A_INTERLEAVE_ENBL;
+
+ /* set decimation used */
+ if (vcs->decimation < 2)
+ ctrl &= ~VINO_CTRL_A_DEC_ENBL;
+ else {
+ ctrl |= VINO_CTRL_A_DEC_ENBL;
+ ctrl &= ~VINO_CTRL_A_DEC_SCALE_MASK;
+ ctrl |= (vcs->decimation - 1) <<
+ VINO_CTRL_A_DEC_SCALE_SHIFT;
+ }
+
+ /* select input interface */
+ if (vcs->input == VINO_INPUT_D1)
+ ctrl |= VINO_CTRL_A_SELECT;
+ else
+ ctrl &= ~VINO_CTRL_A_SELECT;
+
+ /* palette */
+ ctrl &= ~(VINO_CTRL_A_LUMA_ONLY | VINO_CTRL_A_RGB |
+ VINO_CTRL_A_DITHER);
+ } else {
+ intr &= ~VINO_INTSTAT_B;
+ ctrl |= VINO_CTRL_B_INT;
+
+ ctrl |= VINO_CTRL_B_SYNC_ENBL;
+ ctrl |= VINO_CTRL_B_INTERLEAVE_ENBL;
+
+ if (vcs->decimation < 2)
+ ctrl &= ~VINO_CTRL_B_DEC_ENBL;
+ else {
+ ctrl |= VINO_CTRL_B_DEC_ENBL;
+ ctrl &= ~VINO_CTRL_B_DEC_SCALE_MASK;
+ ctrl |= (vcs->decimation - 1) <<
+ VINO_CTRL_B_DEC_SCALE_SHIFT;
+
+ }
+ if (vcs->input == VINO_INPUT_D1)
+ ctrl |= VINO_CTRL_B_SELECT;
+ else
+ ctrl &= ~VINO_CTRL_B_SELECT;
+
+ ctrl &= ~(VINO_CTRL_B_LUMA_ONLY | VINO_CTRL_B_RGB |
+ VINO_CTRL_B_DITHER);
+ }
+
+ /* set palette */
+ fb->data_format = vcs->data_format;
+
+ switch (vcs->data_format) {
+ case VINO_DATA_FMT_GREY:
+ ctrl |= (vcs->channel == VINO_CHANNEL_A) ?
+ VINO_CTRL_A_LUMA_ONLY : VINO_CTRL_B_LUMA_ONLY;
+ break;
+ case VINO_DATA_FMT_RGB32:
+ ctrl |= (vcs->channel == VINO_CHANNEL_A) ?
+ VINO_CTRL_A_RGB : VINO_CTRL_B_RGB;
+ break;
+ case VINO_DATA_FMT_YUV:
+ /* nothing needs to be done */
+ break;
+ case VINO_DATA_FMT_RGB332:
+ ctrl |= (vcs->channel == VINO_CHANNEL_A) ?
+ VINO_CTRL_A_RGB | VINO_CTRL_A_DITHER :
+ VINO_CTRL_B_RGB | VINO_CTRL_B_DITHER;
+ break;
+ }
+
+ vino->intr_status = intr;
+ vino->control = ctrl;
+
+ return 0;
+}
+
+/* (execute only with vino_lock locked) */
+static void vino_dma_start(struct vino_channel_settings *vcs)
+{
+ u32 ctrl = vino->control;
+
+ dprintk("vino_dma_start():\n");
+ ctrl |= (vcs->channel == VINO_CHANNEL_A) ?
+ VINO_CTRL_A_DMA_ENBL : VINO_CTRL_B_DMA_ENBL;
+ vino->control = ctrl;
+}
+
+/* (execute only with vino_lock locked) */
+static void vino_dma_stop(struct vino_channel_settings *vcs)
+{
+ u32 ctrl = vino->control;
+
+ ctrl &= (vcs->channel == VINO_CHANNEL_A) ?
+ ~VINO_CTRL_A_DMA_ENBL : ~VINO_CTRL_B_DMA_ENBL;
+ vino->control = ctrl;
+ dprintk("vino_dma_stop():\n");
+}
+
+/*
+ * Load dummy page to descriptor registers. This prevents generating of
+ * spurious interrupts. (execute only with vino_lock locked)
+ */
+static void vino_clear_interrupt(struct vino_channel_settings *vcs)
+{
+ struct sgi_vino_channel *ch;
+
+ ch = (vcs->channel == VINO_CHANNEL_A) ? &vino->a : &vino->b;
+
+ ch->page_index = 0;
+ ch->line_count = 0;
+
+ ch->start_desc_tbl = vino_drvdata->dummy_desc_table.dma;
+ ch->next_4_desc = vino_drvdata->dummy_desc_table.dma;
+
+ udelay(VINO_DESC_FETCH_DELAY);
+ dprintk("channel %c clear interrupt condition\n",
+ (vcs->channel == VINO_CHANNEL_A) ? 'A':'B');
+}
+
+static int vino_capture(struct vino_channel_settings *vcs,
+ struct vino_framebuffer *fb)
+{
+ int err = 0;
+ unsigned long flags, flags2;
+
+ spin_lock_irqsave(&fb->state_lock, flags);
+
+ if (fb->state == VINO_FRAMEBUFFER_IN_USE)
+ err = -EBUSY;
+ fb->state = VINO_FRAMEBUFFER_IN_USE;
+
+ spin_unlock_irqrestore(&fb->state_lock, flags);
+
+ if (err)
+ return err;
+
+ spin_lock_irqsave(&vino_drvdata->vino_lock, flags);
+ spin_lock_irqsave(&vino_drvdata->input_lock, flags2);
+
+ vino_dma_setup(vcs, fb);
+ vino_dma_start(vcs);
+
+ spin_unlock_irqrestore(&vino_drvdata->input_lock, flags2);
+ spin_unlock_irqrestore(&vino_drvdata->vino_lock, flags);
+
+ return err;
+}
+
+static
+struct vino_framebuffer *vino_capture_enqueue(struct
+ vino_channel_settings *vcs,
+ unsigned int index)
+{
+ struct vino_framebuffer *fb;
+ unsigned long flags;
+
+ dprintk("vino_capture_enqueue():\n");
+
+ spin_lock_irqsave(&vcs->capture_lock, flags);
+
+ fb = vino_queue_add(&vcs->fb_queue, index);
+ if (fb == NULL) {
+ dprintk("vino_capture_enqueue(): vino_queue_add() failed, "
+ "queue full?\n");
+ goto out;
+ }
+out:
+ spin_unlock_irqrestore(&vcs->capture_lock, flags);
+
+ return fb;
+}
+
+static int vino_capture_next(struct vino_channel_settings *vcs, int start)
+{
+ struct vino_framebuffer *fb;
+ unsigned int incoming, id;
+ int err = 0;
+ unsigned long flags, flags2;
+
+ dprintk("vino_capture_next():\n");
+
+ spin_lock_irqsave(&vcs->capture_lock, flags);
+
+ if (start) {
+ /* start capture only if capture isn't in progress already */
+ if (vcs->capturing) {
+ spin_unlock_irqrestore(&vcs->capture_lock, flags);
+ return 0;
+ }
+
+ } else {
+ /* capture next frame:
+ * stop capture if capturing is not set */
+ if (!vcs->capturing) {
+ spin_unlock_irqrestore(&vcs->capture_lock, flags);
+ return 0;
+ }
+ }
+
+ err = vino_queue_get_incoming(&vcs->fb_queue, &incoming);
+ if (err) {
+ dprintk("vino_capture_next(): vino_queue_get_incoming() "
+ "failed\n");
+ err = -EINVAL;
+ goto out;
+ }
+ if (incoming == 0) {
+ dprintk("vino_capture_next(): no buffers available\n");
+ goto out;
+ }
+
+ fb = vino_queue_peek(&vcs->fb_queue, &id);
+ if (fb == NULL) {
+ dprintk("vino_capture_next(): vino_queue_peek() failed\n");
+ err = -EINVAL;
+ goto out;
+ }
+
+ spin_lock_irqsave(&fb->state_lock, flags2);
+ fb->state = VINO_FRAMEBUFFER_UNUSED;
+ spin_unlock_irqrestore(&fb->state_lock, flags2);
+
+ if (start) {
+ vcs->capturing = 1;
+ }
+
+ spin_unlock_irqrestore(&vcs->capture_lock, flags);
+
+ err = vino_capture(vcs, fb);
+
+ return err;
+
+out:
+ vcs->capturing = 0;
+ spin_unlock_irqrestore(&vcs->capture_lock, flags);
+
+ return err;
+}
+
+static int vino_is_capturing(struct vino_channel_settings *vcs)
+{
+ int ret;
+ unsigned long flags;
+
+ spin_lock_irqsave(&vcs->capture_lock, flags);
+
+ ret = vcs->capturing;
+
+ spin_unlock_irqrestore(&vcs->capture_lock, flags);
+
+ return ret;
+}
+
+/* waits until a frame is captured */
+static int vino_wait_for_frame(struct vino_channel_settings *vcs)
+{
+ wait_queue_t wait;
+ int err = 0;
+
+ dprintk("vino_wait_for_frame():\n");
+
+ init_waitqueue_entry(&wait, current);
+ /* add ourselves into wait queue */
+ add_wait_queue(&vcs->fb_queue.frame_wait_queue, &wait);
+ /* and set current state */
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ /* to ensure that schedule_timeout will return immediately
+ * if VINO interrupt was triggred meanwhile */
+ schedule_timeout(HZ / 10);
+
+ if (signal_pending(current))
+ err = -EINTR;
+
+ remove_wait_queue(&vcs->fb_queue.frame_wait_queue, &wait);
+
+ dprintk("vino_wait_for_frame(): waiting for frame %s\n",
+ err ? "failed" : "ok");
+
+ return err;
+}
+
+/* the function assumes that PAGE_SIZE % 4 == 0 */
+static void vino_convert_to_rgba(struct vino_framebuffer *fb) {
+ unsigned char *pageptr;
+ unsigned int page, i;
+ unsigned char a;
+
+ for (page = 0; page < fb->desc_table.page_count; page++) {
+ pageptr = (unsigned char *)fb->desc_table.virtual[page];
+
+ for (i = 0; i < PAGE_SIZE; i += 4) {
+ a = pageptr[0];
+ pageptr[0] = pageptr[3];
+ pageptr[1] = pageptr[2];
+ pageptr[2] = pageptr[1];
+ pageptr[3] = a;
+ pageptr += 4;
+ }
+ }
+}
+
+/* checks if the buffer is in correct state and syncs data */
+static int vino_check_buffer(struct vino_channel_settings *vcs,
+ struct vino_framebuffer *fb)
+{
+ int err = 0;
+ unsigned long flags;
+
+ dprintk("vino_check_buffer():\n");
+
+ spin_lock_irqsave(&fb->state_lock, flags);
+ switch (fb->state) {
+ case VINO_FRAMEBUFFER_IN_USE:
+ err = -EIO;
+ break;
+ case VINO_FRAMEBUFFER_READY:
+ vino_sync_buffer(fb);
+ fb->state = VINO_FRAMEBUFFER_UNUSED;
+ break;
+ default:
+ err = -EINVAL;
+ }
+ spin_unlock_irqrestore(&fb->state_lock, flags);
+
+ if (!err) {
+ if (vino_pixel_conversion
+ && (fb->data_format == VINO_DATA_FMT_RGB32)) {
+ vino_convert_to_rgba(fb);
+ }
+ } else if (err && (err != -EINVAL)) {
+ dprintk("vino_check_buffer(): buffer not ready\n");
+
+ spin_lock_irqsave(&vino_drvdata->vino_lock, flags);
+ vino_dma_stop(vcs);
+ vino_clear_interrupt(vcs);
+ spin_unlock_irqrestore(&vino_drvdata->vino_lock, flags);
+ }
+
+ return err;
+}
+
+/* forcefully terminates capture */
+static void vino_capture_stop(struct vino_channel_settings *vcs)
+{
+ unsigned int incoming = 0, outgoing = 0, id;
+ unsigned long flags, flags2;
+
+ dprintk("vino_capture_stop():\n");
+
+ spin_lock_irqsave(&vcs->capture_lock, flags);
+ /* unset capturing to stop queue processing */
+ vcs->capturing = 0;
+
+ spin_lock_irqsave(&vino_drvdata->vino_lock, flags2);
+
+ vino_dma_stop(vcs);
+ vino_clear_interrupt(vcs);
+
+ spin_unlock_irqrestore(&vino_drvdata->vino_lock, flags2);
+
+ /* remove all items from the queue */
+ if (vino_queue_get_incoming(&vcs->fb_queue, &incoming)) {
+ dprintk("vino_capture_stop(): "
+ "vino_queue_get_incoming() failed\n");
+ goto out;
+ }
+ while (incoming > 0) {
+ vino_queue_transfer(&vcs->fb_queue);
+
+ if (vino_queue_get_incoming(&vcs->fb_queue, &incoming)) {
+ dprintk("vino_capture_stop(): "
+ "vino_queue_get_incoming() failed\n");
+ goto out;
+ }
+ }
+
+ if (vino_queue_get_outgoing(&vcs->fb_queue, &outgoing)) {
+ dprintk("vino_capture_stop(): "
+ "vino_queue_get_outgoing() failed\n");
+ goto out;
+ }
+ while (outgoing > 0) {
+ vino_queue_remove(&vcs->fb_queue, &id);
+
+ if (vino_queue_get_outgoing(&vcs->fb_queue, &outgoing)) {
+ dprintk("vino_capture_stop(): "
+ "vino_queue_get_outgoing() failed\n");
+ goto out;
+ }
+ }
+
+out:
+ spin_unlock_irqrestore(&vcs->capture_lock, flags);
+}
+
+static int vino_capture_failed(struct vino_channel_settings *vcs)
+{
+ struct vino_framebuffer *fb;
+ unsigned long flags;
+ unsigned int i;
+ int ret;
+
+ dprintk("vino_capture_failed():\n");
+
+ spin_lock_irqsave(&vino_drvdata->vino_lock, flags);
+
+ vino_dma_stop(vcs);
+ vino_clear_interrupt(vcs);
+
+ spin_unlock_irqrestore(&vino_drvdata->vino_lock, flags);
+
+ ret = vino_queue_get_incoming(&vcs->fb_queue, &i);
+ if (ret == VINO_QUEUE_ERROR) {
+ dprintk("vino_queue_get_incoming() failed\n");
+ return -EINVAL;
+ }
+ if (i == 0) {
+ /* no buffers to process */
+ return 0;
+ }
+
+ fb = vino_queue_peek(&vcs->fb_queue, &i);
+ if (fb == NULL) {
+ dprintk("vino_queue_peek() failed\n");
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&fb->state_lock, flags);
+ if (fb->state == VINO_FRAMEBUFFER_IN_USE) {
+ fb->state = VINO_FRAMEBUFFER_UNUSED;
+ vino_queue_transfer(&vcs->fb_queue);
+ vino_queue_remove(&vcs->fb_queue, &i);
+ /* we should actually discard the newest frame,
+ * but who cares ... */
+ }
+ spin_unlock_irqrestore(&fb->state_lock, flags);
+
+ return 0;
+}
+
+static void vino_frame_done(struct vino_channel_settings *vcs,
+ unsigned int fc)
+{
+ struct vino_framebuffer *fb;
+ unsigned long flags;
+
+ spin_lock_irqsave(&vcs->capture_lock, flags);
+ fb = vino_queue_transfer(&vcs->fb_queue);
+ if (!fb) {
+ spin_unlock_irqrestore(&vcs->capture_lock, flags);
+ dprintk("vino_frame_done(): vino_queue_transfer() failed!\n");
+ return;
+ }
+ spin_unlock_irqrestore(&vcs->capture_lock, flags);
+
+ fb->frame_counter = fc;
+ do_gettimeofday(&fb->timestamp);
+
+ spin_lock_irqsave(&fb->state_lock, flags);
+ if (fb->state == VINO_FRAMEBUFFER_IN_USE)
+ fb->state = VINO_FRAMEBUFFER_READY;
+ spin_unlock_irqrestore(&fb->state_lock, flags);
+
+ wake_up(&vcs->fb_queue.frame_wait_queue);
+
+ vino_capture_next(vcs, 0);
+}
+
+static irqreturn_t vino_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ u32 intr;
+ unsigned int fc_a, fc_b;
+ int done_a = 0;
+ int done_b = 0;
+
+ spin_lock(&vino_drvdata->vino_lock);
+
+ intr = vino->intr_status;
+ fc_a = vino->a.field_counter / 2;
+ fc_b = vino->b.field_counter / 2;
+
+ // TODO: handle error-interrupts in some special way ?
+
+ if (intr & VINO_INTSTAT_A) {
+ if (intr & VINO_INTSTAT_A_EOF) {
+ vino_drvdata->a.field++;
+ if (vino_drvdata->a.field > 1) {
+ vino_dma_stop(&vino_drvdata->a);
+ vino_clear_interrupt(&vino_drvdata->a);
+ vino_drvdata->a.field = 0;
+ done_a = 1;
+ }
+ dprintk("intr: channel A end-of-field interrupt: "
+ "%04x\n", intr);
+ } else {
+ vino_dma_stop(&vino_drvdata->a);
+ vino_clear_interrupt(&vino_drvdata->a);
+ done_a = 1;
+ dprintk("channel A error interrupt: %04x\n", intr);
+ }
+ }
+ if (intr & VINO_INTSTAT_B) {
+ if (intr & VINO_INTSTAT_B_EOF) {
+ vino_drvdata->b.field++;
+ if (vino_drvdata->b.field > 1) {
+ vino_dma_stop(&vino_drvdata->b);
+ vino_clear_interrupt(&vino_drvdata->b);
+ vino_drvdata->b.field = 0;
+ done_b = 1;
+ }
+ dprintk("intr: channel B end-of-field interrupt: "
+ "%04x\n", intr);
+ } else {
+ vino_dma_stop(&vino_drvdata->b);
+ vino_clear_interrupt(&vino_drvdata->b);
+ done_b = 1;
+ dprintk("channel B error interrupt: %04x\n", intr);
+ }
+ }
+
+ /* always remember to clear interrupt status */
+ vino->intr_status = ~intr;
+
+ spin_unlock(&vino_drvdata->vino_lock);
+
+ if (done_a) {
+ vino_frame_done(&vino_drvdata->a, fc_a);
+ dprintk("channel A frame done, interrupt: %d\n", intr);
+ }
+ if (done_b) {
+ vino_frame_done(&vino_drvdata->b, fc_b);
+ dprintk("channel B frame done, interrupt: %d\n", intr);
+ }
- return -EINVAL;
+ return IRQ_HANDLED;
}
-static const struct video_device vino_device = {
+/* VINO video input management */
+
+static int vino_get_saa7191_input(int input)
+{
+ switch (input) {
+ case VINO_INPUT_COMPOSITE:
+ return SAA7191_INPUT_COMPOSITE;
+ case VINO_INPUT_SVIDEO:
+ return SAA7191_INPUT_SVIDEO;
+ default:
+ printk(KERN_ERR "VINO: vino_get_saa7191_input(): "
+ "invalid input!\n");
+ return -1;
+ }
+}
+
+static int vino_get_saa7191_norm(int norm)
+{
+ switch (norm) {
+ case VINO_DATA_NORM_AUTO:
+ return SAA7191_NORM_AUTO;
+ case VINO_DATA_NORM_PAL:
+ return SAA7191_NORM_PAL;
+ case VINO_DATA_NORM_NTSC:
+ return SAA7191_NORM_NTSC;
+ case VINO_DATA_NORM_SECAM:
+ return SAA7191_NORM_SECAM;
+ default:
+ printk(KERN_ERR "VINO: vino_get_saa7191_norm(): "
+ "invalid norm!\n");
+ return -1;
+ }
+}
+
+/* execute with input_lock locked */
+static int vino_is_input_owner(struct vino_channel_settings *vcs)
+{
+ switch(vcs->input) {
+ case VINO_INPUT_COMPOSITE:
+ case VINO_INPUT_SVIDEO:
+ return (vino_drvdata->decoder.owner == vcs->channel);
+ case VINO_INPUT_D1:
+ return (vino_drvdata->camera.owner == vcs->channel);
+ default:
+ return 0;
+ }
+}
+
+static int vino_acquire_input(struct vino_channel_settings *vcs)
+{
+ int ret = 0;
+
+ dprintk("vino_acquire_input():\n");
+
+ spin_lock(&vino_drvdata->input_lock);
+
+ /* First try D1 and then SAA7191 */
+ if (vino_drvdata->camera.driver
+ && (vino_drvdata->camera.owner == VINO_NO_CHANNEL)) {
+ if (i2c_use_client(vino_drvdata->camera.driver)) {
+ ret = -ENODEV;
+ goto out;
+ }
+
+ vino_drvdata->camera.owner = vcs->channel;
+ vcs->input = VINO_INPUT_D1;
+ vcs->data_norm = VINO_DATA_NORM_D1;
+ } else if (vino_drvdata->decoder.driver
+ && (vino_drvdata->decoder.owner == VINO_NO_CHANNEL)) {
+ int saa7191_input;
+ int saa7191_norm;
+
+ if (i2c_use_client(vino_drvdata->decoder.driver)) {
+ ret = -ENODEV;
+ goto out;
+ }
+
+ vino_drvdata->decoder.owner = vcs->channel;
+ vcs->input = VINO_INPUT_COMPOSITE;
+ vcs->data_norm = VINO_DATA_NORM_PAL;
+
+ saa7191_input = vino_get_saa7191_input(vcs->input);
+ i2c_decoder_command(DECODER_SET_INPUT, &saa7191_input);
+
+ saa7191_norm = vino_get_saa7191_norm(vcs->data_norm);
+ i2c_decoder_command(DECODER_SAA7191_SET_NORM, &saa7191_norm);
+ } else {
+ vcs->input = (vcs->channel == VINO_CHANNEL_A) ?
+ vino_drvdata->b.input : vino_drvdata->a.input;
+ vcs->data_norm = (vcs->channel == VINO_CHANNEL_A) ?
+ vino_drvdata->b.data_norm : vino_drvdata->a.data_norm;
+ }
+
+ if (vcs->input == VINO_INPUT_NONE) {
+ ret = -ENODEV;
+ goto out;
+ }
+
+ if (vino_is_input_owner(vcs)) {
+ vino_set_default_clipping(vcs);
+ vino_set_default_framerate(vcs);
+ }
+
+ dprintk("vino_acquire_input(): %s\n", vino_inputs[vcs->input].name);
+
+out:
+ spin_unlock(&vino_drvdata->input_lock);
+
+ return ret;
+}
+
+static int vino_set_input(struct vino_channel_settings *vcs, int input)
+{
+ struct vino_channel_settings *vcs2 = (vcs->channel == VINO_CHANNEL_A) ?
+ &vino_drvdata->b : &vino_drvdata->a;
+ int ret = 0;
+
+ dprintk("vino_set_input():\n");
+
+ spin_lock(&vino_drvdata->input_lock);
+
+ if (vcs->input == input)
+ goto out;
+
+ switch(input) {
+ case VINO_INPUT_COMPOSITE:
+ case VINO_INPUT_SVIDEO:
+ if (!vino_drvdata->decoder.driver) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (vino_drvdata->decoder.owner == VINO_NO_CHANNEL) {
+ if (i2c_use_client(vino_drvdata->decoder.driver)) {
+ ret = -ENODEV;
+ goto out;
+ }
+ vino_drvdata->decoder.owner = vcs->channel;
+ }
+
+ if (vino_drvdata->decoder.owner == vcs->channel) {
+ int saa7191_input;
+ int saa7191_norm;
+
+ vcs->input = input;
+ vcs->data_norm = VINO_DATA_NORM_PAL;
+
+ saa7191_input = vino_get_saa7191_input(vcs->input);
+ i2c_decoder_command(DECODER_SET_INPUT, &saa7191_input);
+ saa7191_norm = vino_get_saa7191_norm(vcs->data_norm);
+ i2c_decoder_command(DECODER_SAA7191_SET_NORM,
+ &saa7191_norm);
+ } else {
+ if (vcs2->input != input) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ vcs->input = input;
+ vcs->data_norm = vcs2->data_norm;
+ }
+
+ if (vino_drvdata->camera.owner == vcs->channel) {
+ /* Transfer the ownership or release the input */
+ if (vcs2->input == VINO_INPUT_D1) {
+ vino_drvdata->camera.owner = vcs2->channel;
+ } else {
+ i2c_release_client(vino_drvdata->
+ camera.driver);
+ vino_drvdata->camera.owner = VINO_NO_CHANNEL;
+ }
+ }
+ break;
+ case VINO_INPUT_D1:
+ if (!vino_drvdata->camera.driver) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (vino_drvdata->camera.owner == VINO_NO_CHANNEL) {
+ if (i2c_use_client(vino_drvdata->camera.driver)) {
+ ret = -ENODEV;
+ goto out;
+ }
+ vino_drvdata->camera.owner = vcs->channel;
+ }
+
+ if (vino_drvdata->decoder.owner == vcs->channel) {
+ /* Transfer the ownership or release the input */
+ if ((vcs2->input == VINO_INPUT_COMPOSITE) ||
+ (vcs2->input == VINO_INPUT_SVIDEO)) {
+ vino_drvdata->decoder.owner = vcs2->channel;
+ } else {
+ i2c_release_client(vino_drvdata->
+ decoder.driver);
+ vino_drvdata->decoder.owner = VINO_NO_CHANNEL;
+ }
+ }
+
+ vcs->input = input;
+ vcs->data_norm = VINO_DATA_NORM_D1;
+ break;
+ default:
+ ret = -EINVAL;
+ goto out;
+ }
+
+ vino_set_default_clipping(vcs);
+ vino_set_default_framerate(vcs);
+
+ dprintk("vino_set_input(): %s\n", vino_inputs[vcs->input].name);
+
+out:
+ spin_unlock(&vino_drvdata->input_lock);
+
+ return ret;
+}
+
+static void vino_release_input(struct vino_channel_settings *vcs)
+{
+ struct vino_channel_settings *vcs2 = (vcs->channel == VINO_CHANNEL_A) ?
+ &vino_drvdata->b : &vino_drvdata->a;
+
+ dprintk("vino_release_input():\n");
+
+ spin_lock(&vino_drvdata->input_lock);
+
+ /* Release ownership of the channel
+ * and if the other channel takes input from
+ * the same source, transfer the ownership */
+ if (vino_drvdata->camera.owner == vcs->channel) {
+ if (vcs2->input == VINO_INPUT_D1) {
+ vino_drvdata->camera.owner = vcs2->channel;
+ } else {
+ i2c_release_client(vino_drvdata->camera.driver);
+ vino_drvdata->camera.owner = VINO_NO_CHANNEL;
+ }
+ } else if (vino_drvdata->decoder.owner == vcs->channel) {
+ if ((vcs2->input == VINO_INPUT_COMPOSITE) ||
+ (vcs2->input == VINO_INPUT_SVIDEO)) {
+ vino_drvdata->decoder.owner = vcs2->channel;
+ } else {
+ i2c_release_client(vino_drvdata->decoder.driver);
+ vino_drvdata->decoder.owner = VINO_NO_CHANNEL;
+ }
+ }
+ vcs->input = VINO_INPUT_NONE;
+
+ spin_unlock(&vino_drvdata->input_lock);
+}
+
+/* execute with input_lock locked */
+static int vino_set_data_norm(struct vino_channel_settings *vcs,
+ unsigned int data_norm)
+{
+ int saa7191_norm;
+
+ switch (vcs->input) {
+ case VINO_INPUT_D1:
+ /* only one "norm" supported */
+ if (data_norm != VINO_DATA_NORM_D1)
+ return -EINVAL;
+ break;
+ case VINO_INPUT_COMPOSITE:
+ case VINO_INPUT_SVIDEO:
+
+ saa7191_norm = vino_get_saa7191_norm(data_norm);
+
+ i2c_decoder_command(DECODER_SAA7191_SET_NORM, &saa7191_norm);
+ vcs->data_norm = data_norm;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* V4L2 helper functions */
+
+static int vino_find_data_format(__u32 pixelformat)
+{
+ int i;
+
+ for (i = 0; i < VINO_DATA_FMT_COUNT; i++) {
+ if (vino_data_formats[i].pixelformat == pixelformat)
+ return i;
+ }
+
+ return VINO_DATA_FMT_NONE;
+}
+
+static int vino_enum_data_norm(struct vino_channel_settings *vcs, __u32 index)
+{
+ int data_norm = VINO_DATA_NORM_NONE;
+
+ spin_lock(&vino_drvdata->input_lock);
+ switch(vcs->input) {
+ case VINO_INPUT_COMPOSITE:
+ case VINO_INPUT_SVIDEO:
+ if (index == 0) {
+ data_norm = VINO_DATA_NORM_PAL;
+ } else if (index == 1) {
+ data_norm = VINO_DATA_NORM_NTSC;
+ } else if (index == 2) {
+ data_norm = VINO_DATA_NORM_SECAM;
+ }
+ break;
+ case VINO_INPUT_D1:
+ if (index == 0) {
+ data_norm = VINO_DATA_NORM_D1;
+ }
+ break;
+ }
+ spin_unlock(&vino_drvdata->input_lock);
+
+ return data_norm;
+}
+
+static int vino_enum_input(struct vino_channel_settings *vcs, __u32 index)
+{
+ int input = VINO_INPUT_NONE;
+
+ spin_lock(&vino_drvdata->input_lock);
+ if (vino_drvdata->decoder.driver && vino_drvdata->camera.driver) {
+ switch (index) {
+ case 0:
+ input = VINO_INPUT_COMPOSITE;
+ break;
+ case 1:
+ input = VINO_INPUT_SVIDEO;
+ break;
+ case 2:
+ input = VINO_INPUT_D1;
+ break;
+ }
+ } else if (vino_drvdata->decoder.driver) {
+ switch (index) {
+ case 0:
+ input = VINO_INPUT_COMPOSITE;
+ break;
+ case 1:
+ input = VINO_INPUT_SVIDEO;
+ break;
+ }
+ } else if (vino_drvdata->camera.driver) {
+ switch (index) {
+ case 0:
+ input = VINO_INPUT_D1;
+ break;
+ }
+ }
+ spin_unlock(&vino_drvdata->input_lock);
+
+ return input;
+}
+
+/* execute with input_lock locked */
+static __u32 vino_find_input_index(struct vino_channel_settings *vcs)
+{
+ __u32 index = 0;
+ // FIXME: detect when no inputs available
+
+ if (vino_drvdata->decoder.driver && vino_drvdata->camera.driver) {
+ switch (vcs->input) {
+ case VINO_INPUT_COMPOSITE:
+ index = 0;
+ break;
+ case VINO_INPUT_SVIDEO:
+ index = 1;
+ break;
+ case VINO_INPUT_D1:
+ index = 2;
+ break;
+ }
+ } else if (vino_drvdata->decoder.driver) {
+ switch (vcs->input) {
+ case VINO_INPUT_COMPOSITE:
+ index = 0;
+ break;
+ case VINO_INPUT_SVIDEO:
+ index = 1;
+ break;
+ }
+ } else if (vino_drvdata->camera.driver) {
+ switch (vcs->input) {
+ case VINO_INPUT_D1:
+ index = 0;
+ break;
+ }
+ }
+
+ return index;
+}
+
+/* V4L2 ioctls */
+
+static void vino_v4l2_querycap(struct v4l2_capability *cap)
+{
+ memset(cap, 0, sizeof(struct v4l2_capability));
+
+ strcpy(cap->driver, vino_driver_name);
+ strcpy(cap->card, vino_driver_description);
+ strcpy(cap->bus_info, vino_bus_name);
+ cap->version = VINO_VERSION_CODE;
+ cap->capabilities =
+ V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_STREAMING;
+ // V4L2_CAP_OVERLAY, V4L2_CAP_READWRITE
+}
+
+static int vino_v4l2_enuminput(struct vino_channel_settings *vcs,
+ struct v4l2_input *i)
+{
+ __u32 index = i->index;
+ int input;
+ dprintk("requested index = %d\n", index);
+
+ input = vino_enum_input(vcs, index);
+ if (input == VINO_INPUT_NONE)
+ return -EINVAL;
+
+ memset(i, 0, sizeof(struct v4l2_input));
+
+ i->index = index;
+ i->type = V4L2_INPUT_TYPE_CAMERA;
+ i->std = vino_inputs[input].std;
+ strcpy(i->name, vino_inputs[input].name);
+
+ if ((input == VINO_INPUT_COMPOSITE)
+ || (input == VINO_INPUT_SVIDEO)) {
+ struct saa7191_status status;
+ i2c_decoder_command(DECODER_SAA7191_GET_STATUS, &status);
+ i->status |= status.signal ? 0 : V4L2_IN_ST_NO_SIGNAL;
+ i->status |= status.color ? 0 : V4L2_IN_ST_NO_COLOR;
+ }
+
+ return 0;
+}
+
+static int vino_v4l2_g_input(struct vino_channel_settings *vcs,
+ struct v4l2_input *i)
+{
+ __u32 index;
+ int input;
+
+ spin_lock(&vino_drvdata->input_lock);
+ input = vcs->input;
+ index = vino_find_input_index(vcs);
+ spin_unlock(&vino_drvdata->input_lock);
+
+ dprintk("input = %d\n", input);
+
+ if (input == VINO_INPUT_NONE) {
+ return -EINVAL;
+ }
+
+ memset(i, 0, sizeof(struct v4l2_input));
+
+ i->index = index;
+ i->type = V4L2_INPUT_TYPE_CAMERA;
+ i->std = vino_inputs[input].std;
+ strcpy(i->name, vino_inputs[input].name);
+
+ return 0;
+}
+
+static int vino_v4l2_s_input(struct vino_channel_settings *vcs,
+ struct v4l2_input *i)
+{
+ int input;
+ dprintk("requested input = %d\n", i->index);
+
+ input = vino_enum_input(vcs, i->index);
+ if (input == VINO_INPUT_NONE)
+ return -EINVAL;
+
+ return vino_set_input(vcs, input);
+}
+
+static int vino_v4l2_enumstd(struct vino_channel_settings *vcs,
+ struct v4l2_standard *s)
+{
+ int index = s->index;
+ int data_norm = vino_enum_data_norm(vcs, index);
+ dprintk("standard index = %d\n", index);
+
+ if (data_norm == VINO_DATA_NORM_NONE)
+ return -EINVAL;
+
+ dprintk("standard name = %s\n",
+ vino_data_norms[data_norm].description);
+
+ memset(s, 0, sizeof(struct v4l2_standard));
+ s->index = index;
+
+ s->id = vino_data_norms[data_norm].std;
+ s->frameperiod.numerator = 1;
+ s->frameperiod.denominator =
+ vino_data_norms[data_norm].fps_max;
+ s->framelines =
+ vino_data_norms[data_norm].framelines;
+ strcpy(s->name,
+ vino_data_norms[data_norm].description);
+
+ return 0;
+}
+
+static int vino_v4l2_g_std(struct vino_channel_settings *vcs,
+ v4l2_std_id *std)
+{
+ spin_lock(&vino_drvdata->input_lock);
+ dprintk("current standard = %d\n", vcs->data_norm);
+ *std = vino_data_norms[vcs->data_norm].std;
+ spin_unlock(&vino_drvdata->input_lock);
+
+ return 0;
+}
+
+static int vino_v4l2_s_std(struct vino_channel_settings *vcs,
+ v4l2_std_id *std)
+{
+ int ret = 0;
+
+ spin_lock(&vino_drvdata->input_lock);
+
+ /* check if the standard is valid for the current input */
+ if (vino_is_input_owner(vcs)
+ && (vino_inputs[vcs->input].std & (*std))) {
+ dprintk("standard accepted\n");
+
+ /* change the video norm for SAA7191
+ * and accept NTSC for D1 (do nothing) */
+
+ if (vcs->input == VINO_INPUT_D1)
+ goto out;
+
+ if ((*std) & V4L2_STD_PAL) {
+ vino_set_data_norm(vcs, VINO_DATA_NORM_PAL);
+ vcs->data_norm = VINO_DATA_NORM_PAL;
+ } else if ((*std) & V4L2_STD_NTSC) {
+ vino_set_data_norm(vcs, VINO_DATA_NORM_NTSC);
+ vcs->data_norm = VINO_DATA_NORM_NTSC;
+ } else if ((*std) & V4L2_STD_SECAM) {
+ vino_set_data_norm(vcs, VINO_DATA_NORM_SECAM);
+ vcs->data_norm = VINO_DATA_NORM_SECAM;
+ } else {
+ ret = -EINVAL;
+ }
+ } else {
+ ret = -EINVAL;
+ }
+
+out:
+ spin_unlock(&vino_drvdata->input_lock);
+
+ return ret;
+}
+
+static int vino_v4l2_enum_fmt(struct vino_channel_settings *vcs,
+ struct v4l2_fmtdesc *fd)
+{
+ enum v4l2_buf_type type = fd->type;
+ int index = fd->index;
+ dprintk("format index = %d\n", index);
+
+ switch (fd->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ if ((fd->index < 0) ||
+ (fd->index >= VINO_DATA_FMT_COUNT))
+ return -EINVAL;
+ dprintk("format name = %s\n",
+ vino_data_formats[index].description);
+
+ memset(fd, 0, sizeof(struct v4l2_fmtdesc));
+ fd->index = index;
+ fd->type = type;
+ fd->pixelformat = vino_data_formats[index].pixelformat;
+ strcpy(fd->description, vino_data_formats[index].description);
+ break;
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int vino_v4l2_try_fmt(struct vino_channel_settings *vcs,
+ struct v4l2_format *f)
+{
+ struct vino_channel_settings tempvcs;
+
+ switch (f->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
+ struct v4l2_pix_format *pf = &f->fmt.pix;
+
+ dprintk("requested: w = %d, h = %d\n",
+ pf->width, pf->height);
+
+ spin_lock(&vino_drvdata->input_lock);
+ memcpy(&tempvcs, vcs, sizeof(struct vino_channel_settings));
+ spin_unlock(&vino_drvdata->input_lock);
+
+ tempvcs.data_format = vino_find_data_format(pf->pixelformat);
+ if (tempvcs.data_format == VINO_DATA_FMT_NONE) {
+ tempvcs.data_format = VINO_DATA_FMT_RGB32;
+ pf->pixelformat =
+ vino_data_formats[tempvcs.data_format].
+ pixelformat;
+ }
+
+ /* data format must be set before clipping/scaling */
+ vino_set_scaling(&tempvcs, pf->width, pf->height);
+
+ dprintk("data format = %s\n",
+ vino_data_formats[tempvcs.data_format].description);
+
+ pf->width = (tempvcs.clipping.right - tempvcs.clipping.left) /
+ tempvcs.decimation;
+ pf->height = (tempvcs.clipping.bottom - tempvcs.clipping.top) /
+ tempvcs.decimation;
+
+ pf->field = V4L2_FIELD_INTERLACED;
+ pf->bytesperline = tempvcs.line_size;
+ pf->sizeimage = tempvcs.line_size *
+ (tempvcs.clipping.bottom - tempvcs.clipping.top) /
+ tempvcs.decimation;
+ pf->colorspace =
+ vino_data_formats[tempvcs.data_format].colorspace;
+
+ pf->priv = 0;
+ break;
+ }
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int vino_v4l2_g_fmt(struct vino_channel_settings *vcs,
+ struct v4l2_format *f)
+{
+ switch (f->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
+ struct v4l2_pix_format *pf = &f->fmt.pix;
+ spin_lock(&vino_drvdata->input_lock);
+
+ pf->width = (vcs->clipping.right - vcs->clipping.left) /
+ vcs->decimation;
+ pf->height = (vcs->clipping.bottom - vcs->clipping.top) /
+ vcs->decimation;
+ pf->pixelformat =
+ vino_data_formats[vcs->data_format].pixelformat;
+
+ pf->field = V4L2_FIELD_INTERLACED;
+ pf->bytesperline = vcs->line_size;
+ pf->sizeimage = vcs->line_size *
+ (vcs->clipping.bottom - vcs->clipping.top) /
+ vcs->decimation;
+ pf->colorspace =
+ vino_data_formats[vcs->data_format].colorspace;
+
+ pf->priv = 0;
+
+ spin_unlock(&vino_drvdata->input_lock);
+ break;
+ }
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int vino_v4l2_s_fmt(struct vino_channel_settings *vcs,
+ struct v4l2_format *f)
+{
+ int data_format;
+
+ switch (f->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
+ struct v4l2_pix_format *pf = &f->fmt.pix;
+ spin_lock(&vino_drvdata->input_lock);
+
+ if (!vino_is_input_owner(vcs)) {
+ spin_unlock(&vino_drvdata->input_lock);
+ return -EINVAL;
+ }
+
+ data_format = vino_find_data_format(pf->pixelformat);
+ if (data_format == VINO_DATA_FMT_NONE) {
+ vcs->data_format = VINO_DATA_FMT_RGB32;
+ pf->pixelformat =
+ vino_data_formats[vcs->data_format].
+ pixelformat;
+ } else {
+ vcs->data_format = data_format;
+ }
+
+ /* data format must be set before clipping/scaling */
+ vino_set_scaling(vcs, pf->width, pf->height);
+
+ dprintk("data format = %s\n",
+ vino_data_formats[vcs->data_format].description);
+
+ pf->width = vcs->clipping.right - vcs->clipping.left;
+ pf->height = vcs->clipping.bottom - vcs->clipping.top;
+
+ pf->field = V4L2_FIELD_INTERLACED;
+ pf->bytesperline = vcs->line_size;
+ pf->sizeimage = vcs->line_size *
+ (vcs->clipping.bottom - vcs->clipping.top) /
+ vcs->decimation;
+ pf->colorspace =
+ vino_data_formats[vcs->data_format].colorspace;
+
+ pf->priv = 0;
+
+ spin_unlock(&vino_drvdata->input_lock);
+ break;
+ }
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int vino_v4l2_cropcap(struct vino_channel_settings *vcs,
+ struct v4l2_cropcap *ccap)
+{
+ const struct vino_data_norm *norm;
+
+ switch (ccap->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ spin_lock(&vino_drvdata->input_lock);
+ norm = &vino_data_norms[vcs->data_norm];
+ spin_unlock(&vino_drvdata->input_lock);
+
+ ccap->bounds.left = 0;
+ ccap->bounds.top = 0;
+ ccap->bounds.width = norm->width;
+ ccap->bounds.height = norm->height;
+ memcpy(&ccap->defrect, &ccap->bounds,
+ sizeof(struct v4l2_rect));
+
+ ccap->pixelaspect.numerator = 1;
+ ccap->pixelaspect.denominator = 1;
+ break;
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int vino_v4l2_g_crop(struct vino_channel_settings *vcs,
+ struct v4l2_crop *c)
+{
+ switch (c->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ spin_lock(&vino_drvdata->input_lock);
+
+ c->c.left = vcs->clipping.left;
+ c->c.top = vcs->clipping.top;
+ c->c.width = vcs->clipping.right - vcs->clipping.left;
+ c->c.height = vcs->clipping.bottom - vcs->clipping.top;
+
+ spin_unlock(&vino_drvdata->input_lock);
+ break;
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int vino_v4l2_s_crop(struct vino_channel_settings *vcs,
+ struct v4l2_crop *c)
+{
+ switch (c->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ spin_lock(&vino_drvdata->input_lock);
+
+ if (!vino_is_input_owner(vcs)) {
+ spin_unlock(&vino_drvdata->input_lock);
+ return -EINVAL;
+ }
+ vino_set_clipping(vcs, c->c.left, c->c.top,
+ c->c.width, c->c.height);
+
+ spin_unlock(&vino_drvdata->input_lock);
+ break;
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int vino_v4l2_g_parm(struct vino_channel_settings *vcs,
+ struct v4l2_streamparm *sp)
+{
+ switch (sp->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
+ struct v4l2_captureparm *cp = &sp->parm.capture;
+ memset(cp, 0, sizeof(struct v4l2_captureparm));
+
+ cp->capability = V4L2_CAP_TIMEPERFRAME;
+ cp->timeperframe.numerator = 1;
+
+ spin_lock(&vino_drvdata->input_lock);
+ cp->timeperframe.denominator = vcs->fps;
+ spin_unlock(&vino_drvdata->input_lock);
+
+ // TODO: cp->readbuffers = xxx;
+ break;
+ }
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int vino_v4l2_s_parm(struct vino_channel_settings *vcs,
+ struct v4l2_streamparm *sp)
+{
+ switch (sp->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
+ struct v4l2_captureparm *cp = &sp->parm.capture;
+
+ spin_lock(&vino_drvdata->input_lock);
+ if (!vino_is_input_owner(vcs)) {
+ spin_unlock(&vino_drvdata->input_lock);
+ return -EINVAL;
+ }
+
+ if ((cp->timeperframe.numerator == 0) ||
+ (cp->timeperframe.denominator == 0)) {
+ /* reset framerate */
+ vino_set_default_framerate(vcs);
+ } else {
+ vino_set_framerate(vcs, cp->timeperframe.denominator /
+ cp->timeperframe.numerator);
+ }
+ spin_unlock(&vino_drvdata->input_lock);
+
+ // TODO: set buffers according to cp->readbuffers
+ break;
+ }
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int vino_v4l2_reqbufs(struct vino_channel_settings *vcs,
+ struct v4l2_requestbuffers *rb)
+{
+ if (vcs->reading)
+ return -EBUSY;
+
+ switch (rb->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
+ // TODO: check queue type
+ if (rb->memory != V4L2_MEMORY_MMAP) {
+ dprintk("type not mmap\n");
+ return -EINVAL;
+ }
+
+ if (vino_is_capturing(vcs)) {
+ dprintk("busy, capturing\n");
+ return -EBUSY;
+ }
+
+ dprintk("count = %d\n", rb->count);
+ if (rb->count > 0) {
+ if (vino_queue_has_mapped_buffers(&vcs->fb_queue)) {
+ dprintk("busy, buffers still mapped\n");
+ return -EBUSY;
+ } else {
+ vino_queue_free(&vcs->fb_queue);
+ vino_queue_init(&vcs->fb_queue, &rb->count);
+ }
+ } else {
+ vino_capture_stop(vcs);
+ vino_queue_free(&vcs->fb_queue);
+ }
+ break;
+ }
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void vino_v4l2_get_buffer_status(struct vino_channel_settings *vcs,
+ struct vino_framebuffer *fb,
+ struct v4l2_buffer *b)
+{
+ if (vino_queue_outgoing_contains(&vcs->fb_queue,
+ fb->id)) {
+ b->flags &= ~V4L2_BUF_FLAG_QUEUED;
+ b->flags |= V4L2_BUF_FLAG_DONE;
+ } else if (vino_queue_incoming_contains(&vcs->fb_queue,
+ fb->id)) {
+ b->flags &= ~V4L2_BUF_FLAG_DONE;
+ b->flags |= V4L2_BUF_FLAG_QUEUED;
+ } else {
+ b->flags &= ~(V4L2_BUF_FLAG_DONE |
+ V4L2_BUF_FLAG_QUEUED);
+ }
+
+ b->flags &= ~(V4L2_BUF_FLAG_TIMECODE);
+
+ if (fb->map_count > 0)
+ b->flags |= V4L2_BUF_FLAG_MAPPED;
+
+ b->index = fb->id;
+ b->memory = (vcs->fb_queue.type == VINO_MEMORY_MMAP) ?
+ V4L2_MEMORY_MMAP : V4L2_MEMORY_USERPTR;
+ b->m.offset = fb->offset;
+ b->bytesused = fb->data_size;
+ b->length = fb->size;
+ b->field = V4L2_FIELD_INTERLACED;
+ b->sequence = fb->frame_counter;
+ memcpy(&b->timestamp, &fb->timestamp,
+ sizeof(struct timeval));
+ // b->input ?
+
+ dprintk("buffer %d: length = %d, bytesused = %d, offset = %d\n",
+ fb->id, fb->size, fb->data_size, fb->offset);
+}
+
+static int vino_v4l2_querybuf(struct vino_channel_settings *vcs,
+ struct v4l2_buffer *b)
+{
+ if (vcs->reading)
+ return -EBUSY;
+
+ switch (b->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
+ struct vino_framebuffer *fb;
+
+ // TODO: check queue type
+ if (b->index >= vino_queue_get_length(&vcs->fb_queue)) {
+ dprintk("invalid index = %d\n",
+ b->index);
+ return -EINVAL;
+ }
+
+ fb = vino_queue_get_buffer(&vcs->fb_queue,
+ b->index);
+ if (fb == NULL) {
+ dprintk("vino_queue_get_buffer() failed");
+ return -EINVAL;
+ }
+
+ vino_v4l2_get_buffer_status(vcs, fb, b);
+ break;
+ }
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int vino_v4l2_qbuf(struct vino_channel_settings *vcs,
+ struct v4l2_buffer *b)
+{
+ if (vcs->reading)
+ return -EBUSY;
+
+ switch (b->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
+ struct vino_framebuffer *fb;
+ int ret;
+
+ // TODO: check queue type
+ if (b->memory != V4L2_MEMORY_MMAP) {
+ dprintk("type not mmap\n");
+ return -EINVAL;
+ }
+
+ fb = vino_capture_enqueue(vcs, b->index);
+ if (fb == NULL)
+ return -EINVAL;
+
+ vino_v4l2_get_buffer_status(vcs, fb, b);
+
+ if (vcs->streaming) {
+ ret = vino_capture_next(vcs, 1);
+ if (ret)
+ return ret;
+ }
+ break;
+ }
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int vino_v4l2_dqbuf(struct vino_channel_settings *vcs,
+ struct v4l2_buffer *b,
+ unsigned int nonblocking)
+{
+ if (vcs->reading)
+ return -EBUSY;
+
+ switch (b->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
+ struct vino_framebuffer *fb;
+ unsigned int incoming, outgoing;
+ int err;
+
+ // TODO: check queue type
+
+ err = vino_queue_get_incoming(&vcs->fb_queue, &incoming);
+ if (err) {
+ dprintk("vino_queue_get_incoming() failed\n");
+ return -EIO;
+ }
+ err = vino_queue_get_outgoing(&vcs->fb_queue, &outgoing);
+ if (err) {
+ dprintk("vino_queue_get_outgoing() failed\n");
+ return -EIO;
+ }
+
+ dprintk("incoming = %d, outgoing = %d\n", incoming, outgoing);
+
+ if (outgoing == 0) {
+ if (incoming == 0) {
+ dprintk("no incoming or outgoing buffers\n");
+ return -EINVAL;
+ }
+ if (nonblocking) {
+ dprintk("non-blocking I/O was selected and "
+ "there are no buffers to dequeue\n");
+ return -EAGAIN;
+ }
+
+ err = vino_wait_for_frame(vcs);
+ if (err) {
+ err = vino_wait_for_frame(vcs);
+ if (err) {
+ /* interrupted */
+ vino_capture_failed(vcs);
+ return -EIO;
+ }
+ }
+ }
+
+ fb = vino_queue_remove(&vcs->fb_queue, &b->index);
+ if (fb == NULL) {
+ dprintk("vino_queue_remove() failed\n");
+ return -EINVAL;
+ }
+
+ err = vino_check_buffer(vcs, fb);
+ if (err)
+ return -EIO;
+
+ vino_v4l2_get_buffer_status(vcs, fb, b);
+ break;
+ }
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int vino_v4l2_streamon(struct vino_channel_settings *vcs)
+{
+ unsigned int incoming;
+ int ret;
+ if (vcs->reading)
+ return -EBUSY;
+
+ if (vcs->streaming)
+ return 0;
+
+ // TODO: check queue type
+
+ if (vino_queue_get_length(&vcs->fb_queue) < 1) {
+ dprintk("no buffers allocated\n");
+ return -EINVAL;
+ }
+
+ ret = vino_queue_get_incoming(&vcs->fb_queue, &incoming);
+ if (ret) {
+ dprintk("vino_queue_get_incoming() failed\n");
+ return -EINVAL;
+ }
+
+ vcs->streaming = 1;
+
+ if (incoming > 0) {
+ ret = vino_capture_next(vcs, 1);
+ if (ret) {
+ vcs->streaming = 0;
+
+ dprintk("couldn't start capture\n");
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static int vino_v4l2_streamoff(struct vino_channel_settings *vcs)
+{
+ if (vcs->reading)
+ return -EBUSY;
+
+ if (!vcs->streaming)
+ return 0;
+
+ vino_capture_stop(vcs);
+ vcs->streaming = 0;
+
+ return 0;
+}
+
+static int vino_v4l2_queryctrl(struct vino_channel_settings *vcs,
+ struct v4l2_queryctrl *queryctrl)
+{
+ int i;
+ int err = 0;
+
+ spin_lock(&vino_drvdata->input_lock);
+
+ switch (vcs->input) {
+ case VINO_INPUT_D1:
+ for (i = 0; i < VINO_INDYCAM_V4L2_CONTROL_COUNT; i++) {
+ if (vino_indycam_v4l2_controls[i].id ==
+ queryctrl->id) {
+ memcpy(queryctrl,
+ &vino_indycam_v4l2_controls[i],
+ sizeof(struct v4l2_queryctrl));
+ goto found;
+ }
+ }
+
+ err = -EINVAL;
+ break;
+ case VINO_INPUT_COMPOSITE:
+ case VINO_INPUT_SVIDEO:
+ for (i = 0; i < VINO_SAA7191_V4L2_CONTROL_COUNT; i++) {
+ if (vino_saa7191_v4l2_controls[i].id ==
+ queryctrl->id) {
+ memcpy(queryctrl,
+ &vino_saa7191_v4l2_controls[i],
+ sizeof(struct v4l2_queryctrl));
+ goto found;
+ }
+ }
+
+ err = -EINVAL;
+ break;
+ default:
+ err = -EINVAL;
+ }
+
+ found:
+ spin_unlock(&vino_drvdata->input_lock);
+
+ return err;
+}
+
+static int vino_v4l2_g_ctrl(struct vino_channel_settings *vcs,
+ struct v4l2_control *control)
+{
+ struct indycam_control indycam_ctrl;
+ struct saa7191_control saa7191_ctrl;
+ int err = 0;
+
+ spin_lock(&vino_drvdata->input_lock);
+
+ switch (vcs->input) {
+ case VINO_INPUT_D1:
+ i2c_camera_command(DECODER_INDYCAM_GET_CONTROLS,
+ &indycam_ctrl);
+
+ switch(control->id) {
+ case V4L2_CID_AUTOGAIN:
+ control->value = indycam_ctrl.agc;
+ break;
+ case V4L2_CID_AUTO_WHITE_BALANCE:
+ control->value = indycam_ctrl.awb;
+ break;
+ case V4L2_CID_GAIN:
+ control->value = indycam_ctrl.gain;
+ break;
+ case V4L2_CID_PRIVATE_BASE:
+ control->value = indycam_ctrl.red_saturation;
+ break;
+ case V4L2_CID_PRIVATE_BASE + 1:
+ control->value = indycam_ctrl.blue_saturation;
+ break;
+ case V4L2_CID_RED_BALANCE:
+ control->value = indycam_ctrl.red_balance;
+ break;
+ case V4L2_CID_BLUE_BALANCE:
+ control->value = indycam_ctrl.blue_balance;
+ break;
+ case V4L2_CID_EXPOSURE:
+ control->value = indycam_ctrl.shutter;
+ break;
+ case V4L2_CID_GAMMA:
+ control->value = indycam_ctrl.gamma;
+ break;
+ default:
+ err = -EINVAL;
+ }
+ break;
+ case VINO_INPUT_COMPOSITE:
+ case VINO_INPUT_SVIDEO:
+ i2c_decoder_command(DECODER_SAA7191_GET_CONTROLS,
+ &saa7191_ctrl);
+
+ switch(control->id) {
+ case V4L2_CID_HUE:
+ control->value = saa7191_ctrl.hue;
+ break;
+ case V4L2_CID_PRIVATE_BASE:
+ control->value = saa7191_ctrl.vtrc;
+ break;
+ default:
+ err = -EINVAL;
+ }
+ break;
+ default:
+ err = -EINVAL;
+ }
+
+ spin_unlock(&vino_drvdata->input_lock);
+
+ return err;
+}
+
+static int vino_v4l2_s_ctrl(struct vino_channel_settings *vcs,
+ struct v4l2_control *control)
+{
+ struct indycam_control indycam_ctrl;
+ struct saa7191_control saa7191_ctrl;
+ int i;
+ int err = 0;
+
+ spin_lock(&vino_drvdata->input_lock);
+
+ switch (vcs->input) {
+ case VINO_INPUT_D1:
+ for (i = 0; i < VINO_INDYCAM_V4L2_CONTROL_COUNT; i++) {
+ if (vino_indycam_v4l2_controls[i].id ==
+ control->id) {
+ if ((control->value >=
+ vino_indycam_v4l2_controls[i].minimum)
+ && (control->value <=
+ vino_indycam_v4l2_controls[i].
+ maximum)) {
+ goto ok1;
+ } else {
+ err = -ERANGE;
+ goto error;
+ }
+ }
+ }
+ err = -EINVAL;
+ goto error;
+
+ok1:
+ indycam_ctrl.agc = INDYCAM_VALUE_UNCHANGED;
+ indycam_ctrl.awb = INDYCAM_VALUE_UNCHANGED;
+ indycam_ctrl.shutter = INDYCAM_VALUE_UNCHANGED;
+ indycam_ctrl.gain = INDYCAM_VALUE_UNCHANGED;
+ indycam_ctrl.red_balance = INDYCAM_VALUE_UNCHANGED;
+ indycam_ctrl.blue_balance = INDYCAM_VALUE_UNCHANGED;
+ indycam_ctrl.red_saturation = INDYCAM_VALUE_UNCHANGED;
+ indycam_ctrl.blue_saturation = INDYCAM_VALUE_UNCHANGED;
+ indycam_ctrl.gamma = INDYCAM_VALUE_UNCHANGED;
+
+ switch(control->id) {
+ case V4L2_CID_AUTOGAIN:
+ indycam_ctrl.agc = control->value;
+ break;
+ case V4L2_CID_AUTO_WHITE_BALANCE:
+ indycam_ctrl.awb = control->value;
+ break;
+ case V4L2_CID_GAIN:
+ indycam_ctrl.gain = control->value;
+ break;
+ case V4L2_CID_PRIVATE_BASE:
+ indycam_ctrl.red_saturation = control->value;
+ break;
+ case V4L2_CID_PRIVATE_BASE + 1:
+ indycam_ctrl.blue_saturation = control->value;
+ break;
+ case V4L2_CID_RED_BALANCE:
+ indycam_ctrl.red_balance = control->value;
+ break;
+ case V4L2_CID_BLUE_BALANCE:
+ indycam_ctrl.blue_balance = control->value;
+ break;
+ case V4L2_CID_EXPOSURE:
+ indycam_ctrl.shutter = control->value;
+ break;
+ case V4L2_CID_GAMMA:
+ indycam_ctrl.gamma = control->value;
+ break;
+ default:
+ err = -EINVAL;
+ }
+
+ if (!err)
+ i2c_camera_command(DECODER_INDYCAM_SET_CONTROLS,
+ &indycam_ctrl);
+ break;
+ case VINO_INPUT_COMPOSITE:
+ case VINO_INPUT_SVIDEO:
+ for (i = 0; i < VINO_SAA7191_V4L2_CONTROL_COUNT; i++) {
+ if (vino_saa7191_v4l2_controls[i].id ==
+ control->id) {
+ if ((control->value >=
+ vino_saa7191_v4l2_controls[i].minimum)
+ && (control->value <=
+ vino_saa7191_v4l2_controls[i].
+ maximum)) {
+ goto ok2;
+ } else {
+ err = -ERANGE;
+ goto error;
+ }
+ }
+ }
+ err = -EINVAL;
+ goto error;
+
+ok2:
+ saa7191_ctrl.hue = SAA7191_VALUE_UNCHANGED;
+ saa7191_ctrl.vtrc = SAA7191_VALUE_UNCHANGED;
+
+ switch(control->id) {
+ case V4L2_CID_HUE:
+ saa7191_ctrl.hue = control->value;
+ break;
+ case V4L2_CID_PRIVATE_BASE:
+ saa7191_ctrl.vtrc = control->value;
+ break;
+ default:
+ err = -EINVAL;
+ }
+
+ if (!err)
+ i2c_decoder_command(DECODER_SAA7191_SET_CONTROLS,
+ &saa7191_ctrl);
+ break;
+ default:
+ err = -EINVAL;
+ }
+
+error:
+ spin_unlock(&vino_drvdata->input_lock);
+
+ return err;
+}
+
+/* File operations */
+
+static int vino_open(struct inode *inode, struct file *file)
+{
+ struct video_device *dev = video_devdata(file);
+ struct vino_channel_settings *vcs = video_get_drvdata(dev);
+ int ret = 0;
+ dprintk("open(): channel = %c\n",
+ (vcs->channel == VINO_CHANNEL_A) ? 'A' : 'B');
+
+ down(&vcs->sem);
+
+ if (vcs->users) {
+ dprintk("open(): driver busy\n");
+ ret = -EBUSY;
+ goto out;
+ }
+
+ ret = vino_acquire_input(vcs);
+ if (ret) {
+ dprintk("open(): vino_acquire_input() failed\n");
+ goto out;
+ }
+
+ vcs->users++;
+
+ out:
+ up(&vcs->sem);
+
+ dprintk("open(): %s!\n", ret ? "failed" : "complete");
+
+ return ret;
+}
+
+static int vino_close(struct inode *inode, struct file *file)
+{
+ struct video_device *dev = video_devdata(file);
+ struct vino_channel_settings *vcs = video_get_drvdata(dev);
+ dprintk("close():\n");
+
+ down(&vcs->sem);
+
+ vcs->users--;
+
+ if (!vcs->users) {
+ vino_release_input(vcs);
+
+ /* stop DMA and free buffers */
+ vino_capture_stop(vcs);
+ vino_queue_free(&vcs->fb_queue);
+ }
+
+ up(&vcs->sem);
+
+ return 0;
+}
+
+static void vino_vm_open(struct vm_area_struct *vma)
+{
+ struct vino_framebuffer *fb = vma->vm_private_data;
+
+ fb->map_count++;
+ dprintk("vino_vm_open(): count = %d\n", fb->map_count);
+}
+
+static void vino_vm_close(struct vm_area_struct *vma)
+{
+ struct vino_framebuffer *fb = vma->vm_private_data;
+
+ fb->map_count--;
+ dprintk("vino_vm_close(): count = %d\n", fb->map_count);
+}
+
+static struct vm_operations_struct vino_vm_ops = {
+ .open = vino_vm_open,
+ .close = vino_vm_close,
+};
+
+static int vino_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct video_device *dev = video_devdata(file);
+ struct vino_channel_settings *vcs = video_get_drvdata(dev);
+
+ unsigned long start = vma->vm_start;
+ unsigned long size = vma->vm_end - vma->vm_start;
+ unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+
+ struct vino_framebuffer *fb = NULL;
+ unsigned int i, length;
+ int ret = 0;
+
+ dprintk("mmap():\n");
+
+ // TODO: reject mmap if already mapped
+
+ if (down_interruptible(&vcs->sem))
+ return -EINTR;
+
+ if (vcs->reading) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ // TODO: check queue type
+
+ if (!(vma->vm_flags & VM_WRITE)) {
+ dprintk("mmap(): app bug: PROT_WRITE please\n");
+ ret = -EINVAL;
+ goto out;
+ }
+ if (!(vma->vm_flags & VM_SHARED)) {
+ dprintk("mmap(): app bug: MAP_SHARED please\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* find the correct buffer using offset */
+ length = vino_queue_get_length(&vcs->fb_queue);
+ if (length == 0) {
+ dprintk("mmap(): queue not initialized\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ for (i = 0; i < length; i++) {
+ fb = vino_queue_get_buffer(&vcs->fb_queue, i);
+ if (fb == NULL) {
+ dprintk("mmap(): vino_queue_get_buffer() failed\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (fb->offset == offset)
+ goto found;
+ }
+
+ dprintk("mmap(): invalid offset = %lu\n", offset);
+ ret = -EINVAL;
+ goto out;
+
+found:
+ dprintk("mmap(): buffer = %d\n", i);
+
+ if (size > (fb->desc_table.page_count * PAGE_SIZE)) {
+ dprintk("mmap(): failed: size = %lu > %lu\n",
+ size, fb->desc_table.page_count * PAGE_SIZE);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ for (i = 0; i < fb->desc_table.page_count; i++) {
+ unsigned long pfn =
+ virt_to_phys((void *)fb->desc_table.virtual[i]) >>
+ PAGE_SHIFT;
+
+ if (size < PAGE_SIZE)
+ break;
+
+ // protection was: PAGE_READONLY
+ if (remap_pfn_range(vma, start, pfn, PAGE_SIZE,
+ vma->vm_page_prot)) {
+ dprintk("mmap(): remap_pfn_range() failed\n");
+ ret = -EAGAIN;
+ goto out;
+ }
+
+ start += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
+
+ fb->map_count = 1;
+
+ vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED;
+ vma->vm_flags &= ~VM_IO;
+ vma->vm_private_data = fb;
+ vma->vm_file = file;
+ vma->vm_ops = &vino_vm_ops;
+
+out:
+ up(&vcs->sem);
+
+ return ret;
+}
+
+static unsigned int vino_poll(struct file *file, poll_table *pt)
+{
+ struct video_device *dev = video_devdata(file);
+ struct vino_channel_settings *vcs = video_get_drvdata(dev);
+ unsigned int outgoing;
+ unsigned int ret = 0;
+
+ // lock mutex (?)
+ // TODO: this has to be corrected for different read modes
+
+ dprintk("poll():\n");
+
+ if (vino_queue_get_outgoing(&vcs->fb_queue, &outgoing)) {
+ dprintk("poll(): vino_queue_get_outgoing() failed\n");
+ ret = POLLERR;
+ goto error;
+ }
+ if (outgoing > 0)
+ goto over;
+
+ poll_wait(file, &vcs->fb_queue.frame_wait_queue, pt);
+
+ if (vino_queue_get_outgoing(&vcs->fb_queue, &outgoing)) {
+ dprintk("poll(): vino_queue_get_outgoing() failed\n");
+ ret = POLLERR;
+ goto error;
+ }
+
+over:
+ dprintk("poll(): data %savailable\n",
+ (outgoing > 0) ? "" : "not ");
+ if (outgoing > 0) {
+ ret = POLLIN | POLLRDNORM;
+ }
+
+error:
+
+ return ret;
+}
+
+static int vino_do_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, void *arg)
+{
+ struct video_device *dev = video_devdata(file);
+ struct vino_channel_settings *vcs = video_get_drvdata(dev);
+
+ switch (_IOC_TYPE(cmd)) {
+ case 'v':
+ dprintk("ioctl(): V4L1 unsupported (0x%08x)\n", cmd);
+ break;
+ case 'V':
+ dprintk("ioctl(): V4L2 %s (0x%08x)\n",
+ v4l2_ioctl_names[_IOC_NR(cmd)], cmd);
+ break;
+ default:
+ dprintk("ioctl(): unsupported command 0x%08x\n", cmd);
+ }
+
+ switch (cmd) {
+ /* TODO: V4L1 interface (use compatibility layer?) */
+ /* V4L2 interface */
+ case VIDIOC_QUERYCAP: {
+ vino_v4l2_querycap(arg);
+ break;
+ }
+ case VIDIOC_ENUMINPUT: {
+ return vino_v4l2_enuminput(vcs, arg);
+ }
+ case VIDIOC_G_INPUT: {
+ return vino_v4l2_g_input(vcs, arg);
+ }
+ case VIDIOC_S_INPUT: {
+ return vino_v4l2_s_input(vcs, arg);
+ }
+ case VIDIOC_ENUMSTD: {
+ return vino_v4l2_enumstd(vcs, arg);
+ }
+ case VIDIOC_G_STD: {
+ return vino_v4l2_g_std(vcs, arg);
+ }
+ case VIDIOC_S_STD: {
+ return vino_v4l2_s_std(vcs, arg);
+ }
+ case VIDIOC_ENUM_FMT: {
+ return vino_v4l2_enum_fmt(vcs, arg);
+ }
+ case VIDIOC_TRY_FMT: {
+ return vino_v4l2_try_fmt(vcs, arg);
+ }
+ case VIDIOC_G_FMT: {
+ return vino_v4l2_g_fmt(vcs, arg);
+ }
+ case VIDIOC_S_FMT: {
+ return vino_v4l2_s_fmt(vcs, arg);
+ }
+ case VIDIOC_CROPCAP: {
+ return vino_v4l2_cropcap(vcs, arg);
+ }
+ case VIDIOC_G_CROP: {
+ return vino_v4l2_g_crop(vcs, arg);
+ }
+ case VIDIOC_S_CROP: {
+ return vino_v4l2_s_crop(vcs, arg);
+ }
+ case VIDIOC_G_PARM: {
+ return vino_v4l2_g_parm(vcs, arg);
+ }
+ case VIDIOC_S_PARM: {
+ return vino_v4l2_s_parm(vcs, arg);
+ }
+ case VIDIOC_REQBUFS: {
+ return vino_v4l2_reqbufs(vcs, arg);
+ }
+ case VIDIOC_QUERYBUF: {
+ return vino_v4l2_querybuf(vcs, arg);
+ }
+ case VIDIOC_QBUF: {
+ return vino_v4l2_qbuf(vcs, arg);
+ }
+ case VIDIOC_DQBUF: {
+ return vino_v4l2_dqbuf(vcs, arg, file->f_flags & O_NONBLOCK);
+ }
+ case VIDIOC_STREAMON: {
+ return vino_v4l2_streamon(vcs);
+ }
+ case VIDIOC_STREAMOFF: {
+ return vino_v4l2_streamoff(vcs);
+ }
+ case VIDIOC_QUERYCTRL: {
+ return vino_v4l2_queryctrl(vcs, arg);
+ }
+ case VIDIOC_G_CTRL: {
+ return vino_v4l2_g_ctrl(vcs, arg);
+ }
+ case VIDIOC_S_CTRL: {
+ return vino_v4l2_s_ctrl(vcs, arg);
+ }
+ default:
+ return -ENOIOCTLCMD;
+ }
+
+ return 0;
+}
+
+static int vino_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct video_device *dev = video_devdata(file);
+ struct vino_channel_settings *vcs = video_get_drvdata(dev);
+ int ret;
+
+ if (down_interruptible(&vcs->sem))
+ return -EINTR;
+
+ ret = video_usercopy(inode, file, cmd, arg, vino_do_ioctl);
+
+ up(&vcs->sem);
+
+ return ret;
+}
+
+/* Initialization and cleanup */
+
+// __initdata
+static int vino_init_stage = 0;
+
+static struct file_operations vino_fops = {
.owner = THIS_MODULE,
- .type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE,
- .hardware = VID_HARDWARE_VINO,
- .name = "VINO",
.open = vino_open,
- .close = vino_close,
+ .release = vino_close,
.ioctl = vino_ioctl,
.mmap = vino_mmap,
+ .poll = vino_poll,
+ .llseek = no_llseek,
};
-static int __init vino_init(void)
+static struct video_device v4l_device_template = {
+ .name = "NOT SET",
+ //.type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE |
+ // VID_TYPE_CLIPPING | VID_TYPE_SCALES, VID_TYPE_OVERLAY
+ .hardware = VID_HARDWARE_VINO,
+ .fops = &vino_fops,
+ .minor = -1,
+};
+
+static void vino_module_cleanup(int stage)
+{
+ switch(stage) {
+ case 10:
+ video_unregister_device(vino_drvdata->b.v4l_device);
+ vino_drvdata->b.v4l_device = NULL;
+ case 9:
+ video_unregister_device(vino_drvdata->a.v4l_device);
+ vino_drvdata->a.v4l_device = NULL;
+ case 8:
+ vino_i2c_del_bus();
+ case 7:
+ free_irq(SGI_VINO_IRQ, NULL);
+ case 6:
+ if (vino_drvdata->b.v4l_device) {
+ video_device_release(vino_drvdata->b.v4l_device);
+ vino_drvdata->b.v4l_device = NULL;
+ }
+ case 5:
+ if (vino_drvdata->a.v4l_device) {
+ video_device_release(vino_drvdata->a.v4l_device);
+ vino_drvdata->a.v4l_device = NULL;
+ }
+ case 4:
+ /* all entries in dma_cpu dummy table have the same address */
+ dma_unmap_single(NULL,
+ vino_drvdata->dummy_desc_table.dma_cpu[0],
+ PAGE_SIZE, DMA_FROM_DEVICE);
+ dma_free_coherent(NULL, VINO_DUMMY_DESC_COUNT
+ * sizeof(dma_addr_t),
+ (void *)vino_drvdata->
+ dummy_desc_table.dma_cpu,
+ vino_drvdata->dummy_desc_table.dma);
+ case 3:
+ free_page(vino_drvdata->dummy_page);
+ case 2:
+ kfree(vino_drvdata);
+ case 1:
+ iounmap(vino);
+ case 0:
+ break;
+ default:
+ dprintk("vino_module_cleanup(): invalid cleanup stage = %d\n",
+ stage);
+ }
+}
+
+static int vino_probe(void)
{
- unsigned long rev;
- int i, ret = 0;
+ unsigned long rev_id;
- /* VINO is Indy specific beast */
- if (ip22_is_fullhouse())
+ if (ip22_is_fullhouse()) {
+ printk(KERN_ERR "VINO doesn't exist in IP22 Fullhouse\n");
return -ENODEV;
+ }
- /*
- * VINO is in the EISA address space, so the sysid register will tell
- * us if the EISA_PRESENT pin on MC has been pulled low.
- *
- * If EISA_PRESENT is not set we definitely don't have a VINO equiped
- * system.
- */
if (!(sgimc->systemid & SGIMC_SYSID_EPRESENT)) {
- printk(KERN_ERR "VINO not found\n");
+ printk(KERN_ERR "VINO is not found (EISA BUS not present)\n");
return -ENODEV;
}
vino = (struct sgi_vino *)ioremap(VINO_BASE, sizeof(struct sgi_vino));
- if (!vino)
+ if (!vino) {
+ printk(KERN_ERR "VINO: ioremap() failed\n");
return -EIO;
+ }
+ vino_init_stage++;
- /* Okay, once we know that VINO is present we'll read its revision
- * safe way. One never knows... */
- if (get_dbe(rev, &(vino->rev_id))) {
- printk(KERN_ERR "VINO: failed to read revision register\n");
- ret = -ENODEV;
- goto out_unmap;
+ if (get_dbe(rev_id, &(vino->rev_id))) {
+ printk(KERN_ERR "Failed to read VINO revision register\n");
+ vino_module_cleanup(vino_init_stage);
+ return -ENODEV;
}
- if (VINO_ID_VALUE(rev) != VINO_CHIP_ID) {
- printk(KERN_ERR "VINO is not VINO (Rev/ID: 0x%04lx)\n", rev);
- ret = -ENODEV;
- goto out_unmap;
+
+ if (VINO_ID_VALUE(rev_id) != VINO_CHIP_ID) {
+ printk(KERN_ERR "Unknown VINO chip ID (Rev/ID: 0x%02lx)\n",
+ rev_id);
+ vino_module_cleanup(vino_init_stage);
+ return -ENODEV;
}
- printk(KERN_INFO "VINO Rev: 0x%02lx\n", VINO_REV_NUM(rev));
- Vino = (struct vino_video *)
- kmalloc(sizeof(struct vino_video), GFP_KERNEL);
- if (!Vino) {
- ret = -ENOMEM;
- goto out_unmap;
+ printk(KERN_INFO "VINO with chip ID %ld, revision %ld found\n",
+ VINO_ID_VALUE(rev_id), VINO_REV_NUM(rev_id));
+
+ return 0;
+}
+
+static int vino_init(void)
+{
+ dma_addr_t dma_dummy_address;
+ int i;
+
+ vino_drvdata = (struct vino_settings *)
+ kmalloc(sizeof(struct vino_settings), GFP_KERNEL);
+ if (!vino_drvdata) {
+ vino_module_cleanup(vino_init_stage);
+ return -ENOMEM;
}
+ memset(vino_drvdata, 0, sizeof(struct vino_settings));
+ vino_init_stage++;
- Vino->dummy_page = get_zeroed_page(GFP_KERNEL | GFP_DMA);
- if (!Vino->dummy_page) {
- ret = -ENOMEM;
- goto out_free_vino;
+ /* create a dummy dma descriptor */
+ vino_drvdata->dummy_page = get_zeroed_page(GFP_KERNEL | GFP_DMA);
+ if (!vino_drvdata->dummy_page) {
+ vino_module_cleanup(vino_init_stage);
+ return -ENOMEM;
}
- for (i = 0; i < 4; i++)
- Vino->dummy_buf[i] = PHYSADDR(Vino->dummy_page);
+ vino_init_stage++;
+
+ // TODO: use page_count in dummy_desc_table
+
+ vino_drvdata->dummy_desc_table.dma_cpu =
+ dma_alloc_coherent(NULL,
+ VINO_DUMMY_DESC_COUNT * sizeof(dma_addr_t),
+ &vino_drvdata->dummy_desc_table.dma,
+ GFP_KERNEL | GFP_DMA);
+ if (!vino_drvdata->dummy_desc_table.dma_cpu) {
+ vino_module_cleanup(vino_init_stage);
+ return -ENOMEM;
+ }
+ vino_init_stage++;
+
+ dma_dummy_address = dma_map_single(NULL,
+ (void *)vino_drvdata->dummy_page,
+ PAGE_SIZE, DMA_FROM_DEVICE);
+ for (i = 0; i < VINO_DUMMY_DESC_COUNT; i++) {
+ vino_drvdata->dummy_desc_table.dma_cpu[i] = dma_dummy_address;
+ }
+
+ /* initialize VINO */
vino->control = 0;
- /* prevent VINO from throwing spurious interrupts */
- vino->a.next_4_desc = PHYSADDR(Vino->dummy_buf);
- vino->b.next_4_desc = PHYSADDR(Vino->dummy_buf);
- udelay(5);
+ vino->a.next_4_desc = vino_drvdata->dummy_desc_table.dma;
+ vino->b.next_4_desc = vino_drvdata->dummy_desc_table.dma;
+ udelay(VINO_DESC_FETCH_DELAY);
+
vino->intr_status = 0;
- /* set threshold level */
- vino->a.fifo_thres = threshold_a;
- vino->b.fifo_thres = threshold_b;
- init_MUTEX(&Vino->input_lock);
+ vino->a.fifo_thres = VINO_FIFO_THRESHOLD_DEFAULT;
+ vino->b.fifo_thres = VINO_FIFO_THRESHOLD_DEFAULT;
+
+ return 0;
+}
+
+static int vino_init_channel_settings(struct vino_channel_settings *vcs,
+ unsigned int channel, const char *name)
+{
+ vcs->channel = channel;
+ vcs->input = VINO_INPUT_NONE;
+ vcs->alpha = 0;
+ vcs->users = 0;
+ vcs->data_format = VINO_DATA_FMT_GREY;
+ vcs->data_norm = VINO_DATA_NORM_NTSC;
+ vcs->decimation = 1;
+ vino_set_default_clipping(vcs);
+ vino_set_default_framerate(vcs);
+
+ vcs->capturing = 0;
+
+ init_MUTEX(&vcs->sem);
+ spin_lock_init(&vcs->capture_lock);
+
+ init_MUTEX(&vcs->fb_queue.queue_sem);
+ spin_lock_init(&vcs->fb_queue.queue_lock);
+ init_waitqueue_head(&vcs->fb_queue.frame_wait_queue);
+
+ vcs->v4l_device = video_device_alloc();
+ if (!vcs->v4l_device) {
+ vino_module_cleanup(vino_init_stage);
+ return -ENOMEM;
+ }
+ vino_init_stage++;
+
+ memcpy(vcs->v4l_device, &v4l_device_template,
+ sizeof(struct video_device));
+ strcpy(vcs->v4l_device->name, name);
+ vcs->v4l_device->release = video_device_release;
+
+ video_set_drvdata(vcs->v4l_device, vcs);
+
+ return 0;
+}
+
+static int __init vino_module_init(void)
+{
+ int ret;
+
+ printk(KERN_INFO "SGI VINO driver version %s\n",
+ VINO_MODULE_VERSION);
+
+ ret = vino_probe();
+ if (ret)
+ return ret;
+
+ ret = vino_init();
+ if (ret)
+ return ret;
+
+ /* initialize data structures */
- if (request_irq(SGI_VINO_IRQ, vino_interrupt, 0, vinostr, NULL)) {
- printk(KERN_ERR "VINO: irq%02d registration failed\n",
+ spin_lock_init(&vino_drvdata->vino_lock);
+ spin_lock_init(&vino_drvdata->input_lock);
+
+ ret = vino_init_channel_settings(&vino_drvdata->a, VINO_CHANNEL_A,
+ vino_v4l_device_name_a);
+ if (ret)
+ return ret;
+
+ ret = vino_init_channel_settings(&vino_drvdata->b, VINO_CHANNEL_B,
+ vino_v4l_device_name_b);
+ if (ret)
+ return ret;
+
+ /* initialize hardware and register V4L devices */
+
+ ret = request_irq(SGI_VINO_IRQ, vino_interrupt, 0,
+ vino_driver_description, NULL);
+ if (ret) {
+ printk(KERN_ERR "VINO: requesting IRQ %02d failed\n",
SGI_VINO_IRQ);
- ret = -EAGAIN;
- goto out_free_page;
+ vino_module_cleanup(vino_init_stage);
+ return -EAGAIN;
}
+ vino_init_stage++;
ret = vino_i2c_add_bus();
if (ret) {
- printk(KERN_ERR "VINO: I2C bus registration failed\n");
- goto out_free_irq;
+ printk(KERN_ERR "VINO I2C bus registration failed\n");
+ vino_module_cleanup(vino_init_stage);
+ return ret;
}
+ vino_init_stage++;
- if (video_register_device(&Vino->chA.vdev, VFL_TYPE_GRABBER, -1) < 0) {
- printk("%s, chnl %d: device registration failed.\n",
- Vino->chA.vdev.name, Vino->chA.chan);
- ret = -EINVAL;
- goto out_i2c_del_bus;
+ ret = video_register_device(vino_drvdata->a.v4l_device,
+ VFL_TYPE_GRABBER, -1);
+ if (ret < 0) {
+ printk(KERN_ERR "VINO channel A Video4Linux-device "
+ "registration failed\n");
+ vino_module_cleanup(vino_init_stage);
+ return -EINVAL;
}
- if (video_register_device(&Vino->chB.vdev, VFL_TYPE_GRABBER, -1) < 0) {
- printk("%s, chnl %d: device registration failed.\n",
- Vino->chB.vdev.name, Vino->chB.chan);
- ret = -EINVAL;
- goto out_unregister_vdev;
+ vino_init_stage++;
+
+ ret = video_register_device(vino_drvdata->b.v4l_device,
+ VFL_TYPE_GRABBER, -1);
+ if (ret < 0) {
+ printk(KERN_ERR "VINO channel B Video4Linux-device "
+ "registration failed\n");
+ vino_module_cleanup(vino_init_stage);
+ return -EINVAL;
}
+ vino_init_stage++;
- return 0;
+#if defined(CONFIG_KMOD) && defined(MODULE)
+ request_module("saa7191");
+ request_module("indycam");
+#endif
-out_unregister_vdev:
- video_unregister_device(&Vino->chA.vdev);
-out_i2c_del_bus:
- vino_i2c_del_bus();
-out_free_irq:
- free_irq(SGI_VINO_IRQ, NULL);
-out_free_page:
- free_page(Vino->dummy_page);
-out_free_vino:
- kfree(Vino);
-out_unmap:
- iounmap(vino);
+ dprintk("init complete!\n");
- return ret;
+ return 0;
}
-static void __exit vino_exit(void)
+static void __exit vino_module_exit(void)
{
- video_unregister_device(&Vino->chA.vdev);
- video_unregister_device(&Vino->chB.vdev);
- vino_i2c_del_bus();
- free_irq(SGI_VINO_IRQ, NULL);
- free_page(Vino->dummy_page);
- kfree(Vino);
- iounmap(vino);
+ dprintk("exiting, stage = %d ...\n", vino_init_stage);
+ vino_module_cleanup(vino_init_stage);
+ dprintk("cleanup complete, exit!\n");
}
-module_init(vino_init);
-module_exit(vino_exit);
-
-MODULE_DESCRIPTION("Video4Linux driver for SGI Indy VINO (IndyCam)");
-MODULE_LICENSE("GPL");
+module_init(vino_module_init);
+module_exit(vino_module_exit);
diff --git a/drivers/media/video/vino.h b/drivers/media/video/vino.h
index d2fce472f35a..de2d615ae7c9 100644
--- a/drivers/media/video/vino.h
+++ b/drivers/media/video/vino.h
@@ -1,13 +1,19 @@
/*
+ * Driver for the VINO (Video In No Out) system found in SGI Indys.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
* Copyright (C) 1999 Ulf Karlsson <ulfc@bun.falkenberg.se>
* Copyright (C) 2003 Ladislav Michl <ladis@linux-mips.org>
*/
-#ifndef VINO_H
-#define VINO_H
+#ifndef _VINO_H_
+#define _VINO_H_
#define VINO_BASE 0x00080000 /* Vino is in the EISA address space,
* but it is not an EISA bus card */
+#define VINO_PAGE_SIZE 4096
struct sgi_vino_channel {
u32 _pad_alpha;
@@ -21,8 +27,9 @@ struct sgi_vino_channel {
u32 _pad_clip_end;
volatile u32 clip_end;
+#define VINO_FRAMERT_FULL 0xfff
#define VINO_FRAMERT_PAL (1<<0) /* 0=NTSC 1=PAL */
-#define VINO_FRAMERT_RT(x) (((x) & 0x1fff) << 1) /* bits 1:12 */
+#define VINO_FRAMERT_RT(x) (((x) & 0xfff) << 1) /* bits 1:12 */
u32 _pad_frame_rate;
volatile u32 frame_rate;
@@ -67,18 +74,18 @@ struct sgi_vino {
volatile u32 rev_id;
#define VINO_CTRL_LITTLE_ENDIAN (1<<0)
-#define VINO_CTRL_A_FIELD_TRANS_INT (1<<1) /* Field transferred int */
-#define VINO_CTRL_A_FIFO_OF_INT (1<<2) /* FIFO overflow int */
-#define VINO_CTRL_A_END_DESC_TBL_INT (1<<3) /* End of desc table int */
-#define VINO_CTRL_A_INT (VINO_CTRL_A_FIELD_TRANS_INT | \
- VINO_CTRL_A_FIFO_OF_INT | \
- VINO_CTRL_A_END_DESC_TBL_INT)
-#define VINO_CTRL_B_FIELD_TRANS_INT (1<<4) /* Field transferred int */
-#define VINO_CTRL_B_FIFO_OF_INT (1<<5) /* FIFO overflow int */
-#define VINO_CTRL_B_END_DESC_TBL_INT (1<<6) /* End of desc table int */
-#define VINO_CTRL_B_INT (VINO_CTRL_B_FIELD_TRANS_INT | \
- VINO_CTRL_B_FIFO_OF_INT | \
- VINO_CTRL_B_END_DESC_TBL_INT)
+#define VINO_CTRL_A_EOF_INT (1<<1) /* Field transferred int */
+#define VINO_CTRL_A_FIFO_INT (1<<2) /* FIFO overflow int */
+#define VINO_CTRL_A_EOD_INT (1<<3) /* End of desc table int */
+#define VINO_CTRL_A_INT (VINO_CTRL_A_EOF_INT | \
+ VINO_CTRL_A_FIFO_INT | \
+ VINO_CTRL_A_EOD_INT)
+#define VINO_CTRL_B_EOF_INT (1<<4) /* Field transferred int */
+#define VINO_CTRL_B_FIFO_INT (1<<5) /* FIFO overflow int */
+#define VINO_CTRL_B_EOD_INT (1<<6) /* End of desc table int */
+#define VINO_CTRL_B_INT (VINO_CTRL_B_EOF_INT | \
+ VINO_CTRL_B_FIFO_INT | \
+ VINO_CTRL_B_EOD_INT)
#define VINO_CTRL_A_DMA_ENBL (1<<7)
#define VINO_CTRL_A_INTERLEAVE_ENBL (1<<8)
#define VINO_CTRL_A_SYNC_ENBL (1<<9)
@@ -104,18 +111,18 @@ struct sgi_vino {
u32 _pad_control;
volatile u32 control;
-#define VINO_INTSTAT_A_FIELD_TRANS (1<<0) /* Field transferred int */
-#define VINO_INTSTAT_A_FIFO_OF (1<<1) /* FIFO overflow int */
-#define VINO_INTSTAT_A_END_DESC_TBL (1<<2) /* End of desc table int */
-#define VINO_INTSTAT_A (VINO_INTSTAT_A_FIELD_TRANS | \
- VINO_INTSTAT_A_FIFO_OF | \
- VINO_INTSTAT_A_END_DESC_TBL)
-#define VINO_INTSTAT_B_FIELD_TRANS (1<<3) /* Field transferred int */
-#define VINO_INTSTAT_B_FIFO_OF (1<<4) /* FIFO overflow int */
-#define VINO_INTSTAT_B_END_DESC_TBL (1<<5) /* End of desc table int */
-#define VINO_INTSTAT_B (VINO_INTSTAT_B_FIELD_TRANS | \
- VINO_INTSTAT_B_FIFO_OF | \
- VINO_INTSTAT_B_END_DESC_TBL)
+#define VINO_INTSTAT_A_EOF (1<<0) /* Field transferred int */
+#define VINO_INTSTAT_A_FIFO (1<<1) /* FIFO overflow int */
+#define VINO_INTSTAT_A_EOD (1<<2) /* End of desc table int */
+#define VINO_INTSTAT_A (VINO_INTSTAT_A_EOF | \
+ VINO_INTSTAT_A_FIFO | \
+ VINO_INTSTAT_A_EOD)
+#define VINO_INTSTAT_B_EOF (1<<3) /* Field transferred int */
+#define VINO_INTSTAT_B_FIFO (1<<4) /* FIFO overflow int */
+#define VINO_INTSTAT_B_EOD (1<<5) /* End of desc table int */
+#define VINO_INTSTAT_B (VINO_INTSTAT_B_EOF | \
+ VINO_INTSTAT_B_FIFO | \
+ VINO_INTSTAT_B_EOD)
u32 _pad_intr_status;
volatile u32 intr_status;
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 0a8165974ba7..0a117c61cd18 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -2,6 +2,8 @@
* linux/drivers/mmc/mmc.c
*
* Copyright (C) 2003-2004 Russell King, All Rights Reserved.
+ * SD support Copyright (C) 2004 Ian Molton, All Rights Reserved.
+ * SD support Copyright (C) 2005 Pierre Ossman, All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -16,6 +18,8 @@
#include <linux/delay.h>
#include <linux/pagemap.h>
#include <linux/err.h>
+#include <asm/scatterlist.h>
+#include <linux/scatterlist.h>
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
@@ -172,7 +176,81 @@ int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries
EXPORT_SYMBOL(mmc_wait_for_cmd);
+/**
+ * mmc_wait_for_app_cmd - start an application command and wait for
+ completion
+ * @host: MMC host to start command
+ * @rca: RCA to send MMC_APP_CMD to
+ * @cmd: MMC command to start
+ * @retries: maximum number of retries
+ *
+ * Sends a MMC_APP_CMD, checks the card response, sends the command
+ * in the parameter and waits for it to complete. Return any error
+ * that occurred while the command was executing. Do not attempt to
+ * parse the response.
+ */
+int mmc_wait_for_app_cmd(struct mmc_host *host, unsigned int rca,
+ struct mmc_command *cmd, int retries)
+{
+ struct mmc_request mrq;
+ struct mmc_command appcmd;
+
+ int i, err;
+
+ BUG_ON(host->card_busy == NULL);
+ BUG_ON(retries < 0);
+
+ err = MMC_ERR_INVALID;
+
+ /*
+ * We have to resend MMC_APP_CMD for each attempt so
+ * we cannot use the retries field in mmc_command.
+ */
+ for (i = 0;i <= retries;i++) {
+ memset(&mrq, 0, sizeof(struct mmc_request));
+
+ appcmd.opcode = MMC_APP_CMD;
+ appcmd.arg = rca << 16;
+ appcmd.flags = MMC_RSP_R1;
+ appcmd.retries = 0;
+ memset(appcmd.resp, 0, sizeof(appcmd.resp));
+ appcmd.data = NULL;
+
+ mrq.cmd = &appcmd;
+ appcmd.data = NULL;
+
+ mmc_wait_for_req(host, &mrq);
+
+ if (appcmd.error) {
+ err = appcmd.error;
+ continue;
+ }
+
+ /* Check that card supported application commands */
+ if (!(appcmd.resp[0] & R1_APP_CMD))
+ return MMC_ERR_FAILED;
+
+ memset(&mrq, 0, sizeof(struct mmc_request));
+
+ memset(cmd->resp, 0, sizeof(cmd->resp));
+ cmd->retries = 0;
+
+ mrq.cmd = cmd;
+ cmd->data = NULL;
+ mmc_wait_for_req(host, &mrq);
+
+ err = cmd->error;
+ if (cmd->error == MMC_ERR_NONE)
+ break;
+ }
+
+ return err;
+}
+
+EXPORT_SYMBOL(mmc_wait_for_app_cmd);
+
+static int mmc_select_card(struct mmc_host *host, struct mmc_card *card);
/**
* __mmc_claim_host - exclusively claim a host
@@ -206,16 +284,10 @@ int __mmc_claim_host(struct mmc_host *host, struct mmc_card *card)
spin_unlock_irqrestore(&host->lock, flags);
remove_wait_queue(&host->wq, &wait);
- if (card != (void *)-1 && host->card_selected != card) {
- struct mmc_command cmd;
-
- host->card_selected = card;
-
- cmd.opcode = MMC_SELECT_CARD;
- cmd.arg = card->rca << 16;
- cmd.flags = MMC_RSP_R1;
-
- err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
+ if (card != (void *)-1) {
+ err = mmc_select_card(host, card);
+ if (err != MMC_ERR_NONE)
+ return err;
}
return err;
@@ -245,6 +317,63 @@ void mmc_release_host(struct mmc_host *host)
EXPORT_SYMBOL(mmc_release_host);
+static int mmc_select_card(struct mmc_host *host, struct mmc_card *card)
+{
+ int err;
+ struct mmc_command cmd;
+
+ BUG_ON(host->card_busy == NULL);
+
+ if (host->card_selected == card)
+ return MMC_ERR_NONE;
+
+ host->card_selected = card;
+
+ cmd.opcode = MMC_SELECT_CARD;
+ cmd.arg = card->rca << 16;
+ cmd.flags = MMC_RSP_R1;
+
+ err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
+ if (err != MMC_ERR_NONE)
+ return err;
+
+ /*
+ * Default bus width is 1 bit.
+ */
+ host->ios.bus_width = MMC_BUS_WIDTH_1;
+
+ /*
+ * We can only change the bus width of the selected
+ * card so therefore we have to put the handling
+ * here.
+ */
+ if (host->caps & MMC_CAP_4_BIT_DATA) {
+ /*
+ * The card is in 1 bit mode by default so
+ * we only need to change if it supports the
+ * wider version.
+ */
+ if (mmc_card_sd(card) &&
+ (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {
+ struct mmc_command cmd;
+ cmd.opcode = SD_APP_SET_BUS_WIDTH;
+ cmd.arg = SD_BUS_WIDTH_4;
+ cmd.flags = MMC_RSP_R1;
+
+ err = mmc_wait_for_app_cmd(host, card->rca, &cmd,
+ CMD_RETRIES);
+ if (err != MMC_ERR_NONE)
+ return err;
+
+ host->ios.bus_width = MMC_BUS_WIDTH_4;
+ }
+ }
+
+ host->ops->set_ios(host, &host->ios);
+
+ return MMC_ERR_NONE;
+}
+
/*
* Ensure that no card is selected.
*/
@@ -322,48 +451,69 @@ static void mmc_decode_cid(struct mmc_card *card)
memset(&card->cid, 0, sizeof(struct mmc_cid));
- /*
- * The selection of the format here is guesswork based upon
- * information people have sent to date.
- */
- switch (card->csd.mmca_vsn) {
- case 0: /* MMC v1.? */
- case 1: /* MMC v1.4 */
- card->cid.manfid = UNSTUFF_BITS(resp, 104, 24);
- card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8);
- card->cid.prod_name[1] = UNSTUFF_BITS(resp, 88, 8);
- card->cid.prod_name[2] = UNSTUFF_BITS(resp, 80, 8);
- card->cid.prod_name[3] = UNSTUFF_BITS(resp, 72, 8);
- card->cid.prod_name[4] = UNSTUFF_BITS(resp, 64, 8);
- card->cid.prod_name[5] = UNSTUFF_BITS(resp, 56, 8);
- card->cid.prod_name[6] = UNSTUFF_BITS(resp, 48, 8);
- card->cid.hwrev = UNSTUFF_BITS(resp, 44, 4);
- card->cid.fwrev = UNSTUFF_BITS(resp, 40, 4);
- card->cid.serial = UNSTUFF_BITS(resp, 16, 24);
- card->cid.month = UNSTUFF_BITS(resp, 12, 4);
- card->cid.year = UNSTUFF_BITS(resp, 8, 4) + 1997;
- break;
-
- case 2: /* MMC v2.x ? */
- case 3: /* MMC v3.x ? */
- card->cid.manfid = UNSTUFF_BITS(resp, 120, 8);
- card->cid.oemid = UNSTUFF_BITS(resp, 104, 16);
- card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8);
- card->cid.prod_name[1] = UNSTUFF_BITS(resp, 88, 8);
- card->cid.prod_name[2] = UNSTUFF_BITS(resp, 80, 8);
- card->cid.prod_name[3] = UNSTUFF_BITS(resp, 72, 8);
- card->cid.prod_name[4] = UNSTUFF_BITS(resp, 64, 8);
- card->cid.prod_name[5] = UNSTUFF_BITS(resp, 56, 8);
- card->cid.serial = UNSTUFF_BITS(resp, 16, 32);
- card->cid.month = UNSTUFF_BITS(resp, 12, 4);
- card->cid.year = UNSTUFF_BITS(resp, 8, 4) + 1997;
- break;
-
- default:
- printk("%s: card has unknown MMCA version %d\n",
- mmc_hostname(card->host), card->csd.mmca_vsn);
- mmc_card_set_bad(card);
- break;
+ if (mmc_card_sd(card)) {
+ /*
+ * SD doesn't currently have a version field so we will
+ * have to assume we can parse this.
+ */
+ card->cid.manfid = UNSTUFF_BITS(resp, 120, 8);
+ card->cid.oemid = UNSTUFF_BITS(resp, 104, 16);
+ card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8);
+ card->cid.prod_name[1] = UNSTUFF_BITS(resp, 88, 8);
+ card->cid.prod_name[2] = UNSTUFF_BITS(resp, 80, 8);
+ card->cid.prod_name[3] = UNSTUFF_BITS(resp, 72, 8);
+ card->cid.prod_name[4] = UNSTUFF_BITS(resp, 64, 8);
+ card->cid.hwrev = UNSTUFF_BITS(resp, 60, 4);
+ card->cid.fwrev = UNSTUFF_BITS(resp, 56, 4);
+ card->cid.serial = UNSTUFF_BITS(resp, 24, 32);
+ card->cid.year = UNSTUFF_BITS(resp, 12, 8);
+ card->cid.month = UNSTUFF_BITS(resp, 8, 4);
+
+ card->cid.year += 2000; /* SD cards year offset */
+ } else {
+ /*
+ * The selection of the format here is based upon published
+ * specs from sandisk and from what people have reported.
+ */
+ switch (card->csd.mmca_vsn) {
+ case 0: /* MMC v1.0 - v1.2 */
+ case 1: /* MMC v1.4 */
+ card->cid.manfid = UNSTUFF_BITS(resp, 104, 24);
+ card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8);
+ card->cid.prod_name[1] = UNSTUFF_BITS(resp, 88, 8);
+ card->cid.prod_name[2] = UNSTUFF_BITS(resp, 80, 8);
+ card->cid.prod_name[3] = UNSTUFF_BITS(resp, 72, 8);
+ card->cid.prod_name[4] = UNSTUFF_BITS(resp, 64, 8);
+ card->cid.prod_name[5] = UNSTUFF_BITS(resp, 56, 8);
+ card->cid.prod_name[6] = UNSTUFF_BITS(resp, 48, 8);
+ card->cid.hwrev = UNSTUFF_BITS(resp, 44, 4);
+ card->cid.fwrev = UNSTUFF_BITS(resp, 40, 4);
+ card->cid.serial = UNSTUFF_BITS(resp, 16, 24);
+ card->cid.month = UNSTUFF_BITS(resp, 12, 4);
+ card->cid.year = UNSTUFF_BITS(resp, 8, 4) + 1997;
+ break;
+
+ case 2: /* MMC v2.0 - v2.2 */
+ case 3: /* MMC v3.1 - v3.3 */
+ card->cid.manfid = UNSTUFF_BITS(resp, 120, 8);
+ card->cid.oemid = UNSTUFF_BITS(resp, 104, 16);
+ card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8);
+ card->cid.prod_name[1] = UNSTUFF_BITS(resp, 88, 8);
+ card->cid.prod_name[2] = UNSTUFF_BITS(resp, 80, 8);
+ card->cid.prod_name[3] = UNSTUFF_BITS(resp, 72, 8);
+ card->cid.prod_name[4] = UNSTUFF_BITS(resp, 64, 8);
+ card->cid.prod_name[5] = UNSTUFF_BITS(resp, 56, 8);
+ card->cid.serial = UNSTUFF_BITS(resp, 16, 32);
+ card->cid.month = UNSTUFF_BITS(resp, 12, 4);
+ card->cid.year = UNSTUFF_BITS(resp, 8, 4) + 1997;
+ break;
+
+ default:
+ printk("%s: card has unknown MMCA version %d\n",
+ mmc_hostname(card->host), card->csd.mmca_vsn);
+ mmc_card_set_bad(card);
+ break;
+ }
}
}
@@ -376,34 +526,86 @@ static void mmc_decode_csd(struct mmc_card *card)
unsigned int e, m, csd_struct;
u32 *resp = card->raw_csd;
- /*
- * We only understand CSD structure v1.1 and v2.
- * v2 has extra information in bits 15, 11 and 10.
- */
- csd_struct = UNSTUFF_BITS(resp, 126, 2);
- if (csd_struct != 1 && csd_struct != 2) {
- printk("%s: unrecognised CSD structure version %d\n",
- mmc_hostname(card->host), csd_struct);
- mmc_card_set_bad(card);
- return;
+ if (mmc_card_sd(card)) {
+ csd_struct = UNSTUFF_BITS(resp, 126, 2);
+ if (csd_struct != 0) {
+ printk("%s: unrecognised CSD structure version %d\n",
+ mmc_hostname(card->host), csd_struct);
+ mmc_card_set_bad(card);
+ return;
+ }
+
+ m = UNSTUFF_BITS(resp, 115, 4);
+ e = UNSTUFF_BITS(resp, 112, 3);
+ csd->tacc_ns = (tacc_exp[e] * tacc_mant[m] + 9) / 10;
+ csd->tacc_clks = UNSTUFF_BITS(resp, 104, 8) * 100;
+
+ m = UNSTUFF_BITS(resp, 99, 4);
+ e = UNSTUFF_BITS(resp, 96, 3);
+ csd->max_dtr = tran_exp[e] * tran_mant[m];
+ csd->cmdclass = UNSTUFF_BITS(resp, 84, 12);
+
+ e = UNSTUFF_BITS(resp, 47, 3);
+ m = UNSTUFF_BITS(resp, 62, 12);
+ csd->capacity = (1 + m) << (e + 2);
+
+ csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4);
+ } else {
+ /*
+ * We only understand CSD structure v1.1 and v1.2.
+ * v1.2 has extra information in bits 15, 11 and 10.
+ */
+ csd_struct = UNSTUFF_BITS(resp, 126, 2);
+ if (csd_struct != 1 && csd_struct != 2) {
+ printk("%s: unrecognised CSD structure version %d\n",
+ mmc_hostname(card->host), csd_struct);
+ mmc_card_set_bad(card);
+ return;
+ }
+
+ csd->mmca_vsn = UNSTUFF_BITS(resp, 122, 4);
+ m = UNSTUFF_BITS(resp, 115, 4);
+ e = UNSTUFF_BITS(resp, 112, 3);
+ csd->tacc_ns = (tacc_exp[e] * tacc_mant[m] + 9) / 10;
+ csd->tacc_clks = UNSTUFF_BITS(resp, 104, 8) * 100;
+
+ m = UNSTUFF_BITS(resp, 99, 4);
+ e = UNSTUFF_BITS(resp, 96, 3);
+ csd->max_dtr = tran_exp[e] * tran_mant[m];
+ csd->cmdclass = UNSTUFF_BITS(resp, 84, 12);
+
+ e = UNSTUFF_BITS(resp, 47, 3);
+ m = UNSTUFF_BITS(resp, 62, 12);
+ csd->capacity = (1 + m) << (e + 2);
+
+ csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4);
}
+}
- csd->mmca_vsn = UNSTUFF_BITS(resp, 122, 4);
- m = UNSTUFF_BITS(resp, 115, 4);
- e = UNSTUFF_BITS(resp, 112, 3);
- csd->tacc_ns = (tacc_exp[e] * tacc_mant[m] + 9) / 10;
- csd->tacc_clks = UNSTUFF_BITS(resp, 104, 8) * 100;
+/*
+ * Given a 64-bit response, decode to our card SCR structure.
+ */
+static void mmc_decode_scr(struct mmc_card *card)
+{
+ struct sd_scr *scr = &card->scr;
+ unsigned int scr_struct;
+ u32 resp[4];
+
+ BUG_ON(!mmc_card_sd(card));
- m = UNSTUFF_BITS(resp, 99, 4);
- e = UNSTUFF_BITS(resp, 96, 3);
- csd->max_dtr = tran_exp[e] * tran_mant[m];
- csd->cmdclass = UNSTUFF_BITS(resp, 84, 12);
+ resp[3] = card->raw_scr[1];
+ resp[2] = card->raw_scr[0];
- e = UNSTUFF_BITS(resp, 47, 3);
- m = UNSTUFF_BITS(resp, 62, 12);
- csd->capacity = (1 + m) << (e + 2);
+ scr_struct = UNSTUFF_BITS(resp, 60, 4);
+ if (scr_struct != 0) {
+ printk("%s: unrecognised SCR structure version %d\n",
+ mmc_hostname(card->host), scr_struct);
+ mmc_card_set_bad(card);
+ return;
+ }
- csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4);
+ scr->sda_vsn = UNSTUFF_BITS(resp, 56, 4);
+ scr->bus_widths = UNSTUFF_BITS(resp, 48, 4);
}
/*
@@ -487,6 +689,7 @@ static void mmc_power_up(struct mmc_host *host)
host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
host->ios.chip_select = MMC_CS_DONTCARE;
host->ios.power_mode = MMC_POWER_UP;
+ host->ios.bus_width = MMC_BUS_WIDTH_1;
host->ops->set_ios(host, &host->ios);
mmc_delay(1);
@@ -505,6 +708,7 @@ static void mmc_power_off(struct mmc_host *host)
host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
host->ios.chip_select = MMC_CS_DONTCARE;
host->ios.power_mode = MMC_POWER_OFF;
+ host->ios.bus_width = MMC_BUS_WIDTH_1;
host->ops->set_ios(host, &host->ios);
}
@@ -536,6 +740,34 @@ static int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
return err;
}
+static int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
+{
+ struct mmc_command cmd;
+ int i, err = 0;
+
+ cmd.opcode = SD_APP_OP_COND;
+ cmd.arg = ocr;
+ cmd.flags = MMC_RSP_R3;
+
+ for (i = 100; i; i--) {
+ err = mmc_wait_for_app_cmd(host, 0, &cmd, CMD_RETRIES);
+ if (err != MMC_ERR_NONE)
+ break;
+
+ if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0)
+ break;
+
+ err = MMC_ERR_TIMEOUT;
+
+ mmc_delay(10);
+ }
+
+ if (rocr)
+ *rocr = cmd.resp[0];
+
+ return err;
+}
+
/*
* Discover cards by requesting their CID. If this command
* times out, it is not an error; there are no further cards
@@ -579,13 +811,38 @@ static void mmc_discover_cards(struct mmc_host *host)
card->state &= ~MMC_STATE_DEAD;
- cmd.opcode = MMC_SET_RELATIVE_ADDR;
- cmd.arg = card->rca << 16;
- cmd.flags = MMC_RSP_R1;
+ if (host->mode == MMC_MODE_SD) {
+ mmc_card_set_sd(card);
- err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
- if (err != MMC_ERR_NONE)
- mmc_card_set_dead(card);
+ cmd.opcode = SD_SEND_RELATIVE_ADDR;
+ cmd.arg = 0;
+ cmd.flags = MMC_RSP_R1;
+
+ err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
+ if (err != MMC_ERR_NONE)
+ mmc_card_set_dead(card);
+ else {
+ card->rca = cmd.resp[0] >> 16;
+
+ if (!host->ops->get_ro) {
+ printk(KERN_WARNING "%s: host does not "
+ "support reading read-only "
+ "switch. assuming write-enable.\n",
+ mmc_hostname(host));
+ } else {
+ if (host->ops->get_ro(host))
+ mmc_card_set_readonly(card);
+ }
+ }
+ } else {
+ cmd.opcode = MMC_SET_RELATIVE_ADDR;
+ cmd.arg = card->rca << 16;
+ cmd.flags = MMC_RSP_R1;
+
+ err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
+ if (err != MMC_ERR_NONE)
+ mmc_card_set_dead(card);
+ }
}
}
@@ -617,6 +874,79 @@ static void mmc_read_csds(struct mmc_host *host)
}
}
+static void mmc_read_scrs(struct mmc_host *host)
+{
+ int err;
+ struct mmc_card *card;
+
+ struct mmc_request mrq;
+ struct mmc_command cmd;
+ struct mmc_data data;
+
+ struct scatterlist sg;
+
+ list_for_each_entry(card, &host->cards, node) {
+ if (card->state & (MMC_STATE_DEAD|MMC_STATE_PRESENT))
+ continue;
+ if (!mmc_card_sd(card))
+ continue;
+
+ err = mmc_select_card(host, card);
+ if (err != MMC_ERR_NONE) {
+ mmc_card_set_dead(card);
+ continue;
+ }
+
+ memset(&cmd, 0, sizeof(struct mmc_command));
+
+ cmd.opcode = MMC_APP_CMD;
+ cmd.arg = card->rca << 16;
+ cmd.flags = MMC_RSP_R1;
+
+ err = mmc_wait_for_cmd(host, &cmd, 0);
+ if ((err != MMC_ERR_NONE) || !(cmd.resp[0] & R1_APP_CMD)) {
+ mmc_card_set_dead(card);
+ continue;
+ }
+
+ memset(&cmd, 0, sizeof(struct mmc_command));
+
+ cmd.opcode = SD_APP_SEND_SCR;
+ cmd.arg = 0;
+ cmd.flags = MMC_RSP_R1;
+
+ memset(&data, 0, sizeof(struct mmc_data));
+
+ data.timeout_ns = card->csd.tacc_ns * 10;
+ data.timeout_clks = card->csd.tacc_clks * 10;
+ data.blksz_bits = 3;
+ data.blocks = 1;
+ data.flags = MMC_DATA_READ;
+ data.sg = &sg;
+ data.sg_len = 1;
+
+ memset(&mrq, 0, sizeof(struct mmc_request));
+
+ mrq.cmd = &cmd;
+ mrq.data = &data;
+
+ sg_init_one(&sg, (u8*)card->raw_scr, 8);
+
+ err = mmc_wait_for_req(host, &mrq);
+ if (err != MMC_ERR_NONE) {
+ mmc_card_set_dead(card);
+ continue;
+ }
+
+ card->raw_scr[0] = ntohl(card->raw_scr[0]);
+ card->raw_scr[1] = ntohl(card->raw_scr[1]);
+
+ mmc_decode_scr(card);
+ }
+
+ mmc_deselect_cards(host);
+}
+
static unsigned int mmc_calculate_clock(struct mmc_host *host)
{
struct mmc_card *card;
@@ -669,12 +999,24 @@ static void mmc_setup(struct mmc_host *host)
int err;
u32 ocr;
+ host->mode = MMC_MODE_SD;
+
mmc_power_up(host);
mmc_idle_cards(host);
- err = mmc_send_op_cond(host, 0, &ocr);
- if (err != MMC_ERR_NONE)
- return;
+ err = mmc_send_app_op_cond(host, 0, &ocr);
+
+ /*
+ * If we fail to detect any SD cards then try
+ * searching for MMC cards.
+ */
+ if (err != MMC_ERR_NONE) {
+ host->mode = MMC_MODE_MMC;
+
+ err = mmc_send_op_cond(host, 0, &ocr);
+ if (err != MMC_ERR_NONE)
+ return;
+ }
host->ocr = mmc_select_voltage(host, ocr);
@@ -714,7 +1056,10 @@ static void mmc_setup(struct mmc_host *host)
* all get the idea that they should be ready for CMD2.
* (My SanDisk card seems to need this.)
*/
- mmc_send_op_cond(host, host->ocr, NULL);
+ if (host->mode == MMC_MODE_SD)
+ mmc_send_app_op_cond(host, host->ocr, NULL);
+ else
+ mmc_send_op_cond(host, host->ocr, NULL);
mmc_discover_cards(host);
@@ -725,6 +1070,9 @@ static void mmc_setup(struct mmc_host *host)
host->ops->set_ios(host, &host->ios);
mmc_read_csds(host);
+
+ if (host->mode == MMC_MODE_SD)
+ mmc_read_scrs(host);
}
diff --git a/drivers/mmc/mmc_block.c b/drivers/mmc/mmc_block.c
index d4eee99c2bf6..fa83f15fdf16 100644
--- a/drivers/mmc/mmc_block.c
+++ b/drivers/mmc/mmc_block.c
@@ -95,6 +95,10 @@ static int mmc_blk_open(struct inode *inode, struct file *filp)
if (md->usage == 2)
check_disk_change(inode->i_bdev);
ret = 0;
+
+ if ((filp->f_mode & FMODE_WRITE) &&
+ mmc_card_readonly(md->queue.card))
+ ret = -EROFS;
}
return ret;
@@ -403,9 +407,10 @@ static int mmc_blk_probe(struct mmc_card *card)
if (err)
goto out;
- printk(KERN_INFO "%s: %s %s %dKiB\n",
+ printk(KERN_INFO "%s: %s %s %dKiB %s\n",
md->disk->disk_name, mmc_card_id(card), mmc_card_name(card),
- (card->csd.capacity << card->csd.read_blkbits) / 1024);
+ (card->csd.capacity << card->csd.read_blkbits) / 1024,
+ mmc_card_readonly(card)?"(ro)":"");
mmc_set_drvdata(card, md);
add_disk(md->disk);
diff --git a/drivers/mmc/mmc_sysfs.c b/drivers/mmc/mmc_sysfs.c
index ad8949810fc5..3f4a66ca9555 100644
--- a/drivers/mmc/mmc_sysfs.c
+++ b/drivers/mmc/mmc_sysfs.c
@@ -34,6 +34,7 @@ MMC_ATTR(cid, "%08x%08x%08x%08x\n", card->raw_cid[0], card->raw_cid[1],
card->raw_cid[2], card->raw_cid[3]);
MMC_ATTR(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1],
card->raw_csd[2], card->raw_csd[3]);
+MMC_ATTR(scr, "%08x%08x\n", card->raw_scr[0], card->raw_scr[1]);
MMC_ATTR(date, "%02d/%04d\n", card->cid.month, card->cid.year);
MMC_ATTR(fwrev, "0x%x\n", card->cid.fwrev);
MMC_ATTR(hwrev, "0x%x\n", card->cid.hwrev);
@@ -57,6 +58,8 @@ static struct device_attribute mmc_dev_attrs[] = {
__ATTR_NULL
};
+static struct device_attribute mmc_dev_attr_scr = MMC_ATTR_RO(scr);
+
static void mmc_release_card(struct device *dev)
{
@@ -207,10 +210,20 @@ void mmc_init_card(struct mmc_card *card, struct mmc_host *host)
*/
int mmc_register_card(struct mmc_card *card)
{
+ int ret;
+
snprintf(card->dev.bus_id, sizeof(card->dev.bus_id),
"%s:%04x", mmc_hostname(card->host), card->rca);
- return device_add(&card->dev);
+ ret = device_add(&card->dev);
+ if (ret == 0) {
+ if (mmc_card_sd(card)) {
+ ret = device_create_file(&card->dev, &mmc_dev_attr_scr);
+ if (ret)
+ device_del(&card->dev);
+ }
+ }
+ return ret;
}
/*
@@ -219,8 +232,12 @@ int mmc_register_card(struct mmc_card *card)
*/
void mmc_remove_card(struct mmc_card *card)
{
- if (mmc_card_present(card))
+ if (mmc_card_present(card)) {
+ if (mmc_card_sd(card))
+ device_remove_file(&card->dev, &mmc_dev_attr_scr);
+
device_del(&card->dev);
+ }
put_device(&card->dev);
}
diff --git a/drivers/mmc/pxamci.c b/drivers/mmc/pxamci.c
index b78beb1b0159..e99a53b09e32 100644
--- a/drivers/mmc/pxamci.c
+++ b/drivers/mmc/pxamci.c
@@ -362,6 +362,16 @@ static void pxamci_request(struct mmc_host *mmc, struct mmc_request *mrq)
pxamci_start_cmd(host, mrq->cmd, cmdat);
}
+static int pxamci_get_ro(struct mmc_host *mmc)
+{
+ struct pxamci_host *host = mmc_priv(mmc);
+
+ if (host->pdata && host->pdata->get_ro)
+ return host->pdata->get_ro(mmc->dev);
+ /* Host doesn't support read only detection so assume writeable */
+ return 0;
+}
+
static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{
struct pxamci_host *host = mmc_priv(mmc);
@@ -401,6 +411,7 @@ static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
static struct mmc_host_ops pxamci_ops = {
.request = pxamci_request,
+ .get_ro = pxamci_get_ro,
.set_ios = pxamci_set_ios,
};
diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c
index 08ae22aed9e8..dec01d38c782 100644
--- a/drivers/mmc/wbsd.c
+++ b/drivers/mmc/wbsd.c
@@ -720,11 +720,28 @@ static void wbsd_prepare_data(struct wbsd_host* host, struct mmc_data* data)
* calculate CRC.
*
* Space for CRC must be included in the size.
+ * Two bytes are needed for each data line.
*/
- blksize = (1 << data->blksz_bits) + 2;
+ if (host->bus_width == MMC_BUS_WIDTH_1)
+ {
+ blksize = (1 << data->blksz_bits) + 2;
+
+ wbsd_write_index(host, WBSD_IDX_PBSMSB, (blksize >> 4) & 0xF0);
+ wbsd_write_index(host, WBSD_IDX_PBSLSB, blksize & 0xFF);
+ }
+ else if (host->bus_width == MMC_BUS_WIDTH_4)
+ {
+ blksize = (1 << data->blksz_bits) + 2 * 4;
- wbsd_write_index(host, WBSD_IDX_PBSMSB, (blksize >> 4) & 0xF0);
- wbsd_write_index(host, WBSD_IDX_PBSLSB, blksize & 0xFF);
+ wbsd_write_index(host, WBSD_IDX_PBSMSB, ((blksize >> 4) & 0xF0)
+ | WBSD_DATA_WIDTH);
+ wbsd_write_index(host, WBSD_IDX_PBSLSB, blksize & 0xFF);
+ }
+ else
+ {
+ data->error = MMC_ERR_INVALID;
+ return;
+ }
/*
* Clear the FIFO. This is needed even for DMA
@@ -960,9 +977,9 @@ static void wbsd_set_ios(struct mmc_host* mmc, struct mmc_ios* ios)
struct wbsd_host* host = mmc_priv(mmc);
u8 clk, setup, pwr;
- DBGF("clock %uHz busmode %u powermode %u cs %u Vdd %u\n",
- ios->clock, ios->bus_mode, ios->power_mode, ios->chip_select,
- ios->vdd);
+ DBGF("clock %uHz busmode %u powermode %u cs %u Vdd %u width %u\n",
+ ios->clock, ios->bus_mode, ios->power_mode, ios->chip_select,
+ ios->vdd, ios->bus_width);
spin_lock_bh(&host->lock);
@@ -1010,6 +1027,7 @@ static void wbsd_set_ios(struct mmc_host* mmc, struct mmc_ios* ios)
setup = wbsd_read_index(host, WBSD_IDX_SETUP);
if (ios->chip_select == MMC_CS_HIGH)
{
+ BUG_ON(ios->bus_width != MMC_BUS_WIDTH_1);
setup |= WBSD_DAT3_H;
host->flags |= WBSD_FIGNORE_DETECT;
}
@@ -1025,12 +1043,41 @@ static void wbsd_set_ios(struct mmc_host* mmc, struct mmc_ios* ios)
}
wbsd_write_index(host, WBSD_IDX_SETUP, setup);
+ /*
+ * Store bus width for later. Will be used when
+ * setting up the data transfer.
+ */
+ host->bus_width = ios->bus_width;
+
spin_unlock_bh(&host->lock);
}
+static int wbsd_get_ro(struct mmc_host* mmc)
+{
+ struct wbsd_host* host = mmc_priv(mmc);
+ u8 csr;
+
+ spin_lock_bh(&host->lock);
+
+ csr = inb(host->base + WBSD_CSR);
+ csr |= WBSD_MSLED;
+ outb(csr, host->base + WBSD_CSR);
+
+ mdelay(1);
+
+ csr = inb(host->base + WBSD_CSR);
+ csr &= ~WBSD_MSLED;
+ outb(csr, host->base + WBSD_CSR);
+
+ spin_unlock_bh(&host->lock);
+
+ return csr & WBSD_WRPT;
+}
+
static struct mmc_host_ops wbsd_ops = {
.request = wbsd_request,
.set_ios = wbsd_set_ios,
+ .get_ro = wbsd_get_ro,
};
/*****************************************************************************\
@@ -1355,6 +1402,7 @@ static int __devinit wbsd_alloc_mmc(struct device* dev)
mmc->f_min = 375000;
mmc->f_max = 24000000;
mmc->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34;
+ mmc->caps = MMC_CAP_4_BIT_DATA;
spin_lock_init(&host->lock);
diff --git a/drivers/mmc/wbsd.h b/drivers/mmc/wbsd.h
index 8af43549f5d5..9005b5241b3c 100644
--- a/drivers/mmc/wbsd.h
+++ b/drivers/mmc/wbsd.h
@@ -106,6 +106,8 @@
#define WBSD_CLK_16M 0x02
#define WBSD_CLK_24M 0x03
+#define WBSD_DATA_WIDTH 0x01
+
#define WBSD_DAT3_H 0x08
#define WBSD_FIFO_RESET 0x04
#define WBSD_SOFT_RESET 0x02
@@ -164,6 +166,7 @@ struct wbsd_host
int firsterr; /* See fifo functions */
u8 clk; /* Current clock speed */
+ unsigned char bus_width; /* Current bus width */
int config; /* Config port */
u8 unlock_code; /* Code to unlock config */
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index eee5115658c8..04e54318bc6a 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -526,6 +526,7 @@ static void nand_wait_ready(struct mtd_info *mtd)
do {
if (this->dev_ready(mtd))
return;
+ touch_softlockup_watchdog();
} while (time_before(jiffies, timeo));
}
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c
index 07746b95fd83..455ba915ede7 100644
--- a/drivers/net/3c59x.c
+++ b/drivers/net/3c59x.c
@@ -973,6 +973,11 @@ static int vortex_suspend (struct pci_dev *pdev, pm_message_t state)
netif_device_detach(dev);
vortex_down(dev, 1);
}
+ pci_save_state(pdev);
+ pci_enable_wake(pdev, pci_choose_state(pdev, state), 0);
+ free_irq(dev->irq, dev);
+ pci_disable_device(pdev);
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
}
return 0;
}
@@ -980,8 +985,19 @@ static int vortex_suspend (struct pci_dev *pdev, pm_message_t state)
static int vortex_resume (struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
+ struct vortex_private *vp = netdev_priv(dev);
- if (dev && dev->priv) {
+ if (dev && vp) {
+ pci_set_power_state(pdev, PCI_D0);
+ pci_restore_state(pdev);
+ pci_enable_device(pdev);
+ pci_set_master(pdev);
+ if (request_irq(dev->irq, vp->full_bus_master_rx ?
+ &boomerang_interrupt : &vortex_interrupt, SA_SHIRQ, dev->name, dev)) {
+ printk(KERN_WARNING "%s: Could not reserve IRQ %d\n", dev->name, dev->irq);
+ pci_disable_device(pdev);
+ return -EBUSY;
+ }
if (netif_running(dev)) {
vortex_up(dev);
netif_device_attach(dev);
@@ -1873,6 +1889,7 @@ vortex_timer(unsigned long data)
{
spin_lock_bh(&vp->lock);
mii_status = mdio_read(dev, vp->phys[0], 1);
+ mii_status = mdio_read(dev, vp->phys[0], 1);
ok = 1;
if (vortex_debug > 2)
printk(KERN_DEBUG "%s: MII transceiver has status %4.4x.\n",
diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c
index 10125a1dba22..dd89bda1f131 100644
--- a/drivers/net/irda/smsc-ircc2.c
+++ b/drivers/net/irda/smsc-ircc2.c
@@ -4,10 +4,10 @@
* Description: Driver for the SMC Infrared Communications Controller
* Status: Experimental.
* Author: Daniele Peri (peri@csai.unipa.it)
- * Created at:
- * Modified at:
- * Modified by:
- *
+ * Created at:
+ * Modified at:
+ * Modified by:
+ *
* Copyright (c) 2002 Daniele Peri
* All Rights Reserved.
* Copyright (c) 2002 Jean Tourrilhes
@@ -17,26 +17,26 @@
*
* Copyright (c) 2001 Stefani Seibold
* Copyright (c) 1999-2001 Dag Brattli
- * Copyright (c) 1998-1999 Thomas Davis,
+ * Copyright (c) 1998-1999 Thomas Davis,
*
* and irport.c:
*
* Copyright (c) 1997, 1998, 1999-2000 Dag Brattli, All Rights Reserved.
*
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
- *
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
********************************************************************/
@@ -68,24 +68,42 @@
#include "smsc-ircc2.h"
#include "smsc-sio.h"
+
+MODULE_AUTHOR("Daniele Peri <peri@csai.unipa.it>");
+MODULE_DESCRIPTION("SMC IrCC SIR/FIR controller driver");
+MODULE_LICENSE("GPL");
+
+static int ircc_dma = 255;
+module_param(ircc_dma, int, 0);
+MODULE_PARM_DESC(ircc_dma, "DMA channel");
+
+static int ircc_irq = 255;
+module_param(ircc_irq, int, 0);
+MODULE_PARM_DESC(ircc_irq, "IRQ line");
+
+static int ircc_fir;
+module_param(ircc_fir, int, 0);
+MODULE_PARM_DESC(ircc_fir, "FIR Base Address");
+
+static int ircc_sir;
+module_param(ircc_sir, int, 0);
+MODULE_PARM_DESC(ircc_sir, "SIR Base Address");
+
+static int ircc_cfg;
+module_param(ircc_cfg, int, 0);
+MODULE_PARM_DESC(ircc_cfg, "Configuration register base address");
+
+static int ircc_transceiver;
+module_param(ircc_transceiver, int, 0);
+MODULE_PARM_DESC(ircc_transceiver, "Transceiver type");
+
/* Types */
struct smsc_transceiver {
char *name;
- void (*set_for_speed)(int fir_base, u32 speed);
+ void (*set_for_speed)(int fir_base, u32 speed);
int (*probe)(int fir_base);
};
-typedef struct smsc_transceiver smsc_transceiver_t;
-
-#if 0
-struct smc_chip {
- char *name;
- u16 flags;
- u8 devid;
- u8 rev;
-};
-typedef struct smc_chip smc_chip_t;
-#endif
struct smsc_chip {
char *name;
@@ -96,20 +114,18 @@ struct smsc_chip {
u8 devid;
u8 rev;
};
-typedef struct smsc_chip smsc_chip_t;
struct smsc_chip_address {
unsigned int cfg_base;
unsigned int type;
};
-typedef struct smsc_chip_address smsc_chip_address_t;
/* Private data for each instance */
struct smsc_ircc_cb {
struct net_device *netdev; /* Yes! we are some kind of netdevice */
struct net_device_stats stats;
struct irlap_cb *irlap; /* The link layer we are binded to */
-
+
chipio_t io; /* IrDA controller information */
iobuff_t tx_buff; /* Transmit buffer */
iobuff_t rx_buff; /* Receive buffer */
@@ -119,7 +135,7 @@ struct smsc_ircc_cb {
struct qos_info qos; /* QoS capabilities for this device */
spinlock_t lock; /* For serializing operations */
-
+
__u32 new_speed;
__u32 flags; /* Interface flags */
@@ -127,18 +143,20 @@ struct smsc_ircc_cb {
int tx_len; /* Number of frames in tx_buff */
int transceiver;
- struct pm_dev *pmdev;
+ struct platform_device *pldev;
};
/* Constants */
-static const char *driver_name = "smsc-ircc2";
-#define DIM(x) (sizeof(x)/(sizeof(*(x))))
+#define SMSC_IRCC2_DRIVER_NAME "smsc-ircc2"
+
#define SMSC_IRCC2_C_IRDA_FALLBACK_SPEED 9600
#define SMSC_IRCC2_C_DEFAULT_TRANSCEIVER 1
-#define SMSC_IRCC2_C_NET_TIMEOUT 0
+#define SMSC_IRCC2_C_NET_TIMEOUT 0
#define SMSC_IRCC2_C_SIR_STOP 0
+static const char *driver_name = SMSC_IRCC2_DRIVER_NAME;
+
/* Prototypes */
static int smsc_ircc_open(unsigned int firbase, unsigned int sirbase, u8 dma, u8 irq);
@@ -147,15 +165,15 @@ static void smsc_ircc_setup_io(struct smsc_ircc_cb *self, unsigned int fir_base,
static void smsc_ircc_setup_qos(struct smsc_ircc_cb *self);
static void smsc_ircc_init_chip(struct smsc_ircc_cb *self);
static int __exit smsc_ircc_close(struct smsc_ircc_cb *self);
-static int smsc_ircc_dma_receive(struct smsc_ircc_cb *self, int iobase);
-static void smsc_ircc_dma_receive_complete(struct smsc_ircc_cb *self, int iobase);
+static int smsc_ircc_dma_receive(struct smsc_ircc_cb *self);
+static void smsc_ircc_dma_receive_complete(struct smsc_ircc_cb *self);
static void smsc_ircc_sir_receive(struct smsc_ircc_cb *self);
static int smsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev);
static int smsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev);
-static void smsc_ircc_dma_xmit(struct smsc_ircc_cb *self, int iobase, int bofs);
-static void smsc_ircc_dma_xmit_complete(struct smsc_ircc_cb *self, int iobase);
-static void smsc_ircc_change_speed(void *priv, u32 speed);
-static void smsc_ircc_set_sir_speed(void *priv, u32 speed);
+static void smsc_ircc_dma_xmit(struct smsc_ircc_cb *self, int bofs);
+static void smsc_ircc_dma_xmit_complete(struct smsc_ircc_cb *self);
+static void smsc_ircc_change_speed(struct smsc_ircc_cb *self, u32 speed);
+static void smsc_ircc_set_sir_speed(struct smsc_ircc_cb *self, u32 speed);
static irqreturn_t smsc_ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static irqreturn_t smsc_ircc_interrupt_sir(struct net_device *dev);
static void smsc_ircc_sir_start(struct smsc_ircc_cb *self);
@@ -171,7 +189,6 @@ static int smsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cm
static void smsc_ircc_timeout(struct net_device *dev);
#endif
static struct net_device_stats *smsc_ircc_net_get_stats(struct net_device *dev);
-static int smsc_ircc_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data);
static int smsc_ircc_is_receiving(struct smsc_ircc_cb *self);
static void smsc_ircc_probe_transceiver(struct smsc_ircc_cb *self);
static void smsc_ircc_set_transceiver_for_speed(struct smsc_ircc_cb *self, u32 speed);
@@ -179,9 +196,9 @@ static void smsc_ircc_sir_wait_hw_transmitter_finish(struct smsc_ircc_cb *self);
/* Probing */
static int __init smsc_ircc_look_for_chips(void);
-static const smsc_chip_t * __init smsc_ircc_probe(unsigned short cfg_base,u8 reg,const smsc_chip_t *chip,char *type);
-static int __init smsc_superio_flat(const smsc_chip_t *chips, unsigned short cfg_base, char *type);
-static int __init smsc_superio_paged(const smsc_chip_t *chips, unsigned short cfg_base, char *type);
+static const struct smsc_chip * __init smsc_ircc_probe(unsigned short cfg_base, u8 reg, const struct smsc_chip *chip, char *type);
+static int __init smsc_superio_flat(const struct smsc_chip *chips, unsigned short cfg_base, char *type);
+static int __init smsc_superio_paged(const struct smsc_chip *chips, unsigned short cfg_base, char *type);
static int __init smsc_superio_fdc(unsigned short cfg_base);
static int __init smsc_superio_lpc(unsigned short cfg_base);
@@ -196,21 +213,26 @@ static int smsc_ircc_probe_transceiver_smsc_ircc_atc(int fir_base);
/* Power Management */
-static void smsc_ircc_suspend(struct smsc_ircc_cb *self);
-static void smsc_ircc_wakeup(struct smsc_ircc_cb *self);
-static int smsc_ircc_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data);
+static int smsc_ircc_suspend(struct device *dev, pm_message_t state, u32 level);
+static int smsc_ircc_resume(struct device *dev, u32 level);
+static struct device_driver smsc_ircc_driver = {
+ .name = SMSC_IRCC2_DRIVER_NAME,
+ .bus = &platform_bus_type,
+ .suspend = smsc_ircc_suspend,
+ .resume = smsc_ircc_resume,
+};
/* Transceivers for SMSC-ircc */
-static smsc_transceiver_t smsc_transceivers[]=
+static struct smsc_transceiver smsc_transceivers[] =
{
- { "Toshiba Satellite 1800 (GP data pin select)", smsc_ircc_set_transceiver_toshiba_sat1800, smsc_ircc_probe_transceiver_toshiba_sat1800},
- { "Fast pin select", smsc_ircc_set_transceiver_smsc_ircc_fast_pin_select, smsc_ircc_probe_transceiver_smsc_ircc_fast_pin_select},
- { "ATC IRMode", smsc_ircc_set_transceiver_smsc_ircc_atc, smsc_ircc_probe_transceiver_smsc_ircc_atc},
- { NULL, NULL}
+ { "Toshiba Satellite 1800 (GP data pin select)", smsc_ircc_set_transceiver_toshiba_sat1800, smsc_ircc_probe_transceiver_toshiba_sat1800 },
+ { "Fast pin select", smsc_ircc_set_transceiver_smsc_ircc_fast_pin_select, smsc_ircc_probe_transceiver_smsc_ircc_fast_pin_select },
+ { "ATC IRMode", smsc_ircc_set_transceiver_smsc_ircc_atc, smsc_ircc_probe_transceiver_smsc_ircc_atc },
+ { NULL, NULL }
};
-#define SMSC_IRCC2_C_NUMBER_OF_TRANSCEIVERS (DIM(smsc_transceivers)-1)
+#define SMSC_IRCC2_C_NUMBER_OF_TRANSCEIVERS (ARRAY_SIZE(smsc_transceivers) - 1)
/* SMC SuperIO chipsets definitions */
@@ -221,7 +243,7 @@ static smsc_transceiver_t smsc_transceivers[]=
#define FIR 4 /* SuperIO Chip has fast IRDA */
#define SERx4 8 /* SuperIO Chip supports 115,2 KBaud * 4=460,8 KBaud */
-static smsc_chip_t __initdata fdc_chips_flat[]=
+static struct smsc_chip __initdata fdc_chips_flat[] =
{
/* Base address 0x3f0 or 0x370 */
{ "37C44", KEY55_1|NoIRDA, 0x00, 0x00 }, /* This chip cannot be detected */
@@ -235,7 +257,7 @@ static smsc_chip_t __initdata fdc_chips_flat[]=
{ NULL }
};
-static smsc_chip_t __initdata fdc_chips_paged[]=
+static struct smsc_chip __initdata fdc_chips_paged[] =
{
/* Base address 0x3f0 or 0x370 */
{ "37B72X", KEY55_1|SIR|SERx4, 0x4c, 0x00 },
@@ -254,7 +276,7 @@ static smsc_chip_t __initdata fdc_chips_paged[]=
{ NULL }
};
-static smsc_chip_t __initdata lpc_chips_flat[]=
+static struct smsc_chip __initdata lpc_chips_flat[] =
{
/* Base address 0x2E or 0x4E */
{ "47N227", KEY55_1|FIR|SERx4, 0x5a, 0x00 },
@@ -262,7 +284,7 @@ static smsc_chip_t __initdata lpc_chips_flat[]=
{ NULL }
};
-static smsc_chip_t __initdata lpc_chips_paged[]=
+static struct smsc_chip __initdata lpc_chips_paged[] =
{
/* Base address 0x2E or 0x4E */
{ "47B27X", KEY55_1|SIR|SERx4, 0x51, 0x00 },
@@ -281,33 +303,25 @@ static smsc_chip_t __initdata lpc_chips_paged[]=
#define SMSCSIO_TYPE_FLAT 4
#define SMSCSIO_TYPE_PAGED 8
-static smsc_chip_address_t __initdata possible_addresses[]=
+static struct smsc_chip_address __initdata possible_addresses[] =
{
- {0x3f0, SMSCSIO_TYPE_FDC|SMSCSIO_TYPE_FLAT|SMSCSIO_TYPE_PAGED},
- {0x370, SMSCSIO_TYPE_FDC|SMSCSIO_TYPE_FLAT|SMSCSIO_TYPE_PAGED},
- {0xe0, SMSCSIO_TYPE_FDC|SMSCSIO_TYPE_FLAT|SMSCSIO_TYPE_PAGED},
- {0x2e, SMSCSIO_TYPE_LPC|SMSCSIO_TYPE_FLAT|SMSCSIO_TYPE_PAGED},
- {0x4e, SMSCSIO_TYPE_LPC|SMSCSIO_TYPE_FLAT|SMSCSIO_TYPE_PAGED},
- {0,0}
+ { 0x3f0, SMSCSIO_TYPE_FDC|SMSCSIO_TYPE_FLAT|SMSCSIO_TYPE_PAGED },
+ { 0x370, SMSCSIO_TYPE_FDC|SMSCSIO_TYPE_FLAT|SMSCSIO_TYPE_PAGED },
+ { 0xe0, SMSCSIO_TYPE_FDC|SMSCSIO_TYPE_FLAT|SMSCSIO_TYPE_PAGED },
+ { 0x2e, SMSCSIO_TYPE_LPC|SMSCSIO_TYPE_FLAT|SMSCSIO_TYPE_PAGED },
+ { 0x4e, SMSCSIO_TYPE_LPC|SMSCSIO_TYPE_FLAT|SMSCSIO_TYPE_PAGED },
+ { 0, 0 }
};
/* Globals */
-static struct smsc_ircc_cb *dev_self[] = { NULL, NULL};
-
-static int ircc_irq=255;
-static int ircc_dma=255;
-static int ircc_fir=0;
-static int ircc_sir=0;
-static int ircc_cfg=0;
-static int ircc_transceiver=0;
-
-static unsigned short dev_count=0;
+static struct smsc_ircc_cb *dev_self[] = { NULL, NULL };
+static unsigned short dev_count;
static inline void register_bank(int iobase, int bank)
{
- outb(((inb(iobase+IRCC_MASTER) & 0xf0) | (bank & 0x07)),
- iobase+IRCC_MASTER);
+ outb(((inb(iobase + IRCC_MASTER) & 0xf0) | (bank & 0x07)),
+ iobase + IRCC_MASTER);
}
@@ -327,34 +341,44 @@ static inline void register_bank(int iobase, int bank)
*/
static int __init smsc_ircc_init(void)
{
- int ret=-ENODEV;
+ int ret;
IRDA_DEBUG(1, "%s\n", __FUNCTION__);
- dev_count=0;
-
- if ((ircc_fir>0)&&(ircc_sir>0)) {
+ ret = driver_register(&smsc_ircc_driver);
+ if (ret) {
+ IRDA_ERROR("%s, Can't register driver!\n", driver_name);
+ return ret;
+ }
+
+ dev_count = 0;
+
+ if (ircc_fir > 0 && ircc_sir > 0) {
IRDA_MESSAGE(" Overriding FIR address 0x%04x\n", ircc_fir);
IRDA_MESSAGE(" Overriding SIR address 0x%04x\n", ircc_sir);
- if (smsc_ircc_open(ircc_fir, ircc_sir, ircc_dma, ircc_irq) == 0)
- return 0;
-
- return -ENODEV;
- }
+ if (smsc_ircc_open(ircc_fir, ircc_sir, ircc_dma, ircc_irq))
+ ret = -ENODEV;
+ } else {
+ ret = -ENODEV;
+
+ /* try user provided configuration register base address */
+ if (ircc_cfg > 0) {
+ IRDA_MESSAGE(" Overriding configuration address "
+ "0x%04x\n", ircc_cfg);
+ if (!smsc_superio_fdc(ircc_cfg))
+ ret = 0;
+ if (!smsc_superio_lpc(ircc_cfg))
+ ret = 0;
+ }
- /* try user provided configuration register base address */
- if (ircc_cfg>0) {
- IRDA_MESSAGE(" Overriding configuration address 0x%04x\n",
- ircc_cfg);
- if (!smsc_superio_fdc(ircc_cfg))
- ret = 0;
- if (!smsc_superio_lpc(ircc_cfg))
+ if (smsc_ircc_look_for_chips() > 0)
ret = 0;
}
-
- if(smsc_ircc_look_for_chips()>0) ret = 0;
-
+
+ if (ret)
+ driver_unregister(&smsc_ircc_driver);
+
return ret;
}
@@ -369,15 +393,15 @@ static int __init smsc_ircc_open(unsigned int fir_base, unsigned int sir_base, u
struct smsc_ircc_cb *self;
struct net_device *dev;
int err;
-
+
IRDA_DEBUG(1, "%s\n", __FUNCTION__);
err = smsc_ircc_present(fir_base, sir_base);
- if(err)
+ if (err)
goto err_out;
-
+
err = -ENOMEM;
- if (dev_count > DIM(dev_self)) {
+ if (dev_count >= ARRAY_SIZE(dev_self)) {
IRDA_WARNING("%s(), too many devices!\n", __FUNCTION__);
goto err_out1;
}
@@ -396,14 +420,14 @@ static int __init smsc_ircc_open(unsigned int fir_base, unsigned int sir_base, u
dev->hard_start_xmit = smsc_ircc_hard_xmit_sir;
#if SMSC_IRCC2_C_NET_TIMEOUT
dev->tx_timeout = smsc_ircc_timeout;
- dev->watchdog_timeo = HZ*2; /* Allow enough time for speed change */
+ dev->watchdog_timeo = HZ * 2; /* Allow enough time for speed change */
#endif
dev->open = smsc_ircc_net_open;
dev->stop = smsc_ircc_net_close;
dev->do_ioctl = smsc_ircc_net_ioctl;
dev->get_stats = smsc_ircc_net_get_stats;
-
- self = dev->priv;
+
+ self = netdev_priv(dev);
self->netdev = dev;
/* Make ifconfig display some details */
@@ -411,10 +435,10 @@ static int __init smsc_ircc_open(unsigned int fir_base, unsigned int sir_base, u
dev->irq = self->io.irq = irq;
/* Need to store self somewhere */
- dev_self[dev_count++] = self;
+ dev_self[dev_count] = self;
spin_lock_init(&self->lock);
- self->rx_buff.truesize = SMSC_IRCC2_RX_BUFF_TRUESIZE;
+ self->rx_buff.truesize = SMSC_IRCC2_RX_BUFF_TRUESIZE;
self->tx_buff.truesize = SMSC_IRCC2_TX_BUFF_TRUESIZE;
self->rx_buff.head =
@@ -442,33 +466,40 @@ static int __init smsc_ircc_open(unsigned int fir_base, unsigned int sir_base, u
self->rx_buff.state = OUTSIDE_FRAME;
self->tx_buff.data = self->tx_buff.head;
self->rx_buff.data = self->rx_buff.head;
-
- smsc_ircc_setup_io(self, fir_base, sir_base, dma, irq);
+ smsc_ircc_setup_io(self, fir_base, sir_base, dma, irq);
smsc_ircc_setup_qos(self);
-
smsc_ircc_init_chip(self);
-
- if(ircc_transceiver > 0 &&
- ircc_transceiver < SMSC_IRCC2_C_NUMBER_OF_TRANSCEIVERS)
+
+ if (ircc_transceiver > 0 &&
+ ircc_transceiver < SMSC_IRCC2_C_NUMBER_OF_TRANSCEIVERS)
self->transceiver = ircc_transceiver;
else
smsc_ircc_probe_transceiver(self);
err = register_netdev(self->netdev);
- if(err) {
+ if (err) {
IRDA_ERROR("%s, Network device registration failed!\n",
driver_name);
goto err_out4;
}
- self->pmdev = pm_register(PM_SYS_DEV, PM_SYS_IRDA, smsc_ircc_pmproc);
- if (self->pmdev)
- self->pmdev->data = self;
+ self->pldev = platform_device_register_simple(SMSC_IRCC2_DRIVER_NAME,
+ dev_count, NULL, 0);
+ if (IS_ERR(self->pldev)) {
+ err = PTR_ERR(self->pldev);
+ goto err_out5;
+ }
+ dev_set_drvdata(&self->pldev->dev, self);
IRDA_MESSAGE("IrDA: Registered device %s\n", dev->name);
+ dev_count++;
return 0;
+
+ err_out5:
+ unregister_netdev(self->netdev);
+
err_out4:
dma_free_coherent(NULL, self->tx_buff.truesize,
self->tx_buff.head, self->tx_buff_dma);
@@ -477,7 +508,7 @@ static int __init smsc_ircc_open(unsigned int fir_base, unsigned int sir_base, u
self->rx_buff.head, self->rx_buff_dma);
err_out2:
free_netdev(self->netdev);
- dev_self[--dev_count] = NULL;
+ dev_self[dev_count] = NULL;
err_out1:
release_region(fir_base, SMSC_IRCC2_FIR_CHIP_IO_EXTENT);
release_region(sir_base, SMSC_IRCC2_SIR_CHIP_IO_EXTENT);
@@ -511,16 +542,16 @@ static int smsc_ircc_present(unsigned int fir_base, unsigned int sir_base)
register_bank(fir_base, 3);
- high = inb(fir_base+IRCC_ID_HIGH);
- low = inb(fir_base+IRCC_ID_LOW);
- chip = inb(fir_base+IRCC_CHIP_ID);
- version = inb(fir_base+IRCC_VERSION);
- config = inb(fir_base+IRCC_INTERFACE);
+ high = inb(fir_base + IRCC_ID_HIGH);
+ low = inb(fir_base + IRCC_ID_LOW);
+ chip = inb(fir_base + IRCC_CHIP_ID);
+ version = inb(fir_base + IRCC_VERSION);
+ config = inb(fir_base + IRCC_INTERFACE);
dma = config & IRCC_INTERFACE_DMA_MASK;
irq = (config & IRCC_INTERFACE_IRQ_MASK) >> 4;
- if (high != 0x10 || low != 0xb8 || (chip != 0xf1 && chip != 0xf2)) {
- IRDA_WARNING("%s(), addr 0x%04x - no device found!\n",
+ if (high != 0x10 || low != 0xb8 || (chip != 0xf1 && chip != 0xf2)) {
+ IRDA_WARNING("%s(), addr 0x%04x - no device found!\n",
__FUNCTION__, fir_base);
goto out3;
}
@@ -529,6 +560,7 @@ static int smsc_ircc_present(unsigned int fir_base, unsigned int sir_base)
chip & 0x0f, version, fir_base, sir_base, dma, irq);
return 0;
+
out3:
release_region(sir_base, SMSC_IRCC2_SIR_CHIP_IO_EXTENT);
out2:
@@ -543,16 +575,16 @@ static int smsc_ircc_present(unsigned int fir_base, unsigned int sir_base)
* Setup I/O
*
*/
-static void smsc_ircc_setup_io(struct smsc_ircc_cb *self,
- unsigned int fir_base, unsigned int sir_base,
+static void smsc_ircc_setup_io(struct smsc_ircc_cb *self,
+ unsigned int fir_base, unsigned int sir_base,
u8 dma, u8 irq)
{
unsigned char config, chip_dma, chip_irq;
register_bank(fir_base, 3);
- config = inb(fir_base+IRCC_INTERFACE);
- chip_dma = config & IRCC_INTERFACE_DMA_MASK;
- chip_irq = (config & IRCC_INTERFACE_IRQ_MASK) >> 4;
+ config = inb(fir_base + IRCC_INTERFACE);
+ chip_dma = config & IRCC_INTERFACE_DMA_MASK;
+ chip_irq = (config & IRCC_INTERFACE_IRQ_MASK) >> 4;
self->io.fir_base = fir_base;
self->io.sir_base = sir_base;
@@ -566,17 +598,15 @@ static void smsc_ircc_setup_io(struct smsc_ircc_cb *self,
IRDA_MESSAGE("%s, Overriding IRQ - chip says %d, using %d\n",
driver_name, chip_irq, irq);
self->io.irq = irq;
- }
- else
+ } else
self->io.irq = chip_irq;
-
+
if (dma < 255) {
if (dma != chip_dma)
IRDA_MESSAGE("%s, Overriding DMA - chip says %d, using %d\n",
driver_name, chip_dma, dma);
self->io.dma = dma;
- }
- else
+ } else
self->io.dma = chip_dma;
}
@@ -591,7 +621,7 @@ static void smsc_ircc_setup_qos(struct smsc_ircc_cb *self)
{
/* Initialize QoS for this device */
irda_init_max_qos_capabilies(&self->qos);
-
+
self->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600|
IR_115200|IR_576000|IR_1152000|(IR_4000000 << 8);
@@ -608,43 +638,43 @@ static void smsc_ircc_setup_qos(struct smsc_ircc_cb *self)
*/
static void smsc_ircc_init_chip(struct smsc_ircc_cb *self)
{
- int iobase, ir_mode, ctrl, fast;
-
- IRDA_ASSERT( self != NULL, return; );
- iobase = self->io.fir_base;
+ int iobase, ir_mode, ctrl, fast;
+
+ IRDA_ASSERT(self != NULL, return;);
+ iobase = self->io.fir_base;
ir_mode = IRCC_CFGA_IRDA_SIR_A;
ctrl = 0;
fast = 0;
register_bank(iobase, 0);
- outb(IRCC_MASTER_RESET, iobase+IRCC_MASTER);
- outb(0x00, iobase+IRCC_MASTER);
+ outb(IRCC_MASTER_RESET, iobase + IRCC_MASTER);
+ outb(0x00, iobase + IRCC_MASTER);
register_bank(iobase, 1);
- outb(((inb(iobase+IRCC_SCE_CFGA) & 0x87) | ir_mode),
- iobase+IRCC_SCE_CFGA);
+ outb(((inb(iobase + IRCC_SCE_CFGA) & 0x87) | ir_mode),
+ iobase + IRCC_SCE_CFGA);
#ifdef smsc_669 /* Uses pin 88/89 for Rx/Tx */
- outb(((inb(iobase+IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_COM),
- iobase+IRCC_SCE_CFGB);
-#else
- outb(((inb(iobase+IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_IR),
- iobase+IRCC_SCE_CFGB);
-#endif
- (void) inb(iobase+IRCC_FIFO_THRESHOLD);
- outb(SMSC_IRCC2_FIFO_THRESHOLD, iobase+IRCC_FIFO_THRESHOLD);
-
+ outb(((inb(iobase + IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_COM),
+ iobase + IRCC_SCE_CFGB);
+#else
+ outb(((inb(iobase + IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_IR),
+ iobase + IRCC_SCE_CFGB);
+#endif
+ (void) inb(iobase + IRCC_FIFO_THRESHOLD);
+ outb(SMSC_IRCC2_FIFO_THRESHOLD, iobase + IRCC_FIFO_THRESHOLD);
+
register_bank(iobase, 4);
- outb((inb(iobase+IRCC_CONTROL) & 0x30) | ctrl, iobase+IRCC_CONTROL);
-
+ outb((inb(iobase + IRCC_CONTROL) & 0x30) | ctrl, iobase + IRCC_CONTROL);
+
register_bank(iobase, 0);
- outb(fast, iobase+IRCC_LCR_A);
+ outb(fast, iobase + IRCC_LCR_A);
smsc_ircc_set_sir_speed(self, SMSC_IRCC2_C_IRDA_FALLBACK_SPEED);
-
+
/* Power on device */
- outb(0x00, iobase+IRCC_MASTER);
+ outb(0x00, iobase + IRCC_MASTER);
}
/*
@@ -662,12 +692,12 @@ static int smsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd
IRDA_ASSERT(dev != NULL, return -1;);
- self = dev->priv;
+ self = netdev_priv(dev);
IRDA_ASSERT(self != NULL, return -1;);
IRDA_DEBUG(2, "%s(), %s, (cmd=0x%X)\n", __FUNCTION__, dev->name, cmd);
-
+
switch (cmd) {
case SIOCSBANDWIDTH: /* Set bandwidth */
if (!capable(CAP_NET_ADMIN))
@@ -703,14 +733,14 @@ static int smsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd
default:
ret = -EOPNOTSUPP;
}
-
+
return ret;
}
static struct net_device_stats *smsc_ircc_net_get_stats(struct net_device *dev)
{
- struct smsc_ircc_cb *self = (struct smsc_ircc_cb *) dev->priv;
-
+ struct smsc_ircc_cb *self = netdev_priv(dev);
+
return &self->stats;
}
@@ -724,11 +754,9 @@ static struct net_device_stats *smsc_ircc_net_get_stats(struct net_device *dev)
static void smsc_ircc_timeout(struct net_device *dev)
{
- struct smsc_ircc_cb *self;
+ struct smsc_ircc_cb *self = netdev_priv(dev);
unsigned long flags;
- self = (struct smsc_ircc_cb *) dev->priv;
-
IRDA_WARNING("%s: transmit timed out, changing speed to: %d\n",
dev->name, self->io.speed);
spin_lock_irqsave(&self->lock, flags);
@@ -751,26 +779,23 @@ int smsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev)
{
struct smsc_ircc_cb *self;
unsigned long flags;
- int iobase;
s32 speed;
IRDA_DEBUG(1, "%s\n", __FUNCTION__);
IRDA_ASSERT(dev != NULL, return 0;);
-
- self = (struct smsc_ircc_cb *) dev->priv;
- IRDA_ASSERT(self != NULL, return 0;);
- iobase = self->io.sir_base;
+ self = netdev_priv(dev);
+ IRDA_ASSERT(self != NULL, return 0;);
netif_stop_queue(dev);
-
+
/* Make sure test of self->io.speed & speed change are atomic */
spin_lock_irqsave(&self->lock, flags);
/* Check if we need to change the speed */
speed = irda_get_next_speed(skb);
- if ((speed != self->io.speed) && (speed != -1)) {
+ if (speed != self->io.speed && speed != -1) {
/* Check for empty frame */
if (!skb->len) {
/*
@@ -787,27 +812,26 @@ int smsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev)
spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb);
return 0;
- } else {
- self->new_speed = speed;
}
+ self->new_speed = speed;
}
/* Init tx buffer */
self->tx_buff.data = self->tx_buff.head;
/* Copy skb to tx_buff while wrapping, stuffing and making CRC */
- self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data,
+ self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data,
self->tx_buff.truesize);
-
+
self->stats.tx_bytes += self->tx_buff.len;
/* Turn on transmit finished interrupt. Will fire immediately! */
- outb(UART_IER_THRI, iobase+UART_IER);
+ outb(UART_IER_THRI, self->io.sir_base + UART_IER);
spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb);
-
+
return 0;
}
@@ -826,9 +850,9 @@ static void smsc_ircc_set_fir_speed(struct smsc_ircc_cb *self, u32 speed)
self->io.speed = speed;
- switch(speed) {
+ switch (speed) {
default:
- case 576000:
+ case 576000:
ir_mode = IRCC_CFGA_IRDA_HDLC;
ctrl = IRCC_CRC;
fast = 0;
@@ -853,14 +877,14 @@ static void smsc_ircc_set_fir_speed(struct smsc_ircc_cb *self, u32 speed)
Now in tranceiver!
/* This causes an interrupt */
register_bank(fir_base, 0);
- outb((inb(fir_base+IRCC_LCR_A) & 0xbf) | fast, fir_base+IRCC_LCR_A);
+ outb((inb(fir_base + IRCC_LCR_A) & 0xbf) | fast, fir_base + IRCC_LCR_A);
#endif
-
+
register_bank(fir_base, 1);
- outb(((inb(fir_base+IRCC_SCE_CFGA) & IRCC_SCE_CFGA_BLOCK_CTRL_BITS_MASK) | ir_mode), fir_base+IRCC_SCE_CFGA);
-
+ outb(((inb(fir_base + IRCC_SCE_CFGA) & IRCC_SCE_CFGA_BLOCK_CTRL_BITS_MASK) | ir_mode), fir_base + IRCC_SCE_CFGA);
+
register_bank(fir_base, 4);
- outb((inb(fir_base+IRCC_CONTROL) & 0x30) | ctrl, fir_base+IRCC_CONTROL);
+ outb((inb(fir_base + IRCC_CONTROL) & 0x30) | ctrl, fir_base + IRCC_CONTROL);
}
/*
@@ -885,31 +909,31 @@ static void smsc_ircc_fir_start(struct smsc_ircc_cb *self)
/* Reset everything */
/* Install FIR transmit handler */
- dev->hard_start_xmit = smsc_ircc_hard_xmit_fir;
+ dev->hard_start_xmit = smsc_ircc_hard_xmit_fir;
/* Clear FIFO */
- outb(inb(fir_base+IRCC_LCR_A)|IRCC_LCR_A_FIFO_RESET, fir_base+IRCC_LCR_A);
+ outb(inb(fir_base + IRCC_LCR_A) | IRCC_LCR_A_FIFO_RESET, fir_base + IRCC_LCR_A);
/* Enable interrupt */
- /*outb(IRCC_IER_ACTIVE_FRAME|IRCC_IER_EOM, fir_base+IRCC_IER);*/
+ /*outb(IRCC_IER_ACTIVE_FRAME|IRCC_IER_EOM, fir_base + IRCC_IER);*/
register_bank(fir_base, 1);
- /* Select the TX/RX interface */
+ /* Select the TX/RX interface */
#ifdef SMSC_669 /* Uses pin 88/89 for Rx/Tx */
- outb(((inb(fir_base+IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_COM),
- fir_base+IRCC_SCE_CFGB);
-#else
- outb(((inb(fir_base+IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_IR),
- fir_base+IRCC_SCE_CFGB);
-#endif
- (void) inb(fir_base+IRCC_FIFO_THRESHOLD);
+ outb(((inb(fir_base + IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_COM),
+ fir_base + IRCC_SCE_CFGB);
+#else
+ outb(((inb(fir_base + IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_IR),
+ fir_base + IRCC_SCE_CFGB);
+#endif
+ (void) inb(fir_base + IRCC_FIFO_THRESHOLD);
/* Enable SCE interrupts */
- outb(0, fir_base+IRCC_MASTER);
+ outb(0, fir_base + IRCC_MASTER);
register_bank(fir_base, 0);
- outb(IRCC_IER_ACTIVE_FRAME|IRCC_IER_EOM, fir_base+IRCC_IER);
- outb(IRCC_MASTER_INT_EN, fir_base+IRCC_MASTER);
+ outb(IRCC_IER_ACTIVE_FRAME | IRCC_IER_EOM, fir_base + IRCC_IER);
+ outb(IRCC_MASTER_INT_EN, fir_base + IRCC_MASTER);
}
/*
@@ -923,13 +947,13 @@ static void smsc_ircc_fir_stop(struct smsc_ircc_cb *self)
int fir_base;
IRDA_DEBUG(1, "%s\n", __FUNCTION__);
-
+
IRDA_ASSERT(self != NULL, return;);
fir_base = self->io.fir_base;
register_bank(fir_base, 0);
- /*outb(IRCC_MASTER_RESET, fir_base+IRCC_MASTER);*/
- outb(inb(fir_base+IRCC_LCR_B) & IRCC_LCR_B_SIP_ENABLE, fir_base+IRCC_LCR_B);
+ /*outb(IRCC_MASTER_RESET, fir_base + IRCC_MASTER);*/
+ outb(inb(fir_base + IRCC_LCR_B) & IRCC_LCR_B_SIP_ENABLE, fir_base + IRCC_LCR_B);
}
@@ -941,18 +965,15 @@ static void smsc_ircc_fir_stop(struct smsc_ircc_cb *self)
* This function *must* be called with spinlock held, because it may
* be called from the irq handler. - Jean II
*/
-static void smsc_ircc_change_speed(void *priv, u32 speed)
+static void smsc_ircc_change_speed(struct smsc_ircc_cb *self, u32 speed)
{
- struct smsc_ircc_cb *self = (struct smsc_ircc_cb *) priv;
struct net_device *dev;
- int iobase;
int last_speed_was_sir;
-
+
IRDA_DEBUG(0, "%s() changing speed to: %d\n", __FUNCTION__, speed);
IRDA_ASSERT(self != NULL, return;);
dev = self->netdev;
- iobase = self->io.fir_base;
last_speed_was_sir = self->io.speed <= SMSC_IRCC2_MAX_SIR_SPEED;
@@ -961,30 +982,30 @@ static void smsc_ircc_change_speed(void *priv, u32 speed)
speed= 1152000;
self->io.speed = speed;
last_speed_was_sir = 0;
- smsc_ircc_fir_start(self);
+ smsc_ircc_fir_start(self);
#endif
-
- if(self->io.speed == 0)
+
+ if (self->io.speed == 0)
smsc_ircc_sir_start(self);
#if 0
- if(!last_speed_was_sir) speed = self->io.speed;
+ if (!last_speed_was_sir) speed = self->io.speed;
#endif
- if(self->io.speed != speed) smsc_ircc_set_transceiver_for_speed(self, speed);
+ if (self->io.speed != speed)
+ smsc_ircc_set_transceiver_for_speed(self, speed);
self->io.speed = speed;
-
- if(speed <= SMSC_IRCC2_MAX_SIR_SPEED) {
- if(!last_speed_was_sir) {
+
+ if (speed <= SMSC_IRCC2_MAX_SIR_SPEED) {
+ if (!last_speed_was_sir) {
smsc_ircc_fir_stop(self);
smsc_ircc_sir_start(self);
}
- smsc_ircc_set_sir_speed(self, speed);
- }
- else {
- if(last_speed_was_sir) {
- #if SMSC_IRCC2_C_SIR_STOP
+ smsc_ircc_set_sir_speed(self, speed);
+ } else {
+ if (last_speed_was_sir) {
+ #if SMSC_IRCC2_C_SIR_STOP
smsc_ircc_sir_stop(self);
#endif
smsc_ircc_fir_start(self);
@@ -994,13 +1015,13 @@ static void smsc_ircc_change_speed(void *priv, u32 speed)
#if 0
self->tx_buff.len = 10;
self->tx_buff.data = self->tx_buff.head;
-
- smsc_ircc_dma_xmit(self, iobase, 4000);
+
+ smsc_ircc_dma_xmit(self, 4000);
#endif
/* Be ready for incoming frames */
- smsc_ircc_dma_receive(self, iobase);
+ smsc_ircc_dma_receive(self);
}
-
+
netif_wake_queue(dev);
}
@@ -1010,10 +1031,9 @@ static void smsc_ircc_change_speed(void *priv, u32 speed)
* Set speed of IrDA port to specified baudrate
*
*/
-void smsc_ircc_set_sir_speed(void *priv, __u32 speed)
+void smsc_ircc_set_sir_speed(struct smsc_ircc_cb *self, __u32 speed)
{
- struct smsc_ircc_cb *self = (struct smsc_ircc_cb *) priv;
- int iobase;
+ int iobase;
int fcr; /* FIFO control reg */
int lcr; /* Line control reg */
int divisor;
@@ -1022,38 +1042,36 @@ void smsc_ircc_set_sir_speed(void *priv, __u32 speed)
IRDA_ASSERT(self != NULL, return;);
iobase = self->io.sir_base;
-
+
/* Update accounting for new speed */
self->io.speed = speed;
/* Turn off interrupts */
- outb(0, iobase+UART_IER);
+ outb(0, iobase + UART_IER);
+
+ divisor = SMSC_IRCC2_MAX_SIR_SPEED / speed;
- divisor = SMSC_IRCC2_MAX_SIR_SPEED/speed;
-
fcr = UART_FCR_ENABLE_FIFO;
- /*
+ /*
* Use trigger level 1 to avoid 3 ms. timeout delay at 9600 bps, and
* almost 1,7 ms at 19200 bps. At speeds above that we can just forget
- * about this timeout since it will always be fast enough.
+ * about this timeout since it will always be fast enough.
*/
- if (self->io.speed < 38400)
- fcr |= UART_FCR_TRIGGER_1;
- else
- fcr |= UART_FCR_TRIGGER_14;
-
+ fcr |= self->io.speed < 38400 ?
+ UART_FCR_TRIGGER_1 : UART_FCR_TRIGGER_14;
+
/* IrDA ports use 8N1 */
lcr = UART_LCR_WLEN8;
-
- outb(UART_LCR_DLAB | lcr, iobase+UART_LCR); /* Set DLAB */
- outb(divisor & 0xff, iobase+UART_DLL); /* Set speed */
- outb(divisor >> 8, iobase+UART_DLM);
- outb(lcr, iobase+UART_LCR); /* Set 8N1 */
- outb(fcr, iobase+UART_FCR); /* Enable FIFO's */
+
+ outb(UART_LCR_DLAB | lcr, iobase + UART_LCR); /* Set DLAB */
+ outb(divisor & 0xff, iobase + UART_DLL); /* Set speed */
+ outb(divisor >> 8, iobase + UART_DLM);
+ outb(lcr, iobase + UART_LCR); /* Set 8N1 */
+ outb(fcr, iobase + UART_FCR); /* Enable FIFO's */
/* Turn on interrups */
- outb(UART_IER_RLSI|UART_IER_RDI|UART_IER_THRI, iobase+UART_IER);
+ outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER);
IRDA_DEBUG(2, "%s() speed changed to: %d\n", __FUNCTION__, speed);
}
@@ -1070,15 +1088,12 @@ static int smsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev)
struct smsc_ircc_cb *self;
unsigned long flags;
s32 speed;
- int iobase;
int mtt;
IRDA_ASSERT(dev != NULL, return 0;);
- self = (struct smsc_ircc_cb *) dev->priv;
+ self = netdev_priv(dev);
IRDA_ASSERT(self != NULL, return 0;);
- iobase = self->io.fir_base;
-
netif_stop_queue(dev);
/* Make sure test of self->io.speed & speed change are atomic */
@@ -1086,30 +1101,31 @@ static int smsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev)
/* Check if we need to change the speed after this frame */
speed = irda_get_next_speed(skb);
- if ((speed != self->io.speed) && (speed != -1)) {
+ if (speed != self->io.speed && speed != -1) {
/* Check for empty frame */
if (!skb->len) {
/* Note : you should make sure that speed changes
* are not going to corrupt any outgoing frame.
* Look at nsc-ircc for the gory details - Jean II */
- smsc_ircc_change_speed(self, speed);
+ smsc_ircc_change_speed(self, speed);
spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb);
return 0;
- } else
- self->new_speed = speed;
+ }
+
+ self->new_speed = speed;
}
-
+
memcpy(self->tx_buff.head, skb->data, skb->len);
self->tx_buff.len = skb->len;
self->tx_buff.data = self->tx_buff.head;
-
- mtt = irda_get_mtt(skb);
+
+ mtt = irda_get_mtt(skb);
if (mtt) {
int bofs;
- /*
+ /*
* Compute how many BOFs (STA or PA's) we need to waste the
* min turn time given the speed of the link.
*/
@@ -1117,11 +1133,12 @@ static int smsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev)
if (bofs > 4095)
bofs = 4095;
- smsc_ircc_dma_xmit(self, iobase, bofs);
+ smsc_ircc_dma_xmit(self, bofs);
} else {
/* Transmit frame */
- smsc_ircc_dma_xmit(self, iobase, 0);
+ smsc_ircc_dma_xmit(self, 0);
}
+
spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb);
@@ -1129,43 +1146,44 @@ static int smsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev)
}
/*
- * Function smsc_ircc_dma_xmit (self, iobase)
+ * Function smsc_ircc_dma_xmit (self, bofs)
*
* Transmit data using DMA
*
*/
-static void smsc_ircc_dma_xmit(struct smsc_ircc_cb *self, int iobase, int bofs)
+static void smsc_ircc_dma_xmit(struct smsc_ircc_cb *self, int bofs)
{
+ int iobase = self->io.fir_base;
u8 ctrl;
IRDA_DEBUG(3, "%s\n", __FUNCTION__);
#if 1
/* Disable Rx */
register_bank(iobase, 0);
- outb(0x00, iobase+IRCC_LCR_B);
+ outb(0x00, iobase + IRCC_LCR_B);
#endif
register_bank(iobase, 1);
- outb(inb(iobase+IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE,
- iobase+IRCC_SCE_CFGB);
+ outb(inb(iobase + IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE,
+ iobase + IRCC_SCE_CFGB);
self->io.direction = IO_XMIT;
/* Set BOF additional count for generating the min turn time */
register_bank(iobase, 4);
- outb(bofs & 0xff, iobase+IRCC_BOF_COUNT_LO);
- ctrl = inb(iobase+IRCC_CONTROL) & 0xf0;
- outb(ctrl | ((bofs >> 8) & 0x0f), iobase+IRCC_BOF_COUNT_HI);
+ outb(bofs & 0xff, iobase + IRCC_BOF_COUNT_LO);
+ ctrl = inb(iobase + IRCC_CONTROL) & 0xf0;
+ outb(ctrl | ((bofs >> 8) & 0x0f), iobase + IRCC_BOF_COUNT_HI);
/* Set max Tx frame size */
- outb(self->tx_buff.len >> 8, iobase+IRCC_TX_SIZE_HI);
- outb(self->tx_buff.len & 0xff, iobase+IRCC_TX_SIZE_LO);
+ outb(self->tx_buff.len >> 8, iobase + IRCC_TX_SIZE_HI);
+ outb(self->tx_buff.len & 0xff, iobase + IRCC_TX_SIZE_LO);
/*outb(UART_MCR_OUT2, self->io.sir_base + UART_MCR);*/
-
+
/* Enable burst mode chip Tx DMA */
register_bank(iobase, 1);
- outb(inb(iobase+IRCC_SCE_CFGB) | IRCC_CFGB_DMA_ENABLE |
- IRCC_CFGB_DMA_BURST, iobase+IRCC_SCE_CFGB);
+ outb(inb(iobase + IRCC_SCE_CFGB) | IRCC_CFGB_DMA_ENABLE |
+ IRCC_CFGB_DMA_BURST, iobase + IRCC_SCE_CFGB);
/* Setup DMA controller (must be done after enabling chip DMA) */
irda_setup_dma(self->io.dma, self->tx_buff_dma, self->tx_buff.len,
@@ -1174,50 +1192,52 @@ static void smsc_ircc_dma_xmit(struct smsc_ircc_cb *self, int iobase, int bofs)
/* Enable interrupt */
register_bank(iobase, 0);
- outb(IRCC_IER_ACTIVE_FRAME | IRCC_IER_EOM, iobase+IRCC_IER);
- outb(IRCC_MASTER_INT_EN, iobase+IRCC_MASTER);
-
+ outb(IRCC_IER_ACTIVE_FRAME | IRCC_IER_EOM, iobase + IRCC_IER);
+ outb(IRCC_MASTER_INT_EN, iobase + IRCC_MASTER);
+
/* Enable transmit */
- outb(IRCC_LCR_B_SCE_TRANSMIT | IRCC_LCR_B_SIP_ENABLE, iobase+IRCC_LCR_B);
+ outb(IRCC_LCR_B_SCE_TRANSMIT | IRCC_LCR_B_SIP_ENABLE, iobase + IRCC_LCR_B);
}
/*
* Function smsc_ircc_dma_xmit_complete (self)
*
- * The transfer of a frame in finished. This function will only be called
+ * The transfer of a frame in finished. This function will only be called
* by the interrupt handler
*
*/
-static void smsc_ircc_dma_xmit_complete(struct smsc_ircc_cb *self, int iobase)
+static void smsc_ircc_dma_xmit_complete(struct smsc_ircc_cb *self)
{
+ int iobase = self->io.fir_base;
+
IRDA_DEBUG(3, "%s\n", __FUNCTION__);
#if 0
/* Disable Tx */
register_bank(iobase, 0);
- outb(0x00, iobase+IRCC_LCR_B);
+ outb(0x00, iobase + IRCC_LCR_B);
#endif
- register_bank(self->io.fir_base, 1);
- outb(inb(self->io.fir_base+IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE,
- self->io.fir_base+IRCC_SCE_CFGB);
+ register_bank(iobase, 1);
+ outb(inb(iobase + IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE,
+ iobase + IRCC_SCE_CFGB);
/* Check for underrun! */
register_bank(iobase, 0);
- if (inb(iobase+IRCC_LSR) & IRCC_LSR_UNDERRUN) {
+ if (inb(iobase + IRCC_LSR) & IRCC_LSR_UNDERRUN) {
self->stats.tx_errors++;
self->stats.tx_fifo_errors++;
/* Reset error condition */
register_bank(iobase, 0);
- outb(IRCC_MASTER_ERROR_RESET, iobase+IRCC_MASTER);
- outb(0x00, iobase+IRCC_MASTER);
+ outb(IRCC_MASTER_ERROR_RESET, iobase + IRCC_MASTER);
+ outb(0x00, iobase + IRCC_MASTER);
} else {
self->stats.tx_packets++;
- self->stats.tx_bytes += self->tx_buff.len;
+ self->stats.tx_bytes += self->tx_buff.len;
}
/* Check if it's time to change the speed */
if (self->new_speed) {
- smsc_ircc_change_speed(self, self->new_speed);
+ smsc_ircc_change_speed(self, self->new_speed);
self->new_speed = 0;
}
@@ -1231,31 +1251,32 @@ static void smsc_ircc_dma_xmit_complete(struct smsc_ircc_cb *self, int iobase)
* if it starts to receive a frame.
*
*/
-static int smsc_ircc_dma_receive(struct smsc_ircc_cb *self, int iobase)
+static int smsc_ircc_dma_receive(struct smsc_ircc_cb *self)
{
+ int iobase = self->io.fir_base;
#if 0
/* Turn off chip DMA */
register_bank(iobase, 1);
- outb(inb(iobase+IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE,
- iobase+IRCC_SCE_CFGB);
+ outb(inb(iobase + IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE,
+ iobase + IRCC_SCE_CFGB);
#endif
-
+
/* Disable Tx */
register_bank(iobase, 0);
- outb(0x00, iobase+IRCC_LCR_B);
+ outb(0x00, iobase + IRCC_LCR_B);
/* Turn off chip DMA */
register_bank(iobase, 1);
- outb(inb(iobase+IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE,
- iobase+IRCC_SCE_CFGB);
+ outb(inb(iobase + IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE,
+ iobase + IRCC_SCE_CFGB);
self->io.direction = IO_RECV;
self->rx_buff.data = self->rx_buff.head;
/* Set max Rx frame size */
register_bank(iobase, 4);
- outb((2050 >> 8) & 0x0f, iobase+IRCC_RX_SIZE_HI);
- outb(2050 & 0xff, iobase+IRCC_RX_SIZE_LO);
+ outb((2050 >> 8) & 0x0f, iobase + IRCC_RX_SIZE_HI);
+ outb(2050 & 0xff, iobase + IRCC_RX_SIZE_LO);
/* Setup DMA controller */
irda_setup_dma(self->io.dma, self->rx_buff_dma, self->rx_buff.truesize,
@@ -1263,83 +1284,83 @@ static int smsc_ircc_dma_receive(struct smsc_ircc_cb *self, int iobase)
/* Enable burst mode chip Rx DMA */
register_bank(iobase, 1);
- outb(inb(iobase+IRCC_SCE_CFGB) | IRCC_CFGB_DMA_ENABLE |
- IRCC_CFGB_DMA_BURST, iobase+IRCC_SCE_CFGB);
+ outb(inb(iobase + IRCC_SCE_CFGB) | IRCC_CFGB_DMA_ENABLE |
+ IRCC_CFGB_DMA_BURST, iobase + IRCC_SCE_CFGB);
/* Enable interrupt */
register_bank(iobase, 0);
- outb(IRCC_IER_ACTIVE_FRAME | IRCC_IER_EOM, iobase+IRCC_IER);
- outb(IRCC_MASTER_INT_EN, iobase+IRCC_MASTER);
-
+ outb(IRCC_IER_ACTIVE_FRAME | IRCC_IER_EOM, iobase + IRCC_IER);
+ outb(IRCC_MASTER_INT_EN, iobase + IRCC_MASTER);
/* Enable receiver */
register_bank(iobase, 0);
- outb(IRCC_LCR_B_SCE_RECEIVE | IRCC_LCR_B_SIP_ENABLE,
- iobase+IRCC_LCR_B);
-
+ outb(IRCC_LCR_B_SCE_RECEIVE | IRCC_LCR_B_SIP_ENABLE,
+ iobase + IRCC_LCR_B);
+
return 0;
}
/*
- * Function smsc_ircc_dma_receive_complete(self, iobase)
+ * Function smsc_ircc_dma_receive_complete(self)
*
* Finished with receiving frames
*
*/
-static void smsc_ircc_dma_receive_complete(struct smsc_ircc_cb *self, int iobase)
+static void smsc_ircc_dma_receive_complete(struct smsc_ircc_cb *self)
{
struct sk_buff *skb;
int len, msgcnt, lsr;
-
+ int iobase = self->io.fir_base;
+
register_bank(iobase, 0);
-
+
IRDA_DEBUG(3, "%s\n", __FUNCTION__);
#if 0
/* Disable Rx */
register_bank(iobase, 0);
- outb(0x00, iobase+IRCC_LCR_B);
+ outb(0x00, iobase + IRCC_LCR_B);
#endif
register_bank(iobase, 0);
- outb(inb(iobase+IRCC_LSAR) & ~IRCC_LSAR_ADDRESS_MASK, iobase+IRCC_LSAR);
- lsr= inb(iobase+IRCC_LSR);
- msgcnt = inb(iobase+IRCC_LCR_B) & 0x08;
+ outb(inb(iobase + IRCC_LSAR) & ~IRCC_LSAR_ADDRESS_MASK, iobase + IRCC_LSAR);
+ lsr= inb(iobase + IRCC_LSR);
+ msgcnt = inb(iobase + IRCC_LCR_B) & 0x08;
IRDA_DEBUG(2, "%s: dma count = %d\n", __FUNCTION__,
get_dma_residue(self->io.dma));
len = self->rx_buff.truesize - get_dma_residue(self->io.dma);
- /* Look for errors
- */
-
- if(lsr & (IRCC_LSR_FRAME_ERROR | IRCC_LSR_CRC_ERROR | IRCC_LSR_SIZE_ERROR)) {
+ /* Look for errors */
+ if (lsr & (IRCC_LSR_FRAME_ERROR | IRCC_LSR_CRC_ERROR | IRCC_LSR_SIZE_ERROR)) {
self->stats.rx_errors++;
- if(lsr & IRCC_LSR_FRAME_ERROR) self->stats.rx_frame_errors++;
- if(lsr & IRCC_LSR_CRC_ERROR) self->stats.rx_crc_errors++;
- if(lsr & IRCC_LSR_SIZE_ERROR) self->stats.rx_length_errors++;
- if(lsr & (IRCC_LSR_UNDERRUN | IRCC_LSR_OVERRUN)) self->stats.rx_length_errors++;
+ if (lsr & IRCC_LSR_FRAME_ERROR)
+ self->stats.rx_frame_errors++;
+ if (lsr & IRCC_LSR_CRC_ERROR)
+ self->stats.rx_crc_errors++;
+ if (lsr & IRCC_LSR_SIZE_ERROR)
+ self->stats.rx_length_errors++;
+ if (lsr & (IRCC_LSR_UNDERRUN | IRCC_LSR_OVERRUN))
+ self->stats.rx_length_errors++;
return;
}
+
/* Remove CRC */
- if (self->io.speed < 4000000)
- len -= 2;
- else
- len -= 4;
+ len -= self->io.speed < 4000000 ? 2 : 4;
- if ((len < 2) || (len > 2050)) {
+ if (len < 2 || len > 2050) {
IRDA_WARNING("%s(), bogus len=%d\n", __FUNCTION__, len);
return;
}
IRDA_DEBUG(2, "%s: msgcnt = %d, len=%d\n", __FUNCTION__, msgcnt, len);
- skb = dev_alloc_skb(len+1);
- if (!skb) {
+ skb = dev_alloc_skb(len + 1);
+ if (!skb) {
IRDA_WARNING("%s(), memory squeeze, dropping frame.\n",
__FUNCTION__);
return;
- }
+ }
/* Make sure IP header gets aligned */
- skb_reserve(skb, 1);
+ skb_reserve(skb, 1);
memcpy(skb_put(skb, len), self->rx_buff.data, len);
self->stats.rx_packets++;
@@ -1357,7 +1378,7 @@ static void smsc_ircc_dma_receive_complete(struct smsc_ircc_cb *self, int iobase
* Receive one frame from the infrared port
*
*/
-static void smsc_ircc_sir_receive(struct smsc_ircc_cb *self)
+static void smsc_ircc_sir_receive(struct smsc_ircc_cb *self)
{
int boguscount = 0;
int iobase;
@@ -1366,20 +1387,20 @@ static void smsc_ircc_sir_receive(struct smsc_ircc_cb *self)
iobase = self->io.sir_base;
- /*
- * Receive all characters in Rx FIFO, unwrap and unstuff them.
- * async_unwrap_char will deliver all found frames
+ /*
+ * Receive all characters in Rx FIFO, unwrap and unstuff them.
+ * async_unwrap_char will deliver all found frames
*/
do {
- async_unwrap_char(self->netdev, &self->stats, &self->rx_buff,
- inb(iobase+UART_RX));
+ async_unwrap_char(self->netdev, &self->stats, &self->rx_buff,
+ inb(iobase + UART_RX));
/* Make sure we don't stay here to long */
if (boguscount++ > 32) {
IRDA_DEBUG(2, "%s(), breaking!\n", __FUNCTION__);
break;
}
- } while (inb(iobase+UART_LSR) & UART_LSR_DR);
+ } while (inb(iobase + UART_LSR) & UART_LSR_DR);
}
@@ -1397,18 +1418,19 @@ static irqreturn_t smsc_ircc_interrupt(int irq, void *dev_id, struct pt_regs *re
irqreturn_t ret = IRQ_NONE;
if (dev == NULL) {
- printk(KERN_WARNING "%s: irq %d for unknown device.\n",
+ printk(KERN_WARNING "%s: irq %d for unknown device.\n",
driver_name, irq);
goto irq_ret;
}
- self = (struct smsc_ircc_cb *) dev->priv;
+
+ self = netdev_priv(dev);
IRDA_ASSERT(self != NULL, return IRQ_NONE;);
/* Serialise the interrupt handler in various CPUs, stop Tx path */
- spin_lock(&self->lock);
+ spin_lock(&self->lock);
/* Check if we should use the SIR interrupt handler */
- if (self->io.speed <= SMSC_IRCC2_MAX_SIR_SPEED) {
+ if (self->io.speed <= SMSC_IRCC2_MAX_SIR_SPEED) {
ret = smsc_ircc_interrupt_sir(dev);
goto irq_ret_unlock;
}
@@ -1416,25 +1438,25 @@ static irqreturn_t smsc_ircc_interrupt(int irq, void *dev_id, struct pt_regs *re
iobase = self->io.fir_base;
register_bank(iobase, 0);
- iir = inb(iobase+IRCC_IIR);
- if (iir == 0)
+ iir = inb(iobase + IRCC_IIR);
+ if (iir == 0)
goto irq_ret_unlock;
ret = IRQ_HANDLED;
/* Disable interrupts */
- outb(0, iobase+IRCC_IER);
- lcra = inb(iobase+IRCC_LCR_A);
- lsr = inb(iobase+IRCC_LSR);
-
+ outb(0, iobase + IRCC_IER);
+ lcra = inb(iobase + IRCC_LCR_A);
+ lsr = inb(iobase + IRCC_LSR);
+
IRDA_DEBUG(2, "%s(), iir = 0x%02x\n", __FUNCTION__, iir);
if (iir & IRCC_IIR_EOM) {
if (self->io.direction == IO_RECV)
- smsc_ircc_dma_receive_complete(self, iobase);
+ smsc_ircc_dma_receive_complete(self);
else
- smsc_ircc_dma_xmit_complete(self, iobase);
-
- smsc_ircc_dma_receive(self, iobase);
+ smsc_ircc_dma_xmit_complete(self);
+
+ smsc_ircc_dma_receive(self);
}
if (iir & IRCC_IIR_ACTIVE_FRAME) {
@@ -1444,7 +1466,7 @@ static irqreturn_t smsc_ircc_interrupt(int irq, void *dev_id, struct pt_regs *re
/* Enable interrupts again */
register_bank(iobase, 0);
- outb(IRCC_IER_ACTIVE_FRAME|IRCC_IER_EOM, iobase+IRCC_IER);
+ outb(IRCC_IER_ACTIVE_FRAME | IRCC_IER_EOM, iobase + IRCC_IER);
irq_ret_unlock:
spin_unlock(&self->lock);
@@ -1459,7 +1481,7 @@ static irqreturn_t smsc_ircc_interrupt(int irq, void *dev_id, struct pt_regs *re
*/
static irqreturn_t smsc_ircc_interrupt_sir(struct net_device *dev)
{
- struct smsc_ircc_cb *self = dev->priv;
+ struct smsc_ircc_cb *self = netdev_priv(dev);
int boguscount = 0;
int iobase;
int iir, lsr;
@@ -1469,14 +1491,14 @@ static irqreturn_t smsc_ircc_interrupt_sir(struct net_device *dev)
iobase = self->io.sir_base;
- iir = inb(iobase+UART_IIR) & UART_IIR_ID;
+ iir = inb(iobase + UART_IIR) & UART_IIR_ID;
if (iir == 0)
return IRQ_NONE;
while (iir) {
/* Clear interrupt */
- lsr = inb(iobase+UART_LSR);
+ lsr = inb(iobase + UART_LSR);
- IRDA_DEBUG(4, "%s(), iir=%02x, lsr=%02x, iobase=%#x\n",
+ IRDA_DEBUG(4, "%s(), iir=%02x, lsr=%02x, iobase=%#x\n",
__FUNCTION__, iir, lsr, iobase);
switch (iir) {
@@ -1496,13 +1518,13 @@ static irqreturn_t smsc_ircc_interrupt_sir(struct net_device *dev)
IRDA_DEBUG(0, "%s(), unhandled IIR=%#x\n",
__FUNCTION__, iir);
break;
- }
-
+ }
+
/* Make sure we don't stay here to long */
if (boguscount++ > 100)
break;
- iir = inb(iobase + UART_IIR) & UART_IIR_ID;
+ iir = inb(iobase + UART_IIR) & UART_IIR_ID;
}
/*spin_unlock(&self->lock);*/
return IRQ_HANDLED;
@@ -1529,7 +1551,7 @@ static int ircc_is_receiving(struct smsc_ircc_cb *self)
get_dma_residue(self->io.dma));
status = (self->rx_buff.state != OUTSIDE_FRAME);
-
+
return status;
}
#endif /* unused */
@@ -1544,19 +1566,16 @@ static int ircc_is_receiving(struct smsc_ircc_cb *self)
static int smsc_ircc_net_open(struct net_device *dev)
{
struct smsc_ircc_cb *self;
- int iobase;
char hwname[16];
unsigned long flags;
IRDA_DEBUG(1, "%s\n", __FUNCTION__);
-
+
IRDA_ASSERT(dev != NULL, return -1;);
- self = (struct smsc_ircc_cb *) dev->priv;
+ self = netdev_priv(dev);
IRDA_ASSERT(self != NULL, return 0;);
-
- iobase = self->io.fir_base;
- if (request_irq(self->io.irq, smsc_ircc_interrupt, 0, dev->name,
+ if (request_irq(self->io.irq, smsc_ircc_interrupt, 0, dev->name,
(void *) dev)) {
IRDA_DEBUG(0, "%s(), unable to allocate irq=%d\n",
__FUNCTION__, self->io.irq);
@@ -1568,14 +1587,14 @@ static int smsc_ircc_net_open(struct net_device *dev)
self->io.speed = 0;
smsc_ircc_change_speed(self, SMSC_IRCC2_C_IRDA_FALLBACK_SPEED);
spin_unlock_irqrestore(&self->lock, flags);
-
+
/* Give self a hardware name */
/* It would be cool to offer the chip revision here - Jean II */
sprintf(hwname, "SMSC @ 0x%03x", self->io.fir_base);
- /*
+ /*
* Open new IrLAP layer instance, now that everything should be
- * initialized properly
+ * initialized properly
*/
self->irlap = irlap_open(dev, &self->qos, hwname);
@@ -1590,7 +1609,7 @@ static int smsc_ircc_net_open(struct net_device *dev)
__FUNCTION__, self->io.dma);
return -EAGAIN;
}
-
+
netif_start_queue(dev);
return 0;
@@ -1605,73 +1624,53 @@ static int smsc_ircc_net_open(struct net_device *dev)
static int smsc_ircc_net_close(struct net_device *dev)
{
struct smsc_ircc_cb *self;
- int iobase;
IRDA_DEBUG(1, "%s\n", __FUNCTION__);
-
+
IRDA_ASSERT(dev != NULL, return -1;);
- self = (struct smsc_ircc_cb *) dev->priv;
+ self = netdev_priv(dev);
IRDA_ASSERT(self != NULL, return 0;);
-
- iobase = self->io.fir_base;
/* Stop device */
netif_stop_queue(dev);
-
+
/* Stop and remove instance of IrLAP */
if (self->irlap)
irlap_close(self->irlap);
self->irlap = NULL;
free_irq(self->io.irq, dev);
-
disable_dma(self->io.dma);
-
free_dma(self->io.dma);
return 0;
}
-
-static void smsc_ircc_suspend(struct smsc_ircc_cb *self)
+static int smsc_ircc_suspend(struct device *dev, pm_message_t state, u32 level)
{
- IRDA_MESSAGE("%s, Suspending\n", driver_name);
+ struct smsc_ircc_cb *self = dev_get_drvdata(dev);
- if (self->io.suspended)
- return;
+ IRDA_MESSAGE("%s, Suspending\n", driver_name);
- smsc_ircc_net_close(self->netdev);
+ if (level == SUSPEND_DISABLE && !self->io.suspended) {
+ smsc_ircc_net_close(self->netdev);
+ self->io.suspended = 1;
+ }
- self->io.suspended = 1;
+ return 0;
}
-static void smsc_ircc_wakeup(struct smsc_ircc_cb *self)
+static int smsc_ircc_resume(struct device *dev, u32 level)
{
- if (!self->io.suspended)
- return;
+ struct smsc_ircc_cb *self = dev_get_drvdata(dev);
- /* The code was doing a "cli()" here, but this can't be right.
- * If you need protection, do it in net_open with a spinlock
- * or give a good reason. - Jean II */
+ if (level == RESUME_ENABLE && self->io.suspended) {
- smsc_ircc_net_open(self->netdev);
-
- IRDA_MESSAGE("%s, Waking up\n", driver_name);
-}
+ smsc_ircc_net_open(self->netdev);
+ self->io.suspended = 0;
-static int smsc_ircc_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data)
-{
- struct smsc_ircc_cb *self = (struct smsc_ircc_cb*) dev->data;
- if (self) {
- switch (rqst) {
- case PM_SUSPEND:
- smsc_ircc_suspend(self);
- break;
- case PM_RESUME:
- smsc_ircc_wakeup(self);
- break;
- }
- }
+ IRDA_MESSAGE("%s, Waking up\n", driver_name);
+ }
return 0;
}
@@ -1690,10 +1689,7 @@ static int __exit smsc_ircc_close(struct smsc_ircc_cb *self)
IRDA_ASSERT(self != NULL, return -1;);
- iobase = self->io.fir_base;
-
- if (self->pmdev)
- pm_unregister(self->pmdev);
+ platform_device_unregister(self->pldev);
/* Remove netdevice */
unregister_netdev(self->netdev);
@@ -1702,15 +1698,16 @@ static int __exit smsc_ircc_close(struct smsc_ircc_cb *self)
spin_lock_irqsave(&self->lock, flags);
/* Stop interrupts */
+ iobase = self->io.fir_base;
register_bank(iobase, 0);
- outb(0, iobase+IRCC_IER);
- outb(IRCC_MASTER_RESET, iobase+IRCC_MASTER);
- outb(0x00, iobase+IRCC_MASTER);
+ outb(0, iobase + IRCC_IER);
+ outb(IRCC_MASTER_RESET, iobase + IRCC_MASTER);
+ outb(0x00, iobase + IRCC_MASTER);
#if 0
/* Reset to SIR mode */
register_bank(iobase, 1);
- outb(IRCC_CFGA_IRDA_SIR_A|IRCC_CFGA_TX_POLARITY, iobase+IRCC_SCE_CFGA);
- outb(IRCC_CFGB_IR, iobase+IRCC_SCE_CFGB);
+ outb(IRCC_CFGA_IRDA_SIR_A|IRCC_CFGA_TX_POLARITY, iobase + IRCC_SCE_CFGA);
+ outb(IRCC_CFGB_IR, iobase + IRCC_SCE_CFGB);
#endif
spin_unlock_irqrestore(&self->lock, flags);
@@ -1720,7 +1717,7 @@ static int __exit smsc_ircc_close(struct smsc_ircc_cb *self)
release_region(self->io.fir_base, self->io.fir_ext);
- IRDA_DEBUG(0, "%s(), releasing 0x%03x\n", __FUNCTION__,
+ IRDA_DEBUG(0, "%s(), releasing 0x%03x\n", __FUNCTION__,
self->io.sir_base);
release_region(self->io.sir_base, self->io.sir_ext);
@@ -1728,7 +1725,7 @@ static int __exit smsc_ircc_close(struct smsc_ircc_cb *self)
if (self->tx_buff.head)
dma_free_coherent(NULL, self->tx_buff.truesize,
self->tx_buff.head, self->tx_buff_dma);
-
+
if (self->rx_buff.head)
dma_free_coherent(NULL, self->rx_buff.truesize,
self->rx_buff.head, self->rx_buff_dma);
@@ -1744,10 +1741,12 @@ static void __exit smsc_ircc_cleanup(void)
IRDA_DEBUG(1, "%s\n", __FUNCTION__);
- for (i=0; i < 2; i++) {
+ for (i = 0; i < 2; i++) {
if (dev_self[i])
smsc_ircc_close(dev_self[i]);
}
+
+ driver_unregister(&smsc_ircc_driver);
}
/*
@@ -1763,34 +1762,34 @@ void smsc_ircc_sir_start(struct smsc_ircc_cb *self)
IRDA_DEBUG(3, "%s\n", __FUNCTION__);
- IRDA_ASSERT(self != NULL, return;);
- dev= self->netdev;
- IRDA_ASSERT(dev != NULL, return;);
+ IRDA_ASSERT(self != NULL, return;);
+ dev = self->netdev;
+ IRDA_ASSERT(dev != NULL, return;);
dev->hard_start_xmit = &smsc_ircc_hard_xmit_sir;
fir_base = self->io.fir_base;
sir_base = self->io.sir_base;
/* Reset everything */
- outb(IRCC_MASTER_RESET, fir_base+IRCC_MASTER);
+ outb(IRCC_MASTER_RESET, fir_base + IRCC_MASTER);
#if SMSC_IRCC2_C_SIR_STOP
/*smsc_ircc_sir_stop(self);*/
#endif
register_bank(fir_base, 1);
- outb(((inb(fir_base+IRCC_SCE_CFGA) & IRCC_SCE_CFGA_BLOCK_CTRL_BITS_MASK) | IRCC_CFGA_IRDA_SIR_A), fir_base+IRCC_SCE_CFGA);
+ outb(((inb(fir_base + IRCC_SCE_CFGA) & IRCC_SCE_CFGA_BLOCK_CTRL_BITS_MASK) | IRCC_CFGA_IRDA_SIR_A), fir_base + IRCC_SCE_CFGA);
/* Initialize UART */
- outb(UART_LCR_WLEN8, sir_base+UART_LCR); /* Reset DLAB */
- outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), sir_base+UART_MCR);
-
+ outb(UART_LCR_WLEN8, sir_base + UART_LCR); /* Reset DLAB */
+ outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), sir_base + UART_MCR);
+
/* Turn on interrups */
- outb(UART_IER_RLSI | UART_IER_RDI |UART_IER_THRI, sir_base+UART_IER);
+ outb(UART_IER_RLSI | UART_IER_RDI |UART_IER_THRI, sir_base + UART_IER);
IRDA_DEBUG(3, "%s() - exit\n", __FUNCTION__);
- outb(0x00, fir_base+IRCC_MASTER);
+ outb(0x00, fir_base + IRCC_MASTER);
}
#if SMSC_IRCC2_C_SIR_STOP
@@ -1802,10 +1801,10 @@ void smsc_ircc_sir_stop(struct smsc_ircc_cb *self)
iobase = self->io.sir_base;
/* Reset UART */
- outb(0, iobase+UART_MCR);
-
+ outb(0, iobase + UART_MCR);
+
/* Turn off interrupts */
- outb(0, iobase+UART_IER);
+ outb(0, iobase + UART_IER);
}
#endif
@@ -1831,16 +1830,16 @@ static void smsc_ircc_sir_write_wakeup(struct smsc_ircc_cb *self)
/* Finished with frame? */
if (self->tx_buff.len > 0) {
/* Write data left in transmit buffer */
- actual = smsc_ircc_sir_write(iobase, self->io.fifo_size,
+ actual = smsc_ircc_sir_write(iobase, self->io.fifo_size,
self->tx_buff.data, self->tx_buff.len);
self->tx_buff.data += actual;
self->tx_buff.len -= actual;
} else {
-
+
/*if (self->tx_buff.len ==0) {*/
-
- /*
- * Now serial buffer is almost free & we can start
+
+ /*
+ * Now serial buffer is almost free & we can start
* transmission of another packet. But first we must check
* if we need to change the speed of the hardware
*/
@@ -1856,21 +1855,19 @@ static void smsc_ircc_sir_write_wakeup(struct smsc_ircc_cb *self)
}
self->stats.tx_packets++;
- if(self->io.speed <= 115200) {
- /*
- * Reset Rx FIFO to make sure that all reflected transmit data
- * is discarded. This is needed for half duplex operation
- */
- fcr = UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR;
- if (self->io.speed < 38400)
- fcr |= UART_FCR_TRIGGER_1;
- else
- fcr |= UART_FCR_TRIGGER_14;
+ if (self->io.speed <= 115200) {
+ /*
+ * Reset Rx FIFO to make sure that all reflected transmit data
+ * is discarded. This is needed for half duplex operation
+ */
+ fcr = UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR;
+ fcr |= self->io.speed < 38400 ?
+ UART_FCR_TRIGGER_1 : UART_FCR_TRIGGER_14;
- outb(fcr, iobase+UART_FCR);
+ outb(fcr, iobase + UART_FCR);
- /* Turn on receive interrupts */
- outb(UART_IER_RDI, iobase+UART_IER);
+ /* Turn on receive interrupts */
+ outb(UART_IER_RDI, iobase + UART_IER);
}
}
}
@@ -1884,17 +1881,17 @@ static void smsc_ircc_sir_write_wakeup(struct smsc_ircc_cb *self)
static int smsc_ircc_sir_write(int iobase, int fifo_size, __u8 *buf, int len)
{
int actual = 0;
-
+
/* Tx FIFO should be empty! */
- if (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) {
+ if (!(inb(iobase + UART_LSR) & UART_LSR_THRE)) {
IRDA_WARNING("%s(), failed, fifo not empty!\n", __FUNCTION__);
return 0;
}
-
+
/* Fill FIFO with current frame */
- while ((fifo_size-- > 0) && (actual < len)) {
+ while (fifo_size-- > 0 && actual < len) {
/* Transmit next byte */
- outb(buf[actual], iobase+UART_TX);
+ outb(buf[actual], iobase + UART_TX);
actual++;
}
return actual;
@@ -1921,20 +1918,21 @@ static int smsc_ircc_is_receiving(struct smsc_ircc_cb *self)
static void smsc_ircc_probe_transceiver(struct smsc_ircc_cb *self)
{
unsigned int i;
-
+
IRDA_ASSERT(self != NULL, return;);
-
- for(i=0; smsc_transceivers[i].name!=NULL; i++)
- if((*smsc_transceivers[i].probe)(self->io.fir_base)) {
+
+ for (i = 0; smsc_transceivers[i].name != NULL; i++)
+ if (smsc_transceivers[i].probe(self->io.fir_base)) {
IRDA_MESSAGE(" %s transceiver found\n",
smsc_transceivers[i].name);
- self->transceiver= i+1;
+ self->transceiver= i + 1;
return;
}
+
IRDA_MESSAGE("No transceiver found. Defaulting to %s\n",
smsc_transceivers[SMSC_IRCC2_C_DEFAULT_TRANSCEIVER].name);
-
- self->transceiver= SMSC_IRCC2_C_DEFAULT_TRANSCEIVER;
+
+ self->transceiver = SMSC_IRCC2_C_DEFAULT_TRANSCEIVER;
}
@@ -1947,9 +1945,10 @@ static void smsc_ircc_probe_transceiver(struct smsc_ircc_cb *self)
static void smsc_ircc_set_transceiver_for_speed(struct smsc_ircc_cb *self, u32 speed)
{
unsigned int trx;
-
+
trx = self->transceiver;
- if(trx>0) (*smsc_transceivers[trx-1].set_for_speed)(self->io.fir_base, speed);
+ if (trx > 0)
+ smsc_transceivers[trx - 1].set_for_speed(self->io.fir_base, speed);
}
/*
@@ -1977,16 +1976,14 @@ static void smsc_ircc_set_transceiver_for_speed(struct smsc_ircc_cb *self, u32 s
static void smsc_ircc_sir_wait_hw_transmitter_finish(struct smsc_ircc_cb *self)
{
- int iobase;
+ int iobase = self->io.sir_base;
int count = SMSC_IRCC2_HW_TRANSMITTER_TIMEOUT_US;
-
- iobase = self->io.sir_base;
-
+
/* Calibrated busy loop */
- while((count-- > 0) && !(inb(iobase+UART_LSR) & UART_LSR_TEMT))
+ while (count-- > 0 && !(inb(iobase + UART_LSR) & UART_LSR_TEMT))
udelay(1);
- if(count == 0)
+ if (count == 0)
IRDA_DEBUG(0, "%s(): stuck transmitter\n", __FUNCTION__);
}
@@ -1998,40 +1995,42 @@ static void smsc_ircc_sir_wait_hw_transmitter_finish(struct smsc_ircc_cb *self)
static int __init smsc_ircc_look_for_chips(void)
{
- smsc_chip_address_t *address;
- char *type;
+ struct smsc_chip_address *address;
+ char *type;
unsigned int cfg_base, found;
-
+
found = 0;
address = possible_addresses;
-
- while(address->cfg_base){
+
+ while (address->cfg_base) {
cfg_base = address->cfg_base;
-
+
/*printk(KERN_WARNING "%s(): probing: 0x%02x for: 0x%02x\n", __FUNCTION__, cfg_base, address->type);*/
-
- if( address->type & SMSCSIO_TYPE_FDC){
+
+ if (address->type & SMSCSIO_TYPE_FDC) {
type = "FDC";
- if((address->type) & SMSCSIO_TYPE_FLAT) {
- if(!smsc_superio_flat(fdc_chips_flat,cfg_base, type)) found++;
- }
- if((address->type) & SMSCSIO_TYPE_PAGED) {
- if(!smsc_superio_paged(fdc_chips_paged,cfg_base, type)) found++;
- }
+ if (address->type & SMSCSIO_TYPE_FLAT)
+ if (!smsc_superio_flat(fdc_chips_flat, cfg_base, type))
+ found++;
+
+ if (address->type & SMSCSIO_TYPE_PAGED)
+ if (!smsc_superio_paged(fdc_chips_paged, cfg_base, type))
+ found++;
}
- if( address->type & SMSCSIO_TYPE_LPC){
+ if (address->type & SMSCSIO_TYPE_LPC) {
type = "LPC";
- if((address->type) & SMSCSIO_TYPE_FLAT) {
- if(!smsc_superio_flat(lpc_chips_flat,cfg_base,type)) found++;
- }
- if((address->type) & SMSCSIO_TYPE_PAGED) {
- if(!smsc_superio_paged(lpc_chips_paged,cfg_base,"LPC")) found++;
- }
+ if (address->type & SMSCSIO_TYPE_FLAT)
+ if (!smsc_superio_flat(lpc_chips_flat, cfg_base, type))
+ found++;
+
+ if (address->type & SMSCSIO_TYPE_PAGED)
+ if (!smsc_superio_paged(lpc_chips_paged, cfg_base, type))
+ found++;
}
address++;
}
return found;
-}
+}
/*
* Function smsc_superio_flat (chip, base, type)
@@ -2039,7 +2038,7 @@ static int __init smsc_ircc_look_for_chips(void)
* Try to get configuration of a smc SuperIO chip with flat register model
*
*/
-static int __init smsc_superio_flat(const smsc_chip_t *chips, unsigned short cfgbase, char *type)
+static int __init smsc_superio_flat(const struct smsc_chip *chips, unsigned short cfgbase, char *type)
{
unsigned short firbase, sirbase;
u8 mode, dma, irq;
@@ -2047,39 +2046,37 @@ static int __init smsc_superio_flat(const smsc_chip_t *chips, unsigned short cfg
IRDA_DEBUG(1, "%s\n", __FUNCTION__);
- if (smsc_ircc_probe(cfgbase, SMSCSIOFLAT_DEVICEID_REG, chips, type)==NULL)
+ if (smsc_ircc_probe(cfgbase, SMSCSIOFLAT_DEVICEID_REG, chips, type) == NULL)
return ret;
outb(SMSCSIOFLAT_UARTMODE0C_REG, cfgbase);
- mode = inb(cfgbase+1);
-
+ mode = inb(cfgbase + 1);
+
/*printk(KERN_WARNING "%s(): mode: 0x%02x\n", __FUNCTION__, mode);*/
-
- if(!(mode & SMSCSIOFLAT_UART2MODE_VAL_IRDA))
+
+ if (!(mode & SMSCSIOFLAT_UART2MODE_VAL_IRDA))
IRDA_WARNING("%s(): IrDA not enabled\n", __FUNCTION__);
outb(SMSCSIOFLAT_UART2BASEADDR_REG, cfgbase);
- sirbase = inb(cfgbase+1) << 2;
+ sirbase = inb(cfgbase + 1) << 2;
- /* FIR iobase */
+ /* FIR iobase */
outb(SMSCSIOFLAT_FIRBASEADDR_REG, cfgbase);
- firbase = inb(cfgbase+1) << 3;
+ firbase = inb(cfgbase + 1) << 3;
/* DMA */
outb(SMSCSIOFLAT_FIRDMASELECT_REG, cfgbase);
- dma = inb(cfgbase+1) & SMSCSIOFLAT_FIRDMASELECT_MASK;
-
+ dma = inb(cfgbase + 1) & SMSCSIOFLAT_FIRDMASELECT_MASK;
+
/* IRQ */
outb(SMSCSIOFLAT_UARTIRQSELECT_REG, cfgbase);
- irq = inb(cfgbase+1) & SMSCSIOFLAT_UART2IRQSELECT_MASK;
+ irq = inb(cfgbase + 1) & SMSCSIOFLAT_UART2IRQSELECT_MASK;
IRDA_MESSAGE("%s(): fir: 0x%02x, sir: 0x%02x, dma: %02d, irq: %d, mode: 0x%02x\n", __FUNCTION__, firbase, sirbase, dma, irq, mode);
- if (firbase) {
- if (smsc_ircc_open(firbase, sirbase, dma, irq) == 0)
- ret=0;
- }
-
+ if (firbase && smsc_ircc_open(firbase, sirbase, dma, irq) == 0)
+ ret = 0;
+
/* Exit configuration */
outb(SMSCSIO_CFGEXITKEY, cfgbase);
@@ -2092,26 +2089,26 @@ static int __init smsc_superio_flat(const smsc_chip_t *chips, unsigned short cfg
* Try to get configuration of a smc SuperIO chip with paged register model
*
*/
-static int __init smsc_superio_paged(const smsc_chip_t *chips, unsigned short cfg_base, char *type)
+static int __init smsc_superio_paged(const struct smsc_chip *chips, unsigned short cfg_base, char *type)
{
unsigned short fir_io, sir_io;
int ret = -ENODEV;
-
+
IRDA_DEBUG(1, "%s\n", __FUNCTION__);
- if (smsc_ircc_probe(cfg_base,0x20,chips,type)==NULL)
+ if (smsc_ircc_probe(cfg_base, 0x20, chips, type) == NULL)
return ret;
-
+
/* Select logical device (UART2) */
outb(0x07, cfg_base);
outb(0x05, cfg_base + 1);
-
+
/* SIR iobase */
outb(0x60, cfg_base);
- sir_io = inb(cfg_base + 1) << 8;
+ sir_io = inb(cfg_base + 1) << 8;
outb(0x61, cfg_base);
sir_io |= inb(cfg_base + 1);
-
+
/* Read FIR base */
outb(0x62, cfg_base);
fir_io = inb(cfg_base + 1) << 8;
@@ -2119,11 +2116,9 @@ static int __init smsc_superio_paged(const smsc_chip_t *chips, unsigned short cf
fir_io |= inb(cfg_base + 1);
outb(0x2b, cfg_base); /* ??? */
- if (fir_io) {
- if (smsc_ircc_open(fir_io, sir_io, ircc_dma, ircc_irq) == 0)
- ret=0;
- }
-
+ if (fir_io && smsc_ircc_open(fir_io, sir_io, ircc_dma, ircc_irq) == 0)
+ ret = 0;
+
/* Exit configuration */
outb(SMSCSIO_CFGEXITKEY, cfg_base);
@@ -2131,21 +2126,17 @@ static int __init smsc_superio_paged(const smsc_chip_t *chips, unsigned short cf
}
-static int __init smsc_access(unsigned short cfg_base,unsigned char reg)
+static int __init smsc_access(unsigned short cfg_base, unsigned char reg)
{
IRDA_DEBUG(1, "%s\n", __FUNCTION__);
outb(reg, cfg_base);
-
- if (inb(cfg_base)!=reg)
- return -1;
-
- return 0;
+ return inb(cfg_base) != reg ? -1 : 0;
}
-static const smsc_chip_t * __init smsc_ircc_probe(unsigned short cfg_base,u8 reg,const smsc_chip_t *chip,char *type)
+static const struct smsc_chip * __init smsc_ircc_probe(unsigned short cfg_base, u8 reg, const struct smsc_chip *chip, char *type)
{
- u8 devid,xdevid,rev;
+ u8 devid, xdevid, rev;
IRDA_DEBUG(1, "%s\n", __FUNCTION__);
@@ -2158,7 +2149,7 @@ static const smsc_chip_t * __init smsc_ircc_probe(unsigned short cfg_base,u8 reg
outb(reg, cfg_base);
- xdevid=inb(cfg_base+1);
+ xdevid = inb(cfg_base + 1);
/* Enter configuration */
@@ -2168,51 +2159,49 @@ static const smsc_chip_t * __init smsc_ircc_probe(unsigned short cfg_base,u8 reg
if (smsc_access(cfg_base,0x55)) /* send second key and check */
return NULL;
#endif
-
+
/* probe device ID */
- if (smsc_access(cfg_base,reg))
+ if (smsc_access(cfg_base, reg))
return NULL;
- devid=inb(cfg_base+1);
-
- if (devid==0) /* typical value for unused port */
- return NULL;
+ devid = inb(cfg_base + 1);
- if (devid==0xff) /* typical value for unused port */
+ if (devid == 0 || devid == 0xff) /* typical values for unused port */
return NULL;
/* probe revision ID */
- if (smsc_access(cfg_base,reg+1))
+ if (smsc_access(cfg_base, reg + 1))
return NULL;
- rev=inb(cfg_base+1);
+ rev = inb(cfg_base + 1);
- if (rev>=128) /* i think this will make no sense */
+ if (rev >= 128) /* i think this will make no sense */
return NULL;
- if (devid==xdevid) /* protection against false positives */
+ if (devid == xdevid) /* protection against false positives */
return NULL;
/* Check for expected device ID; are there others? */
- while(chip->devid!=devid) {
+ while (chip->devid != devid) {
chip++;
- if (chip->name==NULL)
+ if (chip->name == NULL)
return NULL;
}
- IRDA_MESSAGE("found SMC SuperIO Chip (devid=0x%02x rev=%02X base=0x%04x): %s%s\n",devid,rev,cfg_base,type,chip->name);
+ IRDA_MESSAGE("found SMC SuperIO Chip (devid=0x%02x rev=%02X base=0x%04x): %s%s\n",
+ devid, rev, cfg_base, type, chip->name);
- if (chip->rev>rev){
- IRDA_MESSAGE("Revision higher than expected\n");
+ if (chip->rev > rev) {
+ IRDA_MESSAGE("Revision higher than expected\n");
return NULL;
}
-
- if (chip->flags&NoIRDA)
+
+ if (chip->flags & NoIRDA)
IRDA_MESSAGE("chipset does not support IRDA\n");
return chip;
@@ -2226,8 +2215,8 @@ static int __init smsc_superio_fdc(unsigned short cfg_base)
IRDA_WARNING("%s: can't get cfg_base of 0x%03x\n",
__FUNCTION__, cfg_base);
} else {
- if (!smsc_superio_flat(fdc_chips_flat,cfg_base,"FDC")
- ||!smsc_superio_paged(fdc_chips_paged,cfg_base,"FDC"))
+ if (!smsc_superio_flat(fdc_chips_flat, cfg_base, "FDC") ||
+ !smsc_superio_paged(fdc_chips_paged, cfg_base, "FDC"))
ret = 0;
release_region(cfg_base, 2);
@@ -2244,9 +2233,10 @@ static int __init smsc_superio_lpc(unsigned short cfg_base)
IRDA_WARNING("%s: can't get cfg_base of 0x%03x\n",
__FUNCTION__, cfg_base);
} else {
- if (!smsc_superio_flat(lpc_chips_flat,cfg_base,"LPC")
- ||!smsc_superio_paged(lpc_chips_paged,cfg_base,"LPC"))
+ if (!smsc_superio_flat(lpc_chips_flat, cfg_base, "LPC") ||
+ !smsc_superio_paged(lpc_chips_paged, cfg_base, "LPC"))
ret = 0;
+
release_region(cfg_base, 2);
}
return ret;
@@ -2269,18 +2259,23 @@ static int __init smsc_superio_lpc(unsigned short cfg_base)
static void smsc_ircc_set_transceiver_smsc_ircc_atc(int fir_base, u32 speed)
{
unsigned long jiffies_now, jiffies_timeout;
- u8 val;
-
- jiffies_now= jiffies;
- jiffies_timeout= jiffies+SMSC_IRCC2_ATC_PROGRAMMING_TIMEOUT_JIFFIES;
-
+ u8 val;
+
+ jiffies_now = jiffies;
+ jiffies_timeout = jiffies + SMSC_IRCC2_ATC_PROGRAMMING_TIMEOUT_JIFFIES;
+
/* ATC */
register_bank(fir_base, 4);
- outb((inb(fir_base+IRCC_ATC) & IRCC_ATC_MASK) |IRCC_ATC_nPROGREADY|IRCC_ATC_ENABLE, fir_base+IRCC_ATC);
- while((val=(inb(fir_base+IRCC_ATC) & IRCC_ATC_nPROGREADY)) && !time_after(jiffies, jiffies_timeout));
- if(val)
+ outb((inb(fir_base + IRCC_ATC) & IRCC_ATC_MASK) | IRCC_ATC_nPROGREADY|IRCC_ATC_ENABLE,
+ fir_base + IRCC_ATC);
+
+ while ((val = (inb(fir_base + IRCC_ATC) & IRCC_ATC_nPROGREADY)) &&
+ !time_after(jiffies, jiffies_timeout))
+ /* empty */;
+
+ if (val)
IRDA_WARNING("%s(): ATC: 0x%02x\n", __FUNCTION__,
- inb(fir_base+IRCC_ATC));
+ inb(fir_base + IRCC_ATC));
}
/*
@@ -2298,34 +2293,32 @@ static int smsc_ircc_probe_transceiver_smsc_ircc_atc(int fir_base)
/*
* Function smsc_ircc_set_transceiver_smsc_ircc_fast_pin_select(self, speed)
*
- * Set transceiver
+ * Set transceiver
*
*/
static void smsc_ircc_set_transceiver_smsc_ircc_fast_pin_select(int fir_base, u32 speed)
{
- u8 fast_mode;
-
- switch(speed)
- {
- default:
- case 576000 :
- fast_mode = 0;
+ u8 fast_mode;
+
+ switch (speed) {
+ default:
+ case 576000 :
+ fast_mode = 0;
break;
- case 1152000 :
- case 4000000 :
+ case 1152000 :
+ case 4000000 :
fast_mode = IRCC_LCR_A_FAST;
break;
-
}
register_bank(fir_base, 0);
- outb((inb(fir_base+IRCC_LCR_A) & 0xbf) | fast_mode, fir_base+IRCC_LCR_A);
+ outb((inb(fir_base + IRCC_LCR_A) & 0xbf) | fast_mode, fir_base + IRCC_LCR_A);
}
/*
* Function smsc_ircc_probe_transceiver_smsc_ircc_fast_pin_select(fir_base)
*
- * Probe transceiver
+ * Probe transceiver
*
*/
@@ -2337,35 +2330,34 @@ static int smsc_ircc_probe_transceiver_smsc_ircc_fast_pin_select(int fir_base)
/*
* Function smsc_ircc_set_transceiver_toshiba_sat1800(fir_base, speed)
*
- * Set transceiver
+ * Set transceiver
*
*/
static void smsc_ircc_set_transceiver_toshiba_sat1800(int fir_base, u32 speed)
{
- u8 fast_mode;
-
- switch(speed)
- {
- default:
- case 576000 :
- fast_mode = 0;
+ u8 fast_mode;
+
+ switch (speed) {
+ default:
+ case 576000 :
+ fast_mode = 0;
break;
- case 1152000 :
- case 4000000 :
+ case 1152000 :
+ case 4000000 :
fast_mode = /*IRCC_LCR_A_FAST |*/ IRCC_LCR_A_GP_DATA;
break;
-
+
}
/* This causes an interrupt */
register_bank(fir_base, 0);
- outb((inb(fir_base+IRCC_LCR_A) & 0xbf) | fast_mode, fir_base+IRCC_LCR_A);
+ outb((inb(fir_base + IRCC_LCR_A) & 0xbf) | fast_mode, fir_base + IRCC_LCR_A);
}
/*
* Function smsc_ircc_probe_transceiver_toshiba_sat1800(fir_base)
*
- * Probe transceiver
+ * Probe transceiver
*
*/
@@ -2377,20 +2369,3 @@ static int smsc_ircc_probe_transceiver_toshiba_sat1800(int fir_base)
module_init(smsc_ircc_init);
module_exit(smsc_ircc_cleanup);
-
-MODULE_AUTHOR("Daniele Peri <peri@csai.unipa.it>");
-MODULE_DESCRIPTION("SMC IrCC SIR/FIR controller driver");
-MODULE_LICENSE("GPL");
-
-module_param(ircc_dma, int, 0);
-MODULE_PARM_DESC(ircc_dma, "DMA channel");
-module_param(ircc_irq, int, 0);
-MODULE_PARM_DESC(ircc_irq, "IRQ line");
-module_param(ircc_fir, int, 0);
-MODULE_PARM_DESC(ircc_fir, "FIR Base Address");
-module_param(ircc_sir, int, 0);
-MODULE_PARM_DESC(ircc_sir, "SIR Base Address");
-module_param(ircc_cfg, int, 0);
-MODULE_PARM_DESC(ircc_cfg, "Configuration register base address");
-module_param(ircc_transceiver, int, 0);
-MODULE_PARM_DESC(ircc_transceiver, "Transceiver type");
diff --git a/drivers/net/irda/smsc-ircc2.h b/drivers/net/irda/smsc-ircc2.h
index 458611cc0d40..0c36286d87f7 100644
--- a/drivers/net/irda/smsc-ircc2.h
+++ b/drivers/net/irda/smsc-ircc2.h
@@ -1,5 +1,5 @@
/*********************************************************************
- * $Id: smsc-ircc2.h,v 1.12.2.1 2002/10/27 10:52:37 dip Exp $
+ * $Id: smsc-ircc2.h,v 1.12.2.1 2002/10/27 10:52:37 dip Exp $
*
* Description: Definitions for the SMC IrCC chipset
* Status: Experimental.
@@ -9,25 +9,25 @@
* All Rights Reserved.
*
* Based on smc-ircc.h:
- *
+ *
* Copyright (c) 1999-2000, Dag Brattli <dagb@cs.uit.no>
* Copyright (c) 1998-1999, Thomas Davis (tadavis@jps.net>
* All Rights Reserved
*
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
- *
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
********************************************************************/
@@ -112,10 +112,10 @@
#define IRCC_CFGA_COM 0x00
#define IRCC_SCE_CFGA_BLOCK_CTRL_BITS_MASK 0x87
-#define IRCC_CFGA_IRDA_SIR_A 0x08
-#define IRCC_CFGA_ASK_SIR 0x10
-#define IRCC_CFGA_IRDA_SIR_B 0x18
-#define IRCC_CFGA_IRDA_HDLC 0x20
+#define IRCC_CFGA_IRDA_SIR_A 0x08
+#define IRCC_CFGA_ASK_SIR 0x10
+#define IRCC_CFGA_IRDA_SIR_B 0x18
+#define IRCC_CFGA_IRDA_HDLC 0x20
#define IRCC_CFGA_IRDA_4PPM 0x28
#define IRCC_CFGA_CONSUMER 0x30
#define IRCC_CFGA_RAW_IR 0x38
@@ -130,7 +130,7 @@
#define IRCC_CFGB_LPBCK_TX_CRC 0x10
#define IRCC_CFGB_NOWAIT 0x08
#define IRCC_CFGB_STRING_MOVE 0x04
-#define IRCC_CFGB_DMA_BURST 0x02
+#define IRCC_CFGB_DMA_BURST 0x02
#define IRCC_CFGB_DMA_ENABLE 0x01
#define IRCC_CFGB_MUX_COM 0x00
@@ -141,11 +141,11 @@
/* Register block 3 - Identification Registers! */
#define IRCC_ID_HIGH 0x00 /* 0x10 */
#define IRCC_ID_LOW 0x01 /* 0xB8 */
-#define IRCC_CHIP_ID 0x02 /* 0xF1 */
+#define IRCC_CHIP_ID 0x02 /* 0xF1 */
#define IRCC_VERSION 0x03 /* 0x01 */
#define IRCC_INTERFACE 0x04 /* low 4 = DMA, high 4 = IRQ */
-#define IRCC_INTERFACE_DMA_MASK 0x0F /* low 4 = DMA, high 4 = IRQ */
-#define IRCC_INTERFACE_IRQ_MASK 0xF0 /* low 4 = DMA, high 4 = IRQ */
+#define IRCC_INTERFACE_DMA_MASK 0x0F /* low 4 = DMA, high 4 = IRQ */
+#define IRCC_INTERFACE_IRQ_MASK 0xF0 /* low 4 = DMA, high 4 = IRQ */
/* Register block 4 - IrDA */
#define IRCC_CONTROL 0x00
@@ -163,10 +163,10 @@
/* Register block 5 - IrDA */
#define IRCC_ATC 0x00
-#define IRCC_ATC_nPROGREADY 0x80
-#define IRCC_ATC_SPEED 0x40
-#define IRCC_ATC_ENABLE 0x20
-#define IRCC_ATC_MASK 0xE0
+#define IRCC_ATC_nPROGREADY 0x80
+#define IRCC_ATC_SPEED 0x40
+#define IRCC_ATC_ENABLE 0x20
+#define IRCC_ATC_MASK 0xE0
#define IRCC_IRHALFDUPLEX_TIMEOUT 0x01
@@ -178,8 +178,8 @@
*/
#define SMSC_IRCC2_MAX_SIR_SPEED 115200
-#define SMSC_IRCC2_FIR_CHIP_IO_EXTENT 8
-#define SMSC_IRCC2_SIR_CHIP_IO_EXTENT 8
+#define SMSC_IRCC2_FIR_CHIP_IO_EXTENT 8
+#define SMSC_IRCC2_SIR_CHIP_IO_EXTENT 8
#define SMSC_IRCC2_FIFO_SIZE 16
#define SMSC_IRCC2_FIFO_THRESHOLD 64
/* Max DMA buffer size needed = (data_size + 6) * (window_size) + 6; */
diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c
index 4598c6a9212d..97f723179f62 100644
--- a/drivers/parport/parport_pc.c
+++ b/drivers/parport/parport_pc.c
@@ -2739,6 +2739,7 @@ enum parport_pc_pci_cards {
syba_2p_epp,
syba_1p_ecp,
titan_010l,
+ titan_1284p1,
titan_1284p2,
avlab_1p,
avlab_2p,
@@ -2811,6 +2812,7 @@ static struct parport_pc_pci {
/* syba_2p_epp AP138B */ { 2, { { 0, 0x078 }, { 0, 0x178 }, } },
/* syba_1p_ecp W83787 */ { 1, { { 0, 0x078 }, } },
/* titan_010l */ { 1, { { 3, -1 }, } },
+ /* titan_1284p1 */ { 1, { { 0, 1 }, } },
/* titan_1284p2 */ { 2, { { 0, 1 }, { 2, 3 }, } },
/* avlab_1p */ { 1, { { 0, 1}, } },
/* avlab_2p */ { 2, { { 0, 1}, { 2, 3 },} },
@@ -2884,6 +2886,7 @@ static struct pci_device_id parport_pc_pci_tbl[] = {
PCI_ANY_ID, PCI_ANY_ID, 0, 0, syba_1p_ecp },
{ PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_010L,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, titan_010l },
+ { 0x9710, 0x9805, 0x1000, 0x0010, 0, 0, titan_1284p1 },
{ 0x9710, 0x9815, 0x1000, 0x0020, 0, 0, titan_1284p2 },
/* PCI_VENDOR_ID_AVLAB/Intek21 has another bunch of cards ...*/
{ 0x14db, 0x2120, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1p}, /* AFAVLAB_TK9902 */
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index 2b85aa39f954..532f73bb2224 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -91,6 +91,7 @@ static void set_msi_affinity(unsigned int vector, cpumask_t cpu_mask)
{
struct msi_desc *entry;
struct msg_address address;
+ unsigned int irq = vector;
entry = (struct msi_desc *)msi_desc[vector];
if (!entry || !entry->dev)
@@ -112,6 +113,7 @@ static void set_msi_affinity(unsigned int vector, cpumask_t cpu_mask)
entry->msi_attrib.current_cpu = cpu_mask_to_apicid(cpu_mask);
pci_write_config_dword(entry->dev, msi_lower_address_reg(pos),
address.lo_address.value);
+ set_native_irq_info(irq, cpu_mask);
break;
}
case PCI_CAP_ID_MSIX:
@@ -125,22 +127,13 @@ static void set_msi_affinity(unsigned int vector, cpumask_t cpu_mask)
MSI_TARGET_CPU_SHIFT);
entry->msi_attrib.current_cpu = cpu_mask_to_apicid(cpu_mask);
writel(address.lo_address.value, entry->mask_base + offset);
+ set_native_irq_info(irq, cpu_mask);
break;
}
default:
break;
}
}
-
-#ifdef CONFIG_IRQBALANCE
-static inline void move_msi(int vector)
-{
- if (!cpus_empty(pending_irq_balance_cpumask[vector])) {
- set_msi_affinity(vector, pending_irq_balance_cpumask[vector]);
- cpus_clear(pending_irq_balance_cpumask[vector]);
- }
-}
-#endif /* CONFIG_IRQBALANCE */
#endif /* CONFIG_SMP */
static void mask_MSI_irq(unsigned int vector)
@@ -191,13 +184,13 @@ static void shutdown_msi_irq(unsigned int vector)
static void end_msi_irq_wo_maskbit(unsigned int vector)
{
- move_msi(vector);
+ move_native_irq(vector);
ack_APIC_irq();
}
static void end_msi_irq_w_maskbit(unsigned int vector)
{
- move_msi(vector);
+ move_native_irq(vector);
unmask_MSI_irq(vector);
ack_APIC_irq();
}
diff --git a/drivers/pci/msi.h b/drivers/pci/msi.h
index 390f1851c0f1..402136a5c9e4 100644
--- a/drivers/pci/msi.h
+++ b/drivers/pci/msi.h
@@ -19,7 +19,6 @@
#define NR_HP_RESERVED_VECTORS 20
extern int vector_irq[NR_VECTORS];
-extern cpumask_t pending_irq_balance_cpumask[NR_IRQS];
extern void (*interrupt[NR_IRQS])(void);
extern int pci_vector_resources(int last, int nr_released);
@@ -29,10 +28,6 @@ extern int pci_vector_resources(int last, int nr_released);
#define set_msi_irq_affinity NULL
#endif
-#ifndef CONFIG_IRQBALANCE
-static inline void move_msi(int vector) {}
-#endif
-
/*
* MSI-X Address Register
*/
diff --git a/drivers/pcmcia/topic.h b/drivers/pcmcia/topic.h
index be420bb29113..edccfa5bb400 100644
--- a/drivers/pcmcia/topic.h
+++ b/drivers/pcmcia/topic.h
@@ -101,6 +101,8 @@
#define TOPIC97_AVS_AUDIO_CONTROL 0x02
#define TOPIC97_AVS_VIDEO_CONTROL 0x01
+#define TOPIC_EXCA_IF_CONTROL 0x3e /* 8 bit */
+#define TOPIC_EXCA_IFC_33V_ENA 0x01
static void topic97_zoom_video(struct pcmcia_socket *sock, int onoff)
{
@@ -137,4 +139,19 @@ static int topic97_override(struct yenta_socket *socket)
return 0;
}
+
+static int topic95_override(struct yenta_socket *socket)
+{
+ u8 fctrl;
+
+ /* enable 3.3V support for 16bit cards */
+ fctrl = exca_readb(socket, TOPIC_EXCA_IF_CONTROL);
+ exca_writeb(socket, TOPIC_EXCA_IF_CONTROL, fctrl | TOPIC_EXCA_IFC_33V_ENA);
+
+ /* tell yenta to use exca registers to power 16bit cards */
+ socket->flags |= YENTA_16BIT_POWER_EXCA | YENTA_16BIT_POWER_DF;
+
+ return 0;
+}
+
#endif /* _LINUX_TOPIC_H */
diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c
index 62fd705203fb..0347a29f297b 100644
--- a/drivers/pcmcia/yenta_socket.c
+++ b/drivers/pcmcia/yenta_socket.c
@@ -184,22 +184,52 @@ static int yenta_get_status(struct pcmcia_socket *sock, unsigned int *value)
return 0;
}
-static int yenta_Vcc_power(u32 control)
+static void yenta_get_power(struct yenta_socket *socket, socket_state_t *state)
{
- switch (control & CB_SC_VCC_MASK) {
- case CB_SC_VCC_5V: return 50;
- case CB_SC_VCC_3V: return 33;
- default: return 0;
- }
-}
+ if (!(cb_readl(socket, CB_SOCKET_STATE) & CB_CBCARD) &&
+ (socket->flags & YENTA_16BIT_POWER_EXCA)) {
+ u8 reg, vcc, vpp;
+
+ reg = exca_readb(socket, I365_POWER);
+ vcc = reg & I365_VCC_MASK;
+ vpp = reg & I365_VPP1_MASK;
+ state->Vcc = state->Vpp = 0;
+
+ if (socket->flags & YENTA_16BIT_POWER_DF) {
+ if (vcc == I365_VCC_3V)
+ state->Vcc = 33;
+ if (vcc == I365_VCC_5V)
+ state->Vcc = 50;
+ if (vpp == I365_VPP1_5V)
+ state->Vpp = state->Vcc;
+ if (vpp == I365_VPP1_12V)
+ state->Vpp = 120;
+ } else {
+ if (reg & I365_VCC_5V) {
+ state->Vcc = 50;
+ if (vpp == I365_VPP1_5V)
+ state->Vpp = 50;
+ if (vpp == I365_VPP1_12V)
+ state->Vpp = 120;
+ }
+ }
+ } else {
+ u32 control;
-static int yenta_Vpp_power(u32 control)
-{
- switch (control & CB_SC_VPP_MASK) {
- case CB_SC_VPP_12V: return 120;
- case CB_SC_VPP_5V: return 50;
- case CB_SC_VPP_3V: return 33;
- default: return 0;
+ control = cb_readl(socket, CB_SOCKET_CONTROL);
+
+ switch (control & CB_SC_VCC_MASK) {
+ case CB_SC_VCC_5V: state->Vcc = 50; break;
+ case CB_SC_VCC_3V: state->Vcc = 33; break;
+ default: state->Vcc = 0;
+ }
+
+ switch (control & CB_SC_VPP_MASK) {
+ case CB_SC_VPP_12V: state->Vpp = 120; break;
+ case CB_SC_VPP_5V: state->Vpp = 50; break;
+ case CB_SC_VPP_3V: state->Vpp = 33; break;
+ default: state->Vpp = 0;
+ }
}
}
@@ -211,8 +241,7 @@ static int yenta_get_socket(struct pcmcia_socket *sock, socket_state_t *state)
control = cb_readl(socket, CB_SOCKET_CONTROL);
- state->Vcc = yenta_Vcc_power(control);
- state->Vpp = yenta_Vpp_power(control);
+ yenta_get_power(socket, state);
state->io_irq = socket->io_irq;
if (cb_readl(socket, CB_SOCKET_STATE) & CB_CBCARD) {
@@ -246,19 +275,54 @@ static int yenta_get_socket(struct pcmcia_socket *sock, socket_state_t *state)
static void yenta_set_power(struct yenta_socket *socket, socket_state_t *state)
{
- u32 reg = 0; /* CB_SC_STPCLK? */
- switch (state->Vcc) {
- case 33: reg = CB_SC_VCC_3V; break;
- case 50: reg = CB_SC_VCC_5V; break;
- default: reg = 0; break;
- }
- switch (state->Vpp) {
- case 33: reg |= CB_SC_VPP_3V; break;
- case 50: reg |= CB_SC_VPP_5V; break;
- case 120: reg |= CB_SC_VPP_12V; break;
+ /* some birdges require to use the ExCA registers to power 16bit cards */
+ if (!(cb_readl(socket, CB_SOCKET_STATE) & CB_CBCARD) &&
+ (socket->flags & YENTA_16BIT_POWER_EXCA)) {
+ u8 reg, old;
+ reg = old = exca_readb(socket, I365_POWER);
+ reg &= ~(I365_VCC_MASK | I365_VPP1_MASK | I365_VPP2_MASK);
+
+ /* i82365SL-DF style */
+ if (socket->flags & YENTA_16BIT_POWER_DF) {
+ switch (state->Vcc) {
+ case 33: reg |= I365_VCC_3V; break;
+ case 50: reg |= I365_VCC_5V; break;
+ default: reg = 0; break;
+ }
+ switch (state->Vpp) {
+ case 33:
+ case 50: reg |= I365_VPP1_5V; break;
+ case 120: reg |= I365_VPP1_12V; break;
+ }
+ } else {
+ /* i82365SL-B style */
+ switch (state->Vcc) {
+ case 50: reg |= I365_VCC_5V; break;
+ default: reg = 0; break;
+ }
+ switch (state->Vpp) {
+ case 50: reg |= I365_VPP1_5V | I365_VPP2_5V; break;
+ case 120: reg |= I365_VPP1_12V | I365_VPP2_12V; break;
+ }
+ }
+
+ if (reg != old)
+ exca_writeb(socket, I365_POWER, reg);
+ } else {
+ u32 reg = 0; /* CB_SC_STPCLK? */
+ switch (state->Vcc) {
+ case 33: reg = CB_SC_VCC_3V; break;
+ case 50: reg = CB_SC_VCC_5V; break;
+ default: reg = 0; break;
+ }
+ switch (state->Vpp) {
+ case 33: reg |= CB_SC_VPP_3V; break;
+ case 50: reg |= CB_SC_VPP_5V; break;
+ case 120: reg |= CB_SC_VPP_12V; break;
+ }
+ if (reg != cb_readl(socket, CB_SOCKET_CONTROL))
+ cb_writel(socket, CB_SOCKET_CONTROL, reg);
}
- if (reg != cb_readl(socket, CB_SOCKET_CONTROL))
- cb_writel(socket, CB_SOCKET_CONTROL, reg);
}
static int yenta_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
@@ -751,6 +815,7 @@ enum {
CARDBUS_TYPE_TI12XX,
CARDBUS_TYPE_TI1250,
CARDBUS_TYPE_RICOH,
+ CARDBUS_TYPE_TOPIC95,
CARDBUS_TYPE_TOPIC97,
CARDBUS_TYPE_O2MICRO,
};
@@ -789,6 +854,9 @@ static struct cardbus_type cardbus_type[] = {
.save_state = ricoh_save_state,
.restore_state = ricoh_restore_state,
},
+ [CARDBUS_TYPE_TOPIC95] = {
+ .override = topic95_override,
+ },
[CARDBUS_TYPE_TOPIC97] = {
.override = topic97_override,
},
@@ -1196,6 +1264,7 @@ static struct pci_device_id yenta_table [] = {
CB_ID(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C476, RICOH),
CB_ID(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C478, RICOH),
+ CB_ID(PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_TOSHIBA_TOPIC95, TOPIC95),
CB_ID(PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_TOSHIBA_TOPIC97, TOPIC97),
CB_ID(PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_TOSHIBA_TOPIC100, TOPIC97),
diff --git a/drivers/pcmcia/yenta_socket.h b/drivers/pcmcia/yenta_socket.h
index 4e637eef2076..4e75e9e258cd 100644
--- a/drivers/pcmcia/yenta_socket.h
+++ b/drivers/pcmcia/yenta_socket.h
@@ -95,6 +95,12 @@
*/
#define CB_MEM_PAGE(map) (0x40 + (map))
+
+/* control how 16bit cards are powered */
+#define YENTA_16BIT_POWER_EXCA 0x00000001
+#define YENTA_16BIT_POWER_DF 0x00000002
+
+
struct yenta_socket;
struct cardbus_type {
@@ -113,6 +119,8 @@ struct yenta_socket {
struct pcmcia_socket socket;
struct cardbus_type *type;
+ u32 flags;
+
/* for PCI interrupt probing */
unsigned int probe_status;
diff --git a/drivers/pnp/card.c b/drivers/pnp/card.c
index 6e5229e92fbc..e95ed67d4f05 100644
--- a/drivers/pnp/card.c
+++ b/drivers/pnp/card.c
@@ -8,13 +8,6 @@
#include <linux/config.h>
#include <linux/module.h>
#include <linux/slab.h>
-
-#ifdef CONFIG_PNP_DEBUG
- #define DEBUG
-#else
- #undef DEBUG
-#endif
-
#include <linux/pnp.h>
#include "base.h"
diff --git a/drivers/pnp/driver.c b/drivers/pnp/driver.c
index 1d037c2a82ac..33da25f3213f 100644
--- a/drivers/pnp/driver.c
+++ b/drivers/pnp/driver.c
@@ -11,13 +11,6 @@
#include <linux/module.h>
#include <linux/ctype.h>
#include <linux/slab.h>
-
-#ifdef CONFIG_PNP_DEBUG
- #define DEBUG
-#else
- #undef DEBUG
-#endif
-
#include <linux/pnp.h>
#include "base.h"
diff --git a/drivers/pnp/isapnp/core.c b/drivers/pnp/isapnp/core.c
index 82c5edd5b9ee..beedd86800f4 100644
--- a/drivers/pnp/isapnp/core.c
+++ b/drivers/pnp/isapnp/core.c
@@ -142,17 +142,6 @@ static void isapnp_write_word(unsigned char idx, unsigned short val)
isapnp_write_byte(idx+1, val);
}
-static void *isapnp_alloc(long size)
-{
- void *result;
-
- result = kmalloc(size, GFP_KERNEL);
- if (!result)
- return NULL;
- memset(result, 0, size);
- return result;
-}
-
static void isapnp_key(void)
{
unsigned char code = 0x6a, msb;
@@ -406,7 +395,7 @@ static void isapnp_parse_id(struct pnp_dev * dev, unsigned short vendor, unsigne
struct pnp_id * id;
if (!dev)
return;
- id = isapnp_alloc(sizeof(struct pnp_id));
+ id = kcalloc(1, sizeof(struct pnp_id), GFP_KERNEL);
if (!id)
return;
sprintf(id->id, "%c%c%c%x%x%x%x",
@@ -430,7 +419,7 @@ static struct pnp_dev * __init isapnp_parse_device(struct pnp_card *card, int si
struct pnp_dev *dev;
isapnp_peek(tmp, size);
- dev = isapnp_alloc(sizeof(struct pnp_dev));
+ dev = kcalloc(1, sizeof(struct pnp_dev), GFP_KERNEL);
if (!dev)
return NULL;
dev->number = number;
@@ -461,7 +450,7 @@ static void __init isapnp_parse_irq_resource(struct pnp_option *option,
unsigned long bits;
isapnp_peek(tmp, size);
- irq = isapnp_alloc(sizeof(struct pnp_irq));
+ irq = kcalloc(1, sizeof(struct pnp_irq), GFP_KERNEL);
if (!irq)
return;
bits = (tmp[1] << 8) | tmp[0];
@@ -485,7 +474,7 @@ static void __init isapnp_parse_dma_resource(struct pnp_option *option,
struct pnp_dma *dma;
isapnp_peek(tmp, size);
- dma = isapnp_alloc(sizeof(struct pnp_dma));
+ dma = kcalloc(1, sizeof(struct pnp_dma), GFP_KERNEL);
if (!dma)
return;
dma->map = tmp[0];
@@ -505,7 +494,7 @@ static void __init isapnp_parse_port_resource(struct pnp_option *option,
struct pnp_port *port;
isapnp_peek(tmp, size);
- port = isapnp_alloc(sizeof(struct pnp_port));
+ port = kcalloc(1, sizeof(struct pnp_port), GFP_KERNEL);
if (!port)
return;
port->min = (tmp[2] << 8) | tmp[1];
@@ -528,7 +517,7 @@ static void __init isapnp_parse_fixed_port_resource(struct pnp_option *option,
struct pnp_port *port;
isapnp_peek(tmp, size);
- port = isapnp_alloc(sizeof(struct pnp_port));
+ port = kcalloc(1, sizeof(struct pnp_port), GFP_KERNEL);
if (!port)
return;
port->min = port->max = (tmp[1] << 8) | tmp[0];
@@ -550,7 +539,7 @@ static void __init isapnp_parse_mem_resource(struct pnp_option *option,
struct pnp_mem *mem;
isapnp_peek(tmp, size);
- mem = isapnp_alloc(sizeof(struct pnp_mem));
+ mem = kcalloc(1, sizeof(struct pnp_mem), GFP_KERNEL);
if (!mem)
return;
mem->min = ((tmp[2] << 8) | tmp[1]) << 8;
@@ -573,7 +562,7 @@ static void __init isapnp_parse_mem32_resource(struct pnp_option *option,
struct pnp_mem *mem;
isapnp_peek(tmp, size);
- mem = isapnp_alloc(sizeof(struct pnp_mem));
+ mem = kcalloc(1, sizeof(struct pnp_mem), GFP_KERNEL);
if (!mem)
return;
mem->min = (tmp[4] << 24) | (tmp[3] << 16) | (tmp[2] << 8) | tmp[1];
@@ -595,7 +584,7 @@ static void __init isapnp_parse_fixed_mem32_resource(struct pnp_option *option,
struct pnp_mem *mem;
isapnp_peek(tmp, size);
- mem = isapnp_alloc(sizeof(struct pnp_mem));
+ mem = kcalloc(1, sizeof(struct pnp_mem), GFP_KERNEL);
if (!mem)
return;
mem->min = mem->max = (tmp[4] << 24) | (tmp[3] << 16) | (tmp[2] << 8) | tmp[1];
@@ -838,7 +827,7 @@ static unsigned char __init isapnp_checksum(unsigned char *data)
static void isapnp_parse_card_id(struct pnp_card * card, unsigned short vendor, unsigned short device)
{
- struct pnp_id * id = isapnp_alloc(sizeof(struct pnp_id));
+ struct pnp_id * id = kcalloc(1, sizeof(struct pnp_id), GFP_KERNEL);
if (!id)
return;
sprintf(id->id, "%c%c%c%x%x%x%x",
@@ -874,7 +863,7 @@ static int __init isapnp_build_device_list(void)
header[4], header[5], header[6], header[7], header[8]);
printk(KERN_DEBUG "checksum = 0x%x\n", checksum);
#endif
- if ((card = isapnp_alloc(sizeof(struct pnp_card))) == NULL)
+ if ((card = kcalloc(1, sizeof(struct pnp_card), GFP_KERNEL)) == NULL)
continue;
card->number = csn;
diff --git a/drivers/pnp/manager.c b/drivers/pnp/manager.c
index 6c510c19ad7d..94442ffd4aed 100644
--- a/drivers/pnp/manager.c
+++ b/drivers/pnp/manager.c
@@ -11,13 +11,6 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
-
-#ifdef CONFIG_PNP_DEBUG
- #define DEBUG
-#else
- #undef DEBUG
-#endif
-
#include <linux/pnp.h>
#include "base.h"
diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c
index 8655dd2e5b83..1a8915e74160 100644
--- a/drivers/pnp/pnpacpi/core.c
+++ b/drivers/pnp/pnpacpi/core.c
@@ -19,6 +19,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include <linux/config.h>
#include <linux/acpi.h>
#include <linux/pnp.h>
#include <acpi/acpi_bus.h>
@@ -41,14 +42,6 @@ static inline int is_exclusive_device(struct acpi_device *dev)
return (!acpi_match_ids(dev, excluded_id_list));
}
-void *pnpacpi_kmalloc(size_t size, int f)
-{
- void *p = kmalloc(size, f);
- if (p)
- memset(p, 0, size);
- return p;
-}
-
/*
* Compatible Device IDs
*/
@@ -143,7 +136,7 @@ static int __init pnpacpi_add_device(struct acpi_device *device)
return 0;
pnp_dbg("ACPI device : hid %s", acpi_device_hid(device));
- dev = pnpacpi_kmalloc(sizeof(struct pnp_dev), GFP_KERNEL);
+ dev = kcalloc(1, sizeof(struct pnp_dev), GFP_KERNEL);
if (!dev) {
pnp_err("Out of memory");
return -ENOMEM;
@@ -173,7 +166,7 @@ static int __init pnpacpi_add_device(struct acpi_device *device)
dev->number = num;
/* set the initial values for the PnP device */
- dev_id = pnpacpi_kmalloc(sizeof(struct pnp_id), GFP_KERNEL);
+ dev_id = kcalloc(1, sizeof(struct pnp_id), GFP_KERNEL);
if (!dev_id)
goto err;
pnpidacpi_to_pnpid(acpi_device_hid(device), dev_id->id);
@@ -205,8 +198,7 @@ static int __init pnpacpi_add_device(struct acpi_device *device)
for (i = 0; i < cid_list->count; i++) {
if (!ispnpidacpi(cid_list->id[i].value))
continue;
- dev_id = pnpacpi_kmalloc(sizeof(struct pnp_id),
- GFP_KERNEL);
+ dev_id = kcalloc(1, sizeof(struct pnp_id), GFP_KERNEL);
if (!dev_id)
continue;
diff --git a/drivers/pnp/pnpacpi/pnpacpi.h b/drivers/pnp/pnpacpi/pnpacpi.h
index 76f907e09ee6..f28e2ed66fa3 100644
--- a/drivers/pnp/pnpacpi/pnpacpi.h
+++ b/drivers/pnp/pnpacpi/pnpacpi.h
@@ -5,7 +5,6 @@
#include <linux/acpi.h>
#include <linux/pnp.h>
-void *pnpacpi_kmalloc(size_t size, int f);
acpi_status pnpacpi_parse_allocated_resource(acpi_handle, struct pnp_resource_table*);
acpi_status pnpacpi_parse_resource_option_data(acpi_handle, struct pnp_dev*);
int pnpacpi_encode_resources(struct pnp_resource_table *, struct acpi_buffer *);
diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c
index 75575f6c349c..675b76a42403 100644
--- a/drivers/pnp/pnpacpi/rsparser.c
+++ b/drivers/pnp/pnpacpi/rsparser.c
@@ -244,7 +244,7 @@ static void pnpacpi_parse_dma_option(struct pnp_option *option, struct acpi_reso
if (p->number_of_channels == 0)
return;
- dma = pnpacpi_kmalloc(sizeof(struct pnp_dma), GFP_KERNEL);
+ dma = kcalloc(1, sizeof(struct pnp_dma), GFP_KERNEL);
if (!dma)
return;
@@ -300,7 +300,7 @@ static void pnpacpi_parse_irq_option(struct pnp_option *option,
if (p->number_of_interrupts == 0)
return;
- irq = pnpacpi_kmalloc(sizeof(struct pnp_irq), GFP_KERNEL);
+ irq = kcalloc(1, sizeof(struct pnp_irq), GFP_KERNEL);
if (!irq)
return;
@@ -321,7 +321,7 @@ static void pnpacpi_parse_ext_irq_option(struct pnp_option *option,
if (p->number_of_interrupts == 0)
return;
- irq = pnpacpi_kmalloc(sizeof(struct pnp_irq), GFP_KERNEL);
+ irq = kcalloc(1, sizeof(struct pnp_irq), GFP_KERNEL);
if (!irq)
return;
@@ -342,7 +342,7 @@ pnpacpi_parse_port_option(struct pnp_option *option,
if (io->range_length == 0)
return;
- port = pnpacpi_kmalloc(sizeof(struct pnp_port), GFP_KERNEL);
+ port = kcalloc(1, sizeof(struct pnp_port), GFP_KERNEL);
if (!port)
return;
port->min = io->min_base_address;
@@ -363,7 +363,7 @@ pnpacpi_parse_fixed_port_option(struct pnp_option *option,
if (io->range_length == 0)
return;
- port = pnpacpi_kmalloc(sizeof(struct pnp_port), GFP_KERNEL);
+ port = kcalloc(1, sizeof(struct pnp_port), GFP_KERNEL);
if (!port)
return;
port->min = port->max = io->base_address;
@@ -382,7 +382,7 @@ pnpacpi_parse_mem24_option(struct pnp_option *option,
if (p->range_length == 0)
return;
- mem = pnpacpi_kmalloc(sizeof(struct pnp_mem), GFP_KERNEL);
+ mem = kcalloc(1, sizeof(struct pnp_mem), GFP_KERNEL);
if (!mem)
return;
mem->min = p->min_base_address;
@@ -405,7 +405,7 @@ pnpacpi_parse_mem32_option(struct pnp_option *option,
if (p->range_length == 0)
return;
- mem = pnpacpi_kmalloc(sizeof(struct pnp_mem), GFP_KERNEL);
+ mem = kcalloc(1, sizeof(struct pnp_mem), GFP_KERNEL);
if (!mem)
return;
mem->min = p->min_base_address;
@@ -428,7 +428,7 @@ pnpacpi_parse_fixed_mem32_option(struct pnp_option *option,
if (p->range_length == 0)
return;
- mem = pnpacpi_kmalloc(sizeof(struct pnp_mem), GFP_KERNEL);
+ mem = kcalloc(1, sizeof(struct pnp_mem), GFP_KERNEL);
if (!mem)
return;
mem->min = mem->max = p->range_base_address;
@@ -612,7 +612,7 @@ int pnpacpi_build_resource_template(acpi_handle handle,
if (!res_cnt)
return -EINVAL;
buffer->length = sizeof(struct acpi_resource) * (res_cnt + 1) + 1;
- buffer->pointer = pnpacpi_kmalloc(buffer->length - 1, GFP_KERNEL);
+ buffer->pointer = kcalloc(1, buffer->length - 1, GFP_KERNEL);
if (!buffer->pointer)
return -ENOMEM;
pnp_dbg("Res cnt %d", res_cnt);
diff --git a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c
index 778a324028f4..f49674f07949 100644
--- a/drivers/pnp/pnpbios/core.c
+++ b/drivers/pnp/pnpbios/core.c
@@ -86,16 +86,6 @@ int pnp_bios_present(void)
struct pnp_dev_node_info node_info;
-void *pnpbios_kmalloc(size_t size, int f)
-{
- void *p = kmalloc( size, f );
- if ( p == NULL )
- printk(KERN_ERR "PnPBIOS: kmalloc() failed\n");
- else
- memset(p, 0, size);
- return p;
-}
-
/*
*
* DOCKING FUNCTIONS
@@ -121,10 +111,10 @@ static int pnp_dock_event(int dock, struct pnp_docking_station_info *info)
if (!current->fs->root) {
return -EAGAIN;
}
- if (!(envp = (char **) pnpbios_kmalloc (20 * sizeof (char *), GFP_KERNEL))) {
+ if (!(envp = (char **) kcalloc (20, sizeof (char *), GFP_KERNEL))) {
return -ENOMEM;
}
- if (!(buf = pnpbios_kmalloc (256, GFP_KERNEL))) {
+ if (!(buf = kcalloc (1, 256, GFP_KERNEL))) {
kfree (envp);
return -ENOMEM;
}
@@ -231,7 +221,7 @@ static int pnpbios_get_resources(struct pnp_dev * dev, struct pnp_resource_table
if(!pnpbios_is_dynamic(dev))
return -EPERM;
- node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
+ node = kcalloc(1, node_info.max_node_size, GFP_KERNEL);
if (!node)
return -1;
if (pnp_bios_get_dev_node(&nodenum, (char )PNPMODE_DYNAMIC, node)) {
@@ -254,7 +244,7 @@ static int pnpbios_set_resources(struct pnp_dev * dev, struct pnp_resource_table
if (!pnpbios_is_dynamic(dev))
return -EPERM;
- node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
+ node = kcalloc(1, node_info.max_node_size, GFP_KERNEL);
if (!node)
return -1;
if (pnp_bios_get_dev_node(&nodenum, (char )PNPMODE_DYNAMIC, node)) {
@@ -305,7 +295,7 @@ static int pnpbios_disable_resources(struct pnp_dev *dev)
if(dev->flags & PNPBIOS_NO_DISABLE || !pnpbios_is_dynamic(dev))
return -EPERM;
- node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
+ node = kcalloc(1, node_info.max_node_size, GFP_KERNEL);
if (!node)
return -ENOMEM;
@@ -347,7 +337,7 @@ static int insert_device(struct pnp_dev *dev, struct pnp_bios_node * node)
}
/* set the initial values for the PnP device */
- dev_id = pnpbios_kmalloc(sizeof(struct pnp_id), GFP_KERNEL);
+ dev_id = kcalloc(1, sizeof(struct pnp_id), GFP_KERNEL);
if (!dev_id)
return -1;
pnpid32_to_pnpid(node->eisa_id,id);
@@ -385,7 +375,7 @@ static void __init build_devlist(void)
struct pnp_bios_node *node;
struct pnp_dev *dev;
- node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
+ node = kcalloc(1, node_info.max_node_size, GFP_KERNEL);
if (!node)
return;
@@ -402,7 +392,7 @@ static void __init build_devlist(void)
break;
}
nodes_got++;
- dev = pnpbios_kmalloc(sizeof (struct pnp_dev), GFP_KERNEL);
+ dev = kcalloc(1, sizeof (struct pnp_dev), GFP_KERNEL);
if (!dev)
break;
if(insert_device(dev,node)<0)
diff --git a/drivers/pnp/pnpbios/pnpbios.h b/drivers/pnp/pnpbios/pnpbios.h
index 01896e705ed4..d8cb2fd1f127 100644
--- a/drivers/pnp/pnpbios/pnpbios.h
+++ b/drivers/pnp/pnpbios/pnpbios.h
@@ -26,7 +26,6 @@ union pnp_bios_install_struct {
extern int pnp_bios_present(void);
extern int pnpbios_dont_use_current_config;
-extern void *pnpbios_kmalloc(size_t size, int f);
extern int pnpbios_parse_data_stream(struct pnp_dev *dev, struct pnp_bios_node * node);
extern int pnpbios_read_resources_from_node(struct pnp_resource_table *res, struct pnp_bios_node * node);
diff --git a/drivers/pnp/pnpbios/proc.c b/drivers/pnp/pnpbios/proc.c
index 6bb8e1973fd4..5a3dfc97f5e9 100644
--- a/drivers/pnp/pnpbios/proc.c
+++ b/drivers/pnp/pnpbios/proc.c
@@ -87,7 +87,7 @@ static int proc_read_escd(char *buf, char **start, off_t pos,
return -EFBIG;
}
- tmpbuf = pnpbios_kmalloc(escd.escd_size, GFP_KERNEL);
+ tmpbuf = kcalloc(1, escd.escd_size, GFP_KERNEL);
if (!tmpbuf) return -ENOMEM;
if (pnp_bios_read_escd(tmpbuf, escd.nv_storage_base)) {
@@ -133,7 +133,7 @@ static int proc_read_devices(char *buf, char **start, off_t pos,
if (pos >= 0xff)
return 0;
- node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
+ node = kcalloc(1, node_info.max_node_size, GFP_KERNEL);
if (!node) return -ENOMEM;
for (nodenum=pos; nodenum<0xff; ) {
@@ -168,7 +168,7 @@ static int proc_read_node(char *buf, char **start, off_t pos,
u8 nodenum = (long)data;
int len;
- node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
+ node = kcalloc(1, node_info.max_node_size, GFP_KERNEL);
if (!node) return -ENOMEM;
if (pnp_bios_get_dev_node(&nodenum, boot, node)) {
kfree(node);
@@ -188,7 +188,7 @@ static int proc_write_node(struct file *file, const char __user *buf,
u8 nodenum = (long)data;
int ret = count;
- node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
+ node = kcalloc(1, node_info.max_node_size, GFP_KERNEL);
if (!node)
return -ENOMEM;
if (pnp_bios_get_dev_node(&nodenum, boot, node)) {
diff --git a/drivers/pnp/pnpbios/rsparser.c b/drivers/pnp/pnpbios/rsparser.c
index e305bb132c24..b0ca65b68645 100644
--- a/drivers/pnp/pnpbios/rsparser.c
+++ b/drivers/pnp/pnpbios/rsparser.c
@@ -247,7 +247,7 @@ static void
pnpbios_parse_mem_option(unsigned char *p, int size, struct pnp_option *option)
{
struct pnp_mem * mem;
- mem = pnpbios_kmalloc(sizeof(struct pnp_mem), GFP_KERNEL);
+ mem = kcalloc(1, sizeof(struct pnp_mem), GFP_KERNEL);
if (!mem)
return;
mem->min = ((p[5] << 8) | p[4]) << 8;
@@ -263,7 +263,7 @@ static void
pnpbios_parse_mem32_option(unsigned char *p, int size, struct pnp_option *option)
{
struct pnp_mem * mem;
- mem = pnpbios_kmalloc(sizeof(struct pnp_mem), GFP_KERNEL);
+ mem = kcalloc(1, sizeof(struct pnp_mem), GFP_KERNEL);
if (!mem)
return;
mem->min = (p[7] << 24) | (p[6] << 16) | (p[5] << 8) | p[4];
@@ -279,7 +279,7 @@ static void
pnpbios_parse_fixed_mem32_option(unsigned char *p, int size, struct pnp_option *option)
{
struct pnp_mem * mem;
- mem = pnpbios_kmalloc(sizeof(struct pnp_mem), GFP_KERNEL);
+ mem = kcalloc(1, sizeof(struct pnp_mem), GFP_KERNEL);
if (!mem)
return;
mem->min = mem->max = (p[7] << 24) | (p[6] << 16) | (p[5] << 8) | p[4];
@@ -296,7 +296,7 @@ pnpbios_parse_irq_option(unsigned char *p, int size, struct pnp_option *option)
struct pnp_irq * irq;
unsigned long bits;
- irq = pnpbios_kmalloc(sizeof(struct pnp_irq), GFP_KERNEL);
+ irq = kcalloc(1, sizeof(struct pnp_irq), GFP_KERNEL);
if (!irq)
return;
bits = (p[2] << 8) | p[1];
@@ -313,7 +313,7 @@ static void
pnpbios_parse_dma_option(unsigned char *p, int size, struct pnp_option *option)
{
struct pnp_dma * dma;
- dma = pnpbios_kmalloc(sizeof(struct pnp_dma), GFP_KERNEL);
+ dma = kcalloc(1, sizeof(struct pnp_dma), GFP_KERNEL);
if (!dma)
return;
dma->map = p[1];
@@ -326,7 +326,7 @@ static void
pnpbios_parse_port_option(unsigned char *p, int size, struct pnp_option *option)
{
struct pnp_port * port;
- port = pnpbios_kmalloc(sizeof(struct pnp_port), GFP_KERNEL);
+ port = kcalloc(1, sizeof(struct pnp_port), GFP_KERNEL);
if (!port)
return;
port->min = (p[3] << 8) | p[2];
@@ -342,7 +342,7 @@ static void
pnpbios_parse_fixed_port_option(unsigned char *p, int size, struct pnp_option *option)
{
struct pnp_port * port;
- port = pnpbios_kmalloc(sizeof(struct pnp_port), GFP_KERNEL);
+ port = kcalloc(1, sizeof(struct pnp_port), GFP_KERNEL);
if (!port)
return;
port->min = port->max = (p[2] << 8) | p[1];
@@ -530,7 +530,7 @@ pnpbios_parse_compatible_ids(unsigned char *p, unsigned char *end, struct pnp_de
case SMALL_TAG_COMPATDEVID: /* compatible ID */
if (len != 4)
goto len_err;
- dev_id = pnpbios_kmalloc(sizeof (struct pnp_id), GFP_KERNEL);
+ dev_id = kcalloc(1, sizeof (struct pnp_id), GFP_KERNEL);
if (!dev_id)
return NULL;
memset(dev_id, 0, sizeof(struct pnp_id));
diff --git a/drivers/pnp/quirks.c b/drivers/pnp/quirks.c
index 596a02d7e03d..8936b0cb2ec3 100644
--- a/drivers/pnp/quirks.c
+++ b/drivers/pnp/quirks.c
@@ -16,13 +16,6 @@
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/slab.h>
-
-#ifdef CONFIG_PNP_DEBUG
- #define DEBUG
-#else
- #undef DEBUG
-#endif
-
#include <linux/pnp.h>
#include "base.h"
diff --git a/drivers/pnp/support.c b/drivers/pnp/support.c
index b952aec49189..61fe998944bd 100644
--- a/drivers/pnp/support.c
+++ b/drivers/pnp/support.c
@@ -8,13 +8,6 @@
#include <linux/config.h>
#include <linux/module.h>
#include <linux/ctype.h>
-
-#ifdef CONFIG_PNP_DEBUG
- #define DEBUG
-#else
- #undef DEBUG
-#endif
-
#include <linux/pnp.h>
#include "base.h"
diff --git a/drivers/scsi/sata_qstor.c b/drivers/scsi/sata_qstor.c
index 029c2482e127..ffcdeb68641c 100644
--- a/drivers/scsi/sata_qstor.c
+++ b/drivers/scsi/sata_qstor.c
@@ -494,7 +494,7 @@ static int qs_port_start(struct ata_port *ap)
if (rc)
return rc;
qs_enter_reg_mode(ap);
- pp = kcalloc(1, sizeof(*pp), GFP_KERNEL);
+ pp = kzalloc(sizeof(*pp), GFP_KERNEL);
if (!pp) {
rc = -ENOMEM;
goto err_out;
diff --git a/drivers/serial/68328serial.c b/drivers/serial/68328serial.c
index 9097f2f7b12a..2efb317153ce 100644
--- a/drivers/serial/68328serial.c
+++ b/drivers/serial/68328serial.c
@@ -40,7 +40,6 @@
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/system.h>
-#include <asm/segment.h>
#include <asm/delay.h>
#include <asm/uaccess.h>
diff --git a/drivers/serial/68360serial.c b/drivers/serial/68360serial.c
index b116122e569a..170c9d2a749c 100644
--- a/drivers/serial/68360serial.c
+++ b/drivers/serial/68360serial.c
@@ -2474,8 +2474,7 @@ static struct tty_operations rs_360_ops = {
.tiocmset = rs_360_tiocmset,
};
-/* int __init rs_360_init(void) */
-int rs_360_init(void)
+static int __init rs_360_init(void)
{
struct serial_state * state;
ser_info_t *info;
@@ -2827,10 +2826,7 @@ int rs_360_init(void)
return 0;
}
-
-
-
-
+module_init(rs_360_init);
/* This must always be called before the rs_360_init() function, otherwise
* it blows away the port control information.
diff --git a/drivers/serial/crisv10.c b/drivers/serial/crisv10.c
index 5690594b257b..40d3e7139cfe 100644
--- a/drivers/serial/crisv10.c
+++ b/drivers/serial/crisv10.c
@@ -446,7 +446,6 @@ static char *serial_version = "$Revision: 1.25 $";
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/system.h>
-#include <asm/segment.h>
#include <asm/bitops.h>
#include <linux/delay.h>
diff --git a/drivers/serial/icom.c b/drivers/serial/icom.c
index 79f8df4d66b7..eb31125c6a30 100644
--- a/drivers/serial/icom.c
+++ b/drivers/serial/icom.c
@@ -56,7 +56,6 @@
#include <linux/bitops.h>
#include <asm/system.h>
-#include <asm/segment.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
diff --git a/drivers/serial/mcfserial.c b/drivers/serial/mcfserial.c
index 8c40167778de..43b03c55f453 100644
--- a/drivers/serial/mcfserial.c
+++ b/drivers/serial/mcfserial.c
@@ -40,7 +40,6 @@
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/system.h>
-#include <asm/segment.h>
#include <asm/semaphore.h>
#include <asm/delay.h>
#include <asm/coldfire.h>
diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c
index bb1db1959854..c466739428b2 100644
--- a/drivers/usb/atm/usbatm.c
+++ b/drivers/usb/atm/usbatm.c
@@ -960,7 +960,7 @@ int usbatm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id,
intf->altsetting->desc.bInterfaceNumber);
/* instance init */
- instance = kcalloc(1, sizeof(*instance) + sizeof(struct urb *) * (num_rcv_urbs + num_snd_urbs), GFP_KERNEL);
+ instance = kzalloc(sizeof(*instance) + sizeof(struct urb *) * (num_rcv_urbs + num_snd_urbs), GFP_KERNEL);
if (!instance) {
dev_dbg(dev, "%s: no memory for instance data!\n", __func__);
return -ENOMEM;
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 9f44e83c6a69..12ecdb03ee5f 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -1669,7 +1669,7 @@ struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,
{
struct usb_hcd *hcd;
- hcd = kcalloc(1, sizeof(*hcd) + driver->hcd_priv_size, GFP_KERNEL);
+ hcd = kzalloc(sizeof(*hcd) + driver->hcd_priv_size, GFP_KERNEL);
if (!hcd) {
dev_dbg (dev, "hcd alloc failed\n");
return NULL;
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index b56f25864ed6..4c972b57c7c3 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -638,7 +638,7 @@ iso_stream_alloc (unsigned mem_flags)
{
struct ehci_iso_stream *stream;
- stream = kcalloc(1, sizeof *stream, mem_flags);
+ stream = kzalloc(sizeof *stream, mem_flags);
if (likely (stream != NULL)) {
INIT_LIST_HEAD(&stream->td_list);
INIT_LIST_HEAD(&stream->free_list);
diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c
index 76cb496c5836..75128c371800 100644
--- a/drivers/usb/host/isp116x-hcd.c
+++ b/drivers/usb/host/isp116x-hcd.c
@@ -717,7 +717,7 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd,
}
/* avoid all allocations within spinlocks: request or endpoint */
if (!hep->hcpriv) {
- ep = kcalloc(1, sizeof *ep, mem_flags);
+ ep = kzalloc(sizeof *ep, mem_flags);
if (!ep)
return -ENOMEM;
}
diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c
index 80eaf659c198..d2a1fd40dfcb 100644
--- a/drivers/usb/host/sl811-hcd.c
+++ b/drivers/usb/host/sl811-hcd.c
@@ -835,7 +835,7 @@ static int sl811h_urb_enqueue(
/* avoid all allocations within spinlocks */
if (!hep->hcpriv)
- ep = kcalloc(1, sizeof *ep, mem_flags);
+ ep = kzalloc(sizeof *ep, mem_flags);
spin_lock_irqsave(&sl811->lock, flags);
diff --git a/drivers/usb/input/acecad.c b/drivers/usb/input/acecad.c
index 13532f3e3efc..74f8760d7c07 100644
--- a/drivers/usb/input/acecad.c
+++ b/drivers/usb/input/acecad.c
@@ -152,7 +152,7 @@ static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_
pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
- acecad = kcalloc(1, sizeof(struct usb_acecad), GFP_KERNEL);
+ acecad = kzalloc(sizeof(struct usb_acecad), GFP_KERNEL);
if (!acecad)
return -ENOMEM;
diff --git a/drivers/usb/input/itmtouch.c b/drivers/usb/input/itmtouch.c
index 0dc439f10823..becb87efb869 100644
--- a/drivers/usb/input/itmtouch.c
+++ b/drivers/usb/input/itmtouch.c
@@ -166,7 +166,7 @@ static int itmtouch_probe(struct usb_interface *intf, const struct usb_device_id
interface = intf->cur_altsetting;
endpoint = &interface->endpoint[0].desc;
- if (!(itmtouch = kcalloc(1, sizeof(struct itmtouch_dev), GFP_KERNEL))) {
+ if (!(itmtouch = kzalloc(sizeof(struct itmtouch_dev), GFP_KERNEL))) {
err("%s - Out of memory.", __FUNCTION__);
return -ENOMEM;
}
diff --git a/drivers/usb/input/pid.c b/drivers/usb/input/pid.c
index 256963863478..acc71ec560e9 100644
--- a/drivers/usb/input/pid.c
+++ b/drivers/usb/input/pid.c
@@ -263,7 +263,7 @@ int hid_pid_init(struct hid_device *hid)
struct hid_ff_pid *private;
struct hid_input *hidinput = list_entry(&hid->inputs, struct hid_input, list);
- private = hid->ff_private = kcalloc(1, sizeof(struct hid_ff_pid), GFP_KERNEL);
+ private = hid->ff_private = kzalloc(sizeof(struct hid_ff_pid), GFP_KERNEL);
if (!private)
return -ENOMEM;
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index 9aae884475be..4af321fae390 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -3,3 +3,4 @@
obj-$(CONFIG_LCD_CLASS_DEVICE) += lcd.o
obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o
obj-$(CONFIG_BACKLIGHT_CORGI) += corgi_bl.o
+obj-$(CONFIG_SHARP_LOCOMO) += locomolcd.o
diff --git a/drivers/video/backlight/locomolcd.c b/drivers/video/backlight/locomolcd.c
new file mode 100644
index 000000000000..ada6e75eb048
--- /dev/null
+++ b/drivers/video/backlight/locomolcd.c
@@ -0,0 +1,157 @@
+/*
+ * Backlight control code for Sharp Zaurus SL-5500
+ *
+ * Copyright 2005 John Lenz <lenz@cs.wisc.edu>
+ * Maintainer: Pavel Machek <pavel@suse.cz> (unless John wants to :-)
+ * GPL v2
+ *
+ * This driver assumes single CPU. That's okay, because collie is
+ * slightly old hardware, and noone is going to retrofit second CPU to
+ * old PDA.
+ */
+
+/* LCD power functions */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+
+#include <asm/hardware/locomo.h>
+#include <asm/irq.h>
+
+#ifdef CONFIG_SA1100_COLLIE
+#include <asm/arch/collie.h>
+#else
+#include <asm/arch/poodle.h>
+#endif
+
+extern void (*sa1100fb_lcd_power)(int on);
+
+static struct locomo_dev *locomolcd_dev;
+
+static void locomolcd_on(int comadj)
+{
+ locomo_gpio_set_dir(locomolcd_dev, LOCOMO_GPIO_LCD_VSHA_ON, 0);
+ locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_VSHA_ON, 1);
+ mdelay(2);
+
+ locomo_gpio_set_dir(locomolcd_dev, LOCOMO_GPIO_LCD_VSHD_ON, 0);
+ locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_VSHD_ON, 1);
+ mdelay(2);
+
+ locomo_m62332_senddata(locomolcd_dev, comadj, 0);
+ mdelay(5);
+
+ locomo_gpio_set_dir(locomolcd_dev, LOCOMO_GPIO_LCD_VEE_ON, 0);
+ locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_VEE_ON, 1);
+ mdelay(10);
+
+ /* TFTCRST | CPSOUT=0 | CPSEN */
+ locomo_writel(0x01, locomolcd_dev->mapbase + LOCOMO_TC);
+
+ /* Set CPSD */
+ locomo_writel(6, locomolcd_dev->mapbase + LOCOMO_CPSD);
+
+ /* TFTCRST | CPSOUT=0 | CPSEN */
+ locomo_writel((0x04 | 0x01), locomolcd_dev->mapbase + LOCOMO_TC);
+ mdelay(10);
+
+ locomo_gpio_set_dir(locomolcd_dev, LOCOMO_GPIO_LCD_MOD, 0);
+ locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_MOD, 1);
+}
+
+static void locomolcd_off(int comadj)
+{
+ /* TFTCRST=1 | CPSOUT=1 | CPSEN = 0 */
+ locomo_writel(0x06, locomolcd_dev->mapbase + LOCOMO_TC);
+ mdelay(1);
+
+ locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_VSHA_ON, 0);
+ mdelay(110);
+
+ locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_VEE_ON, 0);
+ mdelay(700);
+
+ /* TFTCRST=0 | CPSOUT=0 | CPSEN = 0 */
+ locomo_writel(0, locomolcd_dev->mapbase + LOCOMO_TC);
+ locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_MOD, 0);
+ locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_VSHD_ON, 0);
+}
+
+void locomolcd_power(int on)
+{
+ int comadj = 118;
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ if (!locomolcd_dev) {
+ local_irq_restore(flags);
+ return;
+ }
+
+ /* read comadj */
+#ifdef CONFIG_MACH_POODLE
+ comadj = 118;
+#else
+ comadj = 128;
+#endif
+
+ if (on)
+ locomolcd_on(comadj);
+ else
+ locomolcd_off(comadj);
+
+ local_irq_restore(flags);
+}
+EXPORT_SYMBOL(locomolcd_power);
+
+static int poodle_lcd_probe(struct locomo_dev *dev)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ locomolcd_dev = dev;
+
+ /* the poodle_lcd_power function is called for the first time
+ * from fs_initcall, which is before locomo is activated.
+ * We need to recall poodle_lcd_power here*/
+#ifdef CONFIG_MACH_POODLE
+ locomolcd_power(1);
+#endif
+ local_irq_restore(flags);
+ return 0;
+}
+
+static int poodle_lcd_remove(struct locomo_dev *dev)
+{
+ unsigned long flags;
+ local_irq_save(flags);
+ locomolcd_dev = NULL;
+ local_irq_restore(flags);
+ return 0;
+}
+
+static struct locomo_driver poodle_lcd_driver = {
+ .drv = {
+ .name = "locomo-backlight",
+ },
+ .devid = LOCOMO_DEVID_BACKLIGHT,
+ .probe = poodle_lcd_probe,
+ .remove = poodle_lcd_remove,
+};
+
+static int __init poodle_lcd_init(void)
+{
+ int ret = locomo_driver_register(&poodle_lcd_driver);
+ if (ret) return ret;
+
+#ifdef CONFIG_SA1100_COLLIE
+ sa1100fb_lcd_power = locomolcd_power;
+#endif
+ return 0;
+}
+device_initcall(poodle_lcd_init);
+
diff --git a/drivers/video/q40fb.c b/drivers/video/q40fb.c
index 71b69da0c40d..162012bb9264 100644
--- a/drivers/video/q40fb.c
+++ b/drivers/video/q40fb.c
@@ -21,7 +21,6 @@
#include <asm/uaccess.h>
#include <asm/setup.h>
-#include <asm/segment.h>
#include <asm/system.h>
#include <asm/q40_master.h>
#include <linux/fb.h>
diff --git a/drivers/video/w100fb.c b/drivers/video/w100fb.c
index adcda697ea60..0030c071da8f 100644
--- a/drivers/video/w100fb.c
+++ b/drivers/video/w100fb.c
@@ -5,9 +5,15 @@
*
* Copyright (C) 2002, ATI Corp.
* Copyright (C) 2004-2005 Richard Purdie
+ * Copyright (c) 2005 Ian Molton
*
* Rewritten for 2.6 by Richard Purdie <rpurdie@rpsys.net>
*
+ * Generic platform support by Ian Molton <spyro@f2s.com>
+ * and Richard Purdie <rpurdie@rpsys.net>
+ *
+ * w32xx support by Ian Molton
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
@@ -21,7 +27,7 @@
#include <linux/mm.h>
#include <linux/device.h>
#include <linux/string.h>
-#include <linux/proc_fs.h>
+#include <linux/vmalloc.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <video/w100fb.h>
@@ -30,114 +36,78 @@
/*
* Prototypes
*/
-static void w100fb_save_buffer(void);
-static void w100fb_clear_buffer(void);
-static void w100fb_restore_buffer(void);
-static void w100fb_clear_screen(u32 mode, long int offset);
-static void w100_resume(void);
static void w100_suspend(u32 mode);
-static void w100_init_qvga_rotation(u16 deg);
-static void w100_init_vga_rotation(u16 deg);
static void w100_vsync(void);
-static void w100_init_sharp_lcd(u32 mode);
-static void w100_pwm_setup(void);
-static void w100_InitExtMem(u32 mode);
-static void w100_hw_init(void);
-static u16 w100_set_fastsysclk(u16 Freq);
-
-static void lcdtg_hw_init(u32 mode);
-static void lcdtg_lcd_change(u32 mode);
-static void lcdtg_resume(void);
-static void lcdtg_suspend(void);
-
-
-/* Register offsets & lengths */
-#define REMAPPED_FB_LEN 0x15ffff
-
-#define BITS_PER_PIXEL 16
+static void w100_hw_init(struct w100fb_par*);
+static void w100_pwm_setup(struct w100fb_par*);
+static void w100_init_clocks(struct w100fb_par*);
+static void w100_setup_memory(struct w100fb_par*);
+static void w100_init_lcd(struct w100fb_par*);
+static void w100_set_dispregs(struct w100fb_par*);
+static void w100_update_enable(void);
+static void w100_update_disable(void);
+static void calc_hsync(struct w100fb_par *par);
+struct w100_pll_info *w100_get_xtal_table(unsigned int freq);
/* Pseudo palette size */
#define MAX_PALETTES 16
-/* for resolution change */
-#define LCD_MODE_INIT (-1)
-#define LCD_MODE_480 0
-#define LCD_MODE_320 1
-#define LCD_MODE_240 2
-#define LCD_MODE_640 3
-
-#define LCD_SHARP_QVGA 0
-#define LCD_SHARP_VGA 1
-
-#define LCD_MODE_PORTRAIT 0
-#define LCD_MODE_LANDSCAPE 1
-
#define W100_SUSPEND_EXTMEM 0
#define W100_SUSPEND_ALL 1
-/* General frame buffer data structures */
-struct w100fb_par {
- u32 xres;
- u32 yres;
- int fastsysclk_mode;
- int lcdMode;
- int rotation_flag;
- int blanking_flag;
- int comadj;
- int phadadj;
-};
-
-static struct w100fb_par *current_par;
+#define BITS_PER_PIXEL 16
/* Remapped addresses for base cfg, memmapped regs and the frame buffer itself */
static void *remapped_base;
static void *remapped_regs;
static void *remapped_fbuf;
-/* External Function */
-static void(*w100fb_ssp_send)(u8 adrs, u8 data);
+#define REMAPPED_FB_LEN 0x15ffff
+
+/* This is the offset in the w100's address space we map the current
+ framebuffer memory to. We use the position of external memory as
+ we can remap internal memory to there if external isn't present. */
+#define W100_FB_BASE MEM_EXT_BASE_VALUE
+
/*
* Sysfs functions
*/
-
-static ssize_t rotation_show(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t flip_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct fb_info *info = dev_get_drvdata(dev);
struct w100fb_par *par=info->par;
- return sprintf(buf, "%d\n",par->rotation_flag);
+ return sprintf(buf, "%d\n",par->flip);
}
-static ssize_t rotation_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t flip_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
- unsigned int rotate;
+ unsigned int flip;
struct fb_info *info = dev_get_drvdata(dev);
struct w100fb_par *par=info->par;
- rotate = simple_strtoul(buf, NULL, 10);
+ flip = simple_strtoul(buf, NULL, 10);
+
+ if (flip > 0)
+ par->flip = 1;
+ else
+ par->flip = 0;
- if (rotate > 0) par->rotation_flag = 1;
- else par->rotation_flag = 0;
+ w100_update_disable();
+ w100_set_dispregs(par);
+ w100_update_enable();
- if (par->lcdMode == LCD_MODE_320)
- w100_init_qvga_rotation(par->rotation_flag ? 270 : 90);
- else if (par->lcdMode == LCD_MODE_240)
- w100_init_qvga_rotation(par->rotation_flag ? 180 : 0);
- else if (par->lcdMode == LCD_MODE_640)
- w100_init_vga_rotation(par->rotation_flag ? 270 : 90);
- else if (par->lcdMode == LCD_MODE_480)
- w100_init_vga_rotation(par->rotation_flag ? 180 : 0);
+ calc_hsync(par);
return count;
}
-static DEVICE_ATTR(rotation, 0644, rotation_show, rotation_store);
+static DEVICE_ATTR(flip, 0644, flip_show, flip_store);
static ssize_t w100fb_reg_read(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
- unsigned long param;
- unsigned long regs;
+ unsigned long regs, param;
regs = simple_strtoul(buf, NULL, 16);
param = readl(remapped_regs + regs);
printk("Read Register 0x%08lX: 0x%08lX\n", regs, param);
@@ -148,8 +118,7 @@ static DEVICE_ATTR(reg_read, 0200, NULL, w100fb_reg_read);
static ssize_t w100fb_reg_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
- unsigned long regs;
- unsigned long param;
+ unsigned long regs, param;
sscanf(buf, "%lx %lx", &regs, &param);
if (regs <= 0x2000) {
@@ -163,54 +132,56 @@ static ssize_t w100fb_reg_write(struct device *dev, struct device_attribute *att
static DEVICE_ATTR(reg_write, 0200, NULL, w100fb_reg_write);
-static ssize_t fastsysclk_show(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t fastpllclk_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct fb_info *info = dev_get_drvdata(dev);
struct w100fb_par *par=info->par;
- return sprintf(buf, "%d\n",par->fastsysclk_mode);
+ return sprintf(buf, "%d\n",par->fastpll_mode);
}
-static ssize_t fastsysclk_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t fastpllclk_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
- int param;
struct fb_info *info = dev_get_drvdata(dev);
struct w100fb_par *par=info->par;
- param = simple_strtoul(buf, NULL, 10);
-
- if (param == 75) {
- printk("Set fastsysclk %d\n", param);
- par->fastsysclk_mode = param;
- w100_set_fastsysclk(par->fastsysclk_mode);
- } else if (param == 100) {
- printk("Set fastsysclk %d\n", param);
- par->fastsysclk_mode = param;
- w100_set_fastsysclk(par->fastsysclk_mode);
+ if (simple_strtoul(buf, NULL, 10) > 0) {
+ par->fastpll_mode=1;
+ printk("w100fb: Using fast system clock (if possible)\n");
+ } else {
+ par->fastpll_mode=0;
+ printk("w100fb: Using normal system clock\n");
}
+
+ w100_init_clocks(par);
+ calc_hsync(par);
+
return count;
}
-static DEVICE_ATTR(fastsysclk, 0644, fastsysclk_show, fastsysclk_store);
+static DEVICE_ATTR(fastpllclk, 0644, fastpllclk_show, fastpllclk_store);
/*
- * The touchscreen on this device needs certain information
- * from the video driver to function correctly. We export it here.
+ * Some touchscreens need hsync information from the video driver to
+ * function correctly. We export it here.
*/
-int w100fb_get_xres(void) {
- return current_par->xres;
-}
+unsigned long w100fb_get_hsynclen(struct device *dev)
+{
+ struct fb_info *info = dev_get_drvdata(dev);
+ struct w100fb_par *par=info->par;
-int w100fb_get_blanking(void) {
- return current_par->blanking_flag;
+ /* If display is blanked/suspended, hsync isn't active */
+ if (par->blanked)
+ return 0;
+ else
+ return par->hsync_len;
}
+EXPORT_SYMBOL(w100fb_get_hsynclen);
-int w100fb_get_fastsysclk(void) {
- return current_par->fastsysclk_mode;
+static void w100fb_clear_screen(struct w100fb_par *par)
+{
+ memset_io(remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE), 0, (par->xres * par->yres * BITS_PER_PIXEL/8));
}
-EXPORT_SYMBOL(w100fb_get_xres);
-EXPORT_SYMBOL(w100fb_get_blanking);
-EXPORT_SYMBOL(w100fb_get_fastsysclk);
/*
@@ -234,7 +205,6 @@ static int w100fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
* according to the RGB bitfield information.
*/
if (regno < MAX_PALETTES) {
-
u32 *pal = info->pseudo_palette;
val = (red & 0xf800) | ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);
@@ -250,115 +220,90 @@ static int w100fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
*/
static int w100fb_blank(int blank_mode, struct fb_info *info)
{
- struct w100fb_par *par;
- par=info->par;
+ struct w100fb_par *par = info->par;
+ struct w100_tg_info *tg = par->mach->tg;
switch(blank_mode) {
- case FB_BLANK_NORMAL: /* Normal blanking */
- case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */
- case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */
- case FB_BLANK_POWERDOWN: /* Poweroff */
- if (par->blanking_flag == 0) {
- w100fb_save_buffer();
- lcdtg_suspend();
- par->blanking_flag = 1;
+ case FB_BLANK_NORMAL: /* Normal blanking */
+ case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */
+ case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */
+ case FB_BLANK_POWERDOWN: /* Poweroff */
+ if (par->blanked == 0) {
+ if(tg && tg->suspend)
+ tg->suspend(par);
+ par->blanked = 1;
}
break;
case FB_BLANK_UNBLANK: /* Unblanking */
- if (par->blanking_flag != 0) {
- w100fb_restore_buffer();
- lcdtg_resume();
- par->blanking_flag = 0;
+ if (par->blanked != 0) {
+ if(tg && tg->resume)
+ tg->resume(par);
+ par->blanked = 0;
}
break;
}
return 0;
}
+
/*
* Change the resolution by calling the appropriate hardware functions
*/
-static void w100fb_changeres(int rotate_mode, u32 mode)
+static void w100fb_activate_var(struct w100fb_par *par)
{
- u16 rotation=0;
-
- switch(rotate_mode) {
- case LCD_MODE_LANDSCAPE:
- rotation=(current_par->rotation_flag ? 270 : 90);
- break;
- case LCD_MODE_PORTRAIT:
- rotation=(current_par->rotation_flag ? 180 : 0);
- break;
- }
+ struct w100_tg_info *tg = par->mach->tg;
- w100_pwm_setup();
- switch(mode) {
- case LCD_SHARP_QVGA:
- w100_vsync();
- w100_suspend(W100_SUSPEND_EXTMEM);
- w100_init_sharp_lcd(LCD_SHARP_QVGA);
- w100_init_qvga_rotation(rotation);
- w100_InitExtMem(LCD_SHARP_QVGA);
- w100fb_clear_screen(LCD_SHARP_QVGA, 0);
- lcdtg_lcd_change(LCD_SHARP_QVGA);
- break;
- case LCD_SHARP_VGA:
- w100fb_clear_screen(LCD_SHARP_QVGA, 0);
- writel(0xBFFFA000, remapped_regs + mmMC_EXT_MEM_LOCATION);
- w100_InitExtMem(LCD_SHARP_VGA);
- w100fb_clear_screen(LCD_SHARP_VGA, 0x200000);
- w100_vsync();
- w100_init_sharp_lcd(LCD_SHARP_VGA);
- if (rotation != 0)
- w100_init_vga_rotation(rotation);
- lcdtg_lcd_change(LCD_SHARP_VGA);
- break;
- }
+ w100_pwm_setup(par);
+ w100_setup_memory(par);
+ w100_init_clocks(par);
+ w100fb_clear_screen(par);
+ w100_vsync();
+
+ w100_update_disable();
+ w100_init_lcd(par);
+ w100_set_dispregs(par);
+ w100_update_enable();
+
+ calc_hsync(par);
+
+ if (!par->blanked && tg && tg->change)
+ tg->change(par);
}
-/*
- * Set up the display for the fb subsystem
+
+/* Select the smallest mode that allows the desired resolution to be
+ * displayed. If desired, the x and y parameters can be rounded up to
+ * match the selected mode.
*/
-static void w100fb_activate_var(struct fb_info *info)
+static struct w100_mode *w100fb_get_mode(struct w100fb_par *par, unsigned int *x, unsigned int *y, int saveval)
{
- u32 temp32;
- struct w100fb_par *par=info->par;
- struct fb_var_screeninfo *var = &info->var;
+ struct w100_mode *mode = NULL;
+ struct w100_mode *modelist = par->mach->modelist;
+ unsigned int best_x = 0xffffffff, best_y = 0xffffffff;
+ unsigned int i;
+
+ for (i = 0 ; i < par->mach->num_modes ; i++) {
+ if (modelist[i].xres >= *x && modelist[i].yres >= *y &&
+ modelist[i].xres < best_x && modelist[i].yres < best_y) {
+ best_x = modelist[i].xres;
+ best_y = modelist[i].yres;
+ mode = &modelist[i];
+ } else if(modelist[i].xres >= *y && modelist[i].yres >= *x &&
+ modelist[i].xres < best_y && modelist[i].yres < best_x) {
+ best_x = modelist[i].yres;
+ best_y = modelist[i].xres;
+ mode = &modelist[i];
+ }
+ }
- /* Set the hardware to 565 */
- temp32 = readl(remapped_regs + mmDISP_DEBUG2);
- temp32 &= 0xff7fffff;
- temp32 |= 0x00800000;
- writel(temp32, remapped_regs + mmDISP_DEBUG2);
+ if (mode && saveval) {
+ *x = best_x;
+ *y = best_y;
+ }
- if (par->lcdMode == LCD_MODE_INIT) {
- w100_init_sharp_lcd(LCD_SHARP_VGA);
- w100_init_vga_rotation(par->rotation_flag ? 270 : 90);
- par->lcdMode = LCD_MODE_640;
- lcdtg_hw_init(LCD_SHARP_VGA);
- } else if (var->xres == 320 && var->yres == 240) {
- if (par->lcdMode != LCD_MODE_320) {
- w100fb_changeres(LCD_MODE_LANDSCAPE, LCD_SHARP_QVGA);
- par->lcdMode = LCD_MODE_320;
- }
- } else if (var->xres == 240 && var->yres == 320) {
- if (par->lcdMode != LCD_MODE_240) {
- w100fb_changeres(LCD_MODE_PORTRAIT, LCD_SHARP_QVGA);
- par->lcdMode = LCD_MODE_240;
- }
- } else if (var->xres == 640 && var->yres == 480) {
- if (par->lcdMode != LCD_MODE_640) {
- w100fb_changeres(LCD_MODE_LANDSCAPE, LCD_SHARP_VGA);
- par->lcdMode = LCD_MODE_640;
- }
- } else if (var->xres == 480 && var->yres == 640) {
- if (par->lcdMode != LCD_MODE_480) {
- w100fb_changeres(LCD_MODE_PORTRAIT, LCD_SHARP_VGA);
- par->lcdMode = LCD_MODE_480;
- }
- } else printk(KERN_ERR "W100FB: Resolution error!\n");
+ return mode;
}
@@ -366,31 +311,19 @@ static void w100fb_activate_var(struct fb_info *info)
* w100fb_check_var():
* Get the video params out of 'var'. If a value doesn't fit, round it up,
* if it's too big, return -EINVAL.
- *
*/
static int w100fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
{
- if (var->xres < var->yres) { /* Portrait mode */
- if ((var->xres > 480) || (var->yres > 640)) {
- return -EINVAL;
- } else if ((var->xres > 240) || (var->yres > 320)) {
- var->xres = 480;
- var->yres = 640;
- } else {
- var->xres = 240;
- var->yres = 320;
- }
- } else { /* Landscape mode */
- if ((var->xres > 640) || (var->yres > 480)) {
- return -EINVAL;
- } else if ((var->xres > 320) || (var->yres > 240)) {
- var->xres = 640;
- var->yres = 480;
- } else {
- var->xres = 320;
- var->yres = 240;
- }
- }
+ struct w100fb_par *par=info->par;
+
+ if(!w100fb_get_mode(par, &var->xres, &var->yres, 1))
+ return -EINVAL;
+
+ if (par->mach->mem && ((var->xres*var->yres*BITS_PER_PIXEL/8) > (par->mach->mem->size+1)))
+ return -EINVAL;
+
+ if (!par->mach->mem && ((var->xres*var->yres*BITS_PER_PIXEL/8) > (MEM_INT_SIZE+1)))
+ return -EINVAL;
var->xres_virtual = max(var->xres_virtual, var->xres);
var->yres_virtual = max(var->yres_virtual, var->yres);
@@ -409,13 +342,11 @@ static int w100fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
var->transp.offset = var->transp.length = 0;
var->nonstd = 0;
-
var->height = -1;
var->width = -1;
var->vmode = FB_VMODE_NONINTERLACED;
-
var->sync = 0;
- var->pixclock = 0x04; /* 171521; */
+ var->pixclock = 0x04; /* 171521; */
return 0;
}
@@ -430,274 +361,286 @@ static int w100fb_set_par(struct fb_info *info)
{
struct w100fb_par *par=info->par;
- par->xres = info->var.xres;
- par->yres = info->var.yres;
-
- info->fix.visual = FB_VISUAL_TRUECOLOR;
-
- info->fix.ypanstep = 0;
- info->fix.ywrapstep = 0;
+ if (par->xres != info->var.xres || par->yres != info->var.yres) {
+ par->xres = info->var.xres;
+ par->yres = info->var.yres;
+ par->mode = w100fb_get_mode(par, &par->xres, &par->yres, 0);
- if (par->blanking_flag)
- w100fb_clear_buffer();
+ info->fix.visual = FB_VISUAL_TRUECOLOR;
+ info->fix.ypanstep = 0;
+ info->fix.ywrapstep = 0;
+ info->fix.line_length = par->xres * BITS_PER_PIXEL / 8;
- w100fb_activate_var(info);
+ if ((par->xres*par->yres*BITS_PER_PIXEL/8) > (MEM_INT_SIZE+1)) {
+ par->extmem_active = 1;
+ info->fix.smem_len = par->mach->mem->size+1;
+ } else {
+ par->extmem_active = 0;
+ info->fix.smem_len = MEM_INT_SIZE+1;
+ }
- if (par->lcdMode == LCD_MODE_480) {
- info->fix.line_length = (480 * BITS_PER_PIXEL) / 8;
- info->fix.smem_len = 0x200000;
- } else if (par->lcdMode == LCD_MODE_320) {
- info->fix.line_length = (320 * BITS_PER_PIXEL) / 8;
- info->fix.smem_len = 0x60000;
- } else if (par->lcdMode == LCD_MODE_240) {
- info->fix.line_length = (240 * BITS_PER_PIXEL) / 8;
- info->fix.smem_len = 0x60000;
- } else if (par->lcdMode == LCD_MODE_INIT || par->lcdMode == LCD_MODE_640) {
- info->fix.line_length = (640 * BITS_PER_PIXEL) / 8;
- info->fix.smem_len = 0x200000;
+ w100fb_activate_var(par);
}
-
return 0;
}
/*
- * Frame buffer operations
+ * Frame buffer operations
*/
static struct fb_ops w100fb_ops = {
- .owner = THIS_MODULE,
+ .owner = THIS_MODULE,
.fb_check_var = w100fb_check_var,
- .fb_set_par = w100fb_set_par,
+ .fb_set_par = w100fb_set_par,
.fb_setcolreg = w100fb_setcolreg,
- .fb_blank = w100fb_blank,
- .fb_fillrect = cfb_fillrect,
- .fb_copyarea = cfb_copyarea,
+ .fb_blank = w100fb_blank,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit,
- .fb_cursor = soft_cursor,
+ .fb_cursor = soft_cursor,
};
-
-static void w100fb_clear_screen(u32 mode, long int offset)
+#ifdef CONFIG_PM
+static void w100fb_save_vidmem(struct w100fb_par *par)
{
- int i, numPix = 0;
-
- if (mode == LCD_SHARP_VGA)
- numPix = 640 * 480;
- else if (mode == LCD_SHARP_QVGA)
- numPix = 320 * 240;
+ int memsize;
- for (i = 0; i < numPix; i++)
- writew(0xffff, remapped_fbuf + offset + (2*i));
-}
-
-
-/* Need to split up the buffers to stay within the limits of kmalloc */
-#define W100_BUF_NUM 6
-static uint32_t *gSaveImagePtr[W100_BUF_NUM] = { NULL };
-
-static void w100fb_save_buffer(void)
-{
- int i, j, bufsize;
-
- bufsize=(current_par->xres * current_par->yres * BITS_PER_PIXEL / 8) / W100_BUF_NUM;
- for (i = 0; i < W100_BUF_NUM; i++) {
- if (gSaveImagePtr[i] == NULL)
- gSaveImagePtr[i] = kmalloc(bufsize, GFP_KERNEL);
- if (gSaveImagePtr[i] == NULL) {
- w100fb_clear_buffer();
- printk(KERN_WARNING "can't alloc pre-off image buffer %d\n", i);
- break;
- }
- for (j = 0; j < bufsize/4; j++)
- *(gSaveImagePtr[i] + j) = readl(remapped_fbuf + (bufsize*i) + j*4);
+ if (par->extmem_active) {
+ memsize=par->mach->mem->size;
+ par->saved_extmem = vmalloc(memsize);
+ if (par->saved_extmem)
+ memcpy_fromio(par->saved_extmem, remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE), memsize);
}
+ memsize=MEM_INT_SIZE;
+ par->saved_intmem = vmalloc(memsize);
+ if (par->saved_intmem && par->extmem_active)
+ memcpy_fromio(par->saved_intmem, remapped_fbuf + (W100_FB_BASE-MEM_INT_BASE_VALUE), memsize);
+ else if (par->saved_intmem)
+ memcpy_fromio(par->saved_intmem, remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE), memsize);
}
-
-static void w100fb_restore_buffer(void)
+static void w100fb_restore_vidmem(struct w100fb_par *par)
{
- int i, j, bufsize;
+ int memsize;
- bufsize=(current_par->xres * current_par->yres * BITS_PER_PIXEL / 8) / W100_BUF_NUM;
- for (i = 0; i < W100_BUF_NUM; i++) {
- if (gSaveImagePtr[i] == NULL) {
- printk(KERN_WARNING "can't find pre-off image buffer %d\n", i);
- w100fb_clear_buffer();
- break;
- }
- for (j = 0; j < (bufsize/4); j++)
- writel(*(gSaveImagePtr[i] + j),remapped_fbuf + (bufsize*i) + (j*4));
- kfree(gSaveImagePtr[i]);
- gSaveImagePtr[i] = NULL;
+ if (par->extmem_active && par->saved_extmem) {
+ memsize=par->mach->mem->size;
+ memcpy_toio(remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE), par->saved_extmem, memsize);
+ vfree(par->saved_extmem);
}
-}
-
-
-static void w100fb_clear_buffer(void)
-{
- int i;
- for (i = 0; i < W100_BUF_NUM; i++) {
- kfree(gSaveImagePtr[i]);
- gSaveImagePtr[i] = NULL;
+ if (par->saved_intmem) {
+ memsize=MEM_INT_SIZE;
+ if (par->extmem_active)
+ memcpy_toio(remapped_fbuf + (W100_FB_BASE-MEM_INT_BASE_VALUE), par->saved_intmem, memsize);
+ else
+ memcpy_toio(remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE), par->saved_intmem, memsize);
+ vfree(par->saved_intmem);
}
}
-
-#ifdef CONFIG_PM
-static int w100fb_suspend(struct device *dev, pm_message_t state, u32 level)
+static int w100fb_suspend(struct device *dev, pm_message_t state, uint32_t level)
{
if (level == SUSPEND_POWER_DOWN) {
struct fb_info *info = dev_get_drvdata(dev);
struct w100fb_par *par=info->par;
+ struct w100_tg_info *tg = par->mach->tg;
- w100fb_save_buffer();
- lcdtg_suspend();
+ w100fb_save_vidmem(par);
+ if(tg && tg->suspend)
+ tg->suspend(par);
w100_suspend(W100_SUSPEND_ALL);
- par->blanking_flag = 1;
+ par->blanked = 1;
}
return 0;
}
-static int w100fb_resume(struct device *dev, u32 level)
+static int w100fb_resume(struct device *dev, uint32_t level)
{
if (level == RESUME_POWER_ON) {
struct fb_info *info = dev_get_drvdata(dev);
struct w100fb_par *par=info->par;
-
- w100_resume();
- w100fb_restore_buffer();
- lcdtg_resume();
- par->blanking_flag = 0;
+ struct w100_tg_info *tg = par->mach->tg;
+
+ w100_hw_init(par);
+ w100fb_activate_var(par);
+ w100fb_restore_vidmem(par);
+ if(tg && tg->resume)
+ tg->resume(par);
+ par->blanked = 0;
}
return 0;
}
#else
-#define w100fb_suspend NULL
-#define w100fb_resume NULL
+#define w100fb_suspend NULL
+#define w100fb_resume NULL
#endif
int __init w100fb_probe(struct device *dev)
{
+ int err = -EIO;
struct w100fb_mach_info *inf;
- struct fb_info *info;
+ struct fb_info *info = NULL;
struct w100fb_par *par;
struct platform_device *pdev = to_platform_device(dev);
struct resource *mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ unsigned int chip_id;
if (!mem)
return -EINVAL;
- /* remap the areas we're going to use */
+ /* Remap the chip base address */
remapped_base = ioremap_nocache(mem->start+W100_CFG_BASE, W100_CFG_LEN);
if (remapped_base == NULL)
- return -EIO;
+ goto out;
+ /* Map the register space */
remapped_regs = ioremap_nocache(mem->start+W100_REG_BASE, W100_REG_LEN);
- if (remapped_regs == NULL) {
- iounmap(remapped_base);
- return -EIO;
+ if (remapped_regs == NULL)
+ goto out;
+
+ /* Identify the chip */
+ printk("Found ");
+ chip_id = readl(remapped_regs + mmCHIP_ID);
+ switch(chip_id) {
+ case CHIP_ID_W100: printk("w100"); break;
+ case CHIP_ID_W3200: printk("w3200"); break;
+ case CHIP_ID_W3220: printk("w3220"); break;
+ default:
+ printk("Unknown imageon chip ID\n");
+ err = -ENODEV;
+ goto out;
}
+ printk(" at 0x%08lx.\n", mem->start+W100_CFG_BASE);
- remapped_fbuf = ioremap_nocache(mem->start+MEM_EXT_BASE_VALUE, REMAPPED_FB_LEN);
- if (remapped_fbuf == NULL) {
- iounmap(remapped_base);
- iounmap(remapped_regs);
- return -EIO;
- }
+ /* Remap the framebuffer */
+ remapped_fbuf = ioremap_nocache(mem->start+MEM_WINDOW_BASE, MEM_WINDOW_SIZE);
+ if (remapped_fbuf == NULL)
+ goto out;
info=framebuffer_alloc(sizeof(struct w100fb_par), dev);
if (!info) {
- iounmap(remapped_base);
- iounmap(remapped_regs);
- iounmap(remapped_fbuf);
- return -ENOMEM;
+ err = -ENOMEM;
+ goto out;
}
- info->device=dev;
par = info->par;
- current_par=info->par;
dev_set_drvdata(dev, info);
inf = dev->platform_data;
- par->phadadj = inf->phadadj;
- par->comadj = inf->comadj;
- par->fastsysclk_mode = 75;
- par->lcdMode = LCD_MODE_INIT;
- par->rotation_flag=0;
- par->blanking_flag=0;
- w100fb_ssp_send = inf->w100fb_ssp_send;
-
- w100_hw_init();
- w100_pwm_setup();
+ par->chip_id = chip_id;
+ par->mach = inf;
+ par->fastpll_mode = 0;
+ par->blanked = 0;
+
+ par->pll_table=w100_get_xtal_table(inf->xtal_freq);
+ if (!par->pll_table) {
+ printk(KERN_ERR "No matching Xtal definition found\n");
+ err = -EINVAL;
+ goto out;
+ }
info->pseudo_palette = kmalloc(sizeof (u32) * MAX_PALETTES, GFP_KERNEL);
if (!info->pseudo_palette) {
- iounmap(remapped_base);
- iounmap(remapped_regs);
- iounmap(remapped_fbuf);
- return -ENOMEM;
+ err = -ENOMEM;
+ goto out;
}
info->fbops = &w100fb_ops;
info->flags = FBINFO_DEFAULT;
info->node = -1;
- info->screen_base = remapped_fbuf;
+ info->screen_base = remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE);
info->screen_size = REMAPPED_FB_LEN;
- info->var.xres = 640;
+ strcpy(info->fix.id, "w100fb");
+ info->fix.type = FB_TYPE_PACKED_PIXELS;
+ info->fix.type_aux = 0;
+ info->fix.accel = FB_ACCEL_NONE;
+ info->fix.smem_start = mem->start+W100_FB_BASE;
+ info->fix.mmio_start = mem->start+W100_REG_BASE;
+ info->fix.mmio_len = W100_REG_LEN;
+
+ if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ par->mode = &inf->modelist[0];
+ if(inf->init_mode & INIT_MODE_ROTATED) {
+ info->var.xres = par->mode->yres;
+ info->var.yres = par->mode->xres;
+ }
+ else {
+ info->var.xres = par->mode->xres;
+ info->var.yres = par->mode->yres;
+ }
+
+ if(inf->init_mode &= INIT_MODE_FLIPPED)
+ par->flip = 1;
+ else
+ par->flip = 0;
+
info->var.xres_virtual = info->var.xres;
- info->var.yres = 480;
info->var.yres_virtual = info->var.yres;
- info->var.pixclock = 0x04; /* 171521; */
+ info->var.pixclock = 0x04; /* 171521; */
info->var.sync = 0;
info->var.grayscale = 0;
info->var.xoffset = info->var.yoffset = 0;
info->var.accel_flags = 0;
info->var.activate = FB_ACTIVATE_NOW;
- strcpy(info->fix.id, "w100fb");
- info->fix.type = FB_TYPE_PACKED_PIXELS;
- info->fix.type_aux = 0;
- info->fix.accel = FB_ACCEL_NONE;
- info->fix.smem_start = mem->start+MEM_EXT_BASE_VALUE;
- info->fix.mmio_start = mem->start+W100_REG_BASE;
- info->fix.mmio_len = W100_REG_LEN;
+ w100_hw_init(par);
+
+ if (w100fb_check_var(&info->var, info) < 0) {
+ err = -EINVAL;
+ goto out;
+ }
- w100fb_check_var(&info->var, info);
w100fb_set_par(info);
if (register_framebuffer(info) < 0) {
- kfree(info->pseudo_palette);
- iounmap(remapped_base);
- iounmap(remapped_regs);
- iounmap(remapped_fbuf);
- return -EINVAL;
+ err = -EINVAL;
+ goto out;
}
- device_create_file(dev, &dev_attr_fastsysclk);
+ device_create_file(dev, &dev_attr_fastpllclk);
device_create_file(dev, &dev_attr_reg_read);
device_create_file(dev, &dev_attr_reg_write);
- device_create_file(dev, &dev_attr_rotation);
+ device_create_file(dev, &dev_attr_flip);
printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, info->fix.id);
return 0;
+out:
+ fb_dealloc_cmap(&info->cmap);
+ kfree(info->pseudo_palette);
+ if (remapped_fbuf != NULL)
+ iounmap(remapped_fbuf);
+ if (remapped_regs != NULL)
+ iounmap(remapped_regs);
+ if (remapped_base != NULL)
+ iounmap(remapped_base);
+ if (info)
+ framebuffer_release(info);
+ return err;
}
static int w100fb_remove(struct device *dev)
{
struct fb_info *info = dev_get_drvdata(dev);
+ struct w100fb_par *par=info->par;
- device_remove_file(dev, &dev_attr_fastsysclk);
+ device_remove_file(dev, &dev_attr_fastpllclk);
device_remove_file(dev, &dev_attr_reg_read);
device_remove_file(dev, &dev_attr_reg_write);
- device_remove_file(dev, &dev_attr_rotation);
+ device_remove_file(dev, &dev_attr_flip);
unregister_framebuffer(info);
- w100fb_clear_buffer();
+ vfree(par->saved_intmem);
+ vfree(par->saved_extmem);
kfree(info->pseudo_palette);
+ fb_dealloc_cmap(&info->cmap);
iounmap(remapped_base);
iounmap(remapped_regs);
@@ -721,10 +664,54 @@ static void w100_soft_reset(void)
udelay(100);
}
+static void w100_update_disable(void)
+{
+ union disp_db_buf_cntl_wr_u disp_db_buf_wr_cntl;
+
+ /* Prevent display updates */
+ disp_db_buf_wr_cntl.f.db_buf_cntl = 0x1e;
+ disp_db_buf_wr_cntl.f.update_db_buf = 0;
+ disp_db_buf_wr_cntl.f.en_db_buf = 0;
+ writel((u32) (disp_db_buf_wr_cntl.val), remapped_regs + mmDISP_DB_BUF_CNTL);
+}
+
+static void w100_update_enable(void)
+{
+ union disp_db_buf_cntl_wr_u disp_db_buf_wr_cntl;
+
+ /* Enable display updates */
+ disp_db_buf_wr_cntl.f.db_buf_cntl = 0x1e;
+ disp_db_buf_wr_cntl.f.update_db_buf = 1;
+ disp_db_buf_wr_cntl.f.en_db_buf = 1;
+ writel((u32) (disp_db_buf_wr_cntl.val), remapped_regs + mmDISP_DB_BUF_CNTL);
+}
+
+unsigned long w100fb_gpio_read(int port)
+{
+ unsigned long value;
+
+ if (port==W100_GPIO_PORT_A)
+ value = readl(remapped_regs + mmGPIO_DATA);
+ else
+ value = readl(remapped_regs + mmGPIO_DATA2);
+
+ return value;
+}
+
+void w100fb_gpio_write(int port, unsigned long value)
+{
+ if (port==W100_GPIO_PORT_A)
+ value = writel(value, remapped_regs + mmGPIO_DATA);
+ else
+ value = writel(value, remapped_regs + mmGPIO_DATA2);
+}
+EXPORT_SYMBOL(w100fb_gpio_read);
+EXPORT_SYMBOL(w100fb_gpio_write);
+
/*
* Initialization of critical w100 hardware
*/
-static void w100_hw_init(void)
+static void w100_hw_init(struct w100fb_par *par)
{
u32 temp32;
union cif_cntl_u cif_cntl;
@@ -735,8 +722,8 @@ static void w100_hw_init(void)
union cpu_defaults_u cpu_default;
union cif_write_dbg_u cif_write_dbg;
union wrap_start_dir_u wrap_start_dir;
- union mc_ext_mem_location_u mc_ext_mem_loc;
union cif_io_u cif_io;
+ struct w100_gpio_regs *gpio = par->mach->gpio;
w100_soft_reset();
@@ -791,19 +778,6 @@ static void w100_hw_init(void)
cfgreg_base.f.cfgreg_base = W100_CFG_BASE;
writel((u32) (cfgreg_base.val), remapped_regs + mmCFGREG_BASE);
- /* This location is relative to internal w100 addresses */
- writel(0x15FF1000, remapped_regs + mmMC_FB_LOCATION);
-
- mc_ext_mem_loc.val = defMC_EXT_MEM_LOCATION;
- mc_ext_mem_loc.f.mc_ext_mem_start = MEM_EXT_BASE_VALUE >> 8;
- mc_ext_mem_loc.f.mc_ext_mem_top = MEM_EXT_TOP_VALUE >> 8;
- writel((u32) (mc_ext_mem_loc.val), remapped_regs + mmMC_EXT_MEM_LOCATION);
-
- if ((current_par->lcdMode == LCD_MODE_240) || (current_par->lcdMode == LCD_MODE_320))
- w100_InitExtMem(LCD_SHARP_QVGA);
- else
- w100_InitExtMem(LCD_SHARP_VGA);
-
wrap_start_dir.val = defWRAP_START_DIR;
wrap_start_dir.f.start_addr = WRAP_BUF_BASE_VALUE >> 1;
writel((u32) (wrap_start_dir.val), remapped_regs + mmWRAP_START_DIR);
@@ -813,21 +787,24 @@ static void w100_hw_init(void)
writel((u32) (wrap_top_dir.val), remapped_regs + mmWRAP_TOP_DIR);
writel((u32) 0x2440, remapped_regs + mmRBBM_CNTL);
-}
+ /* Set the hardware to 565 colour */
+ temp32 = readl(remapped_regs + mmDISP_DEBUG2);
+ temp32 &= 0xff7fffff;
+ temp32 |= 0x00800000;
+ writel(temp32, remapped_regs + mmDISP_DEBUG2);
-/*
- * Types
- */
+ /* Initialise the GPIO lines */
+ if (gpio) {
+ writel(gpio->init_data1, remapped_regs + mmGPIO_DATA);
+ writel(gpio->init_data2, remapped_regs + mmGPIO_DATA2);
+ writel(gpio->gpio_dir1, remapped_regs + mmGPIO_CNTL1);
+ writel(gpio->gpio_oe1, remapped_regs + mmGPIO_CNTL2);
+ writel(gpio->gpio_dir2, remapped_regs + mmGPIO_CNTL3);
+ writel(gpio->gpio_oe2, remapped_regs + mmGPIO_CNTL4);
+ }
+}
-struct pll_parm {
- u16 freq; /* desired Fout for PLL */
- u8 M;
- u8 N_int;
- u8 N_fac;
- u8 tfgoal;
- u8 lock_time;
-};
struct power_state {
union clk_pin_cntl_u clk_pin_cntl;
@@ -835,317 +812,275 @@ struct power_state {
union pll_cntl_u pll_cntl;
union sclk_cntl_u sclk_cntl;
union pclk_cntl_u pclk_cntl;
- union clk_test_cntl_u clk_test_cntl;
union pwrmgt_cntl_u pwrmgt_cntl;
- u32 freq; /* Fout for PLL calibration */
- u8 tf100; /* for pll calibration */
- u8 tf80; /* for pll calibration */
- u8 tf20; /* for pll calibration */
- u8 M; /* for pll calibration */
- u8 N_int; /* for pll calibration */
- u8 N_fac; /* for pll calibration */
- u8 lock_time; /* for pll calibration */
- u8 tfgoal; /* for pll calibration */
- u8 auto_mode; /* hardware auto switch? */
- u8 pwm_mode; /* 0 fast, 1 normal/slow */
- u16 fast_sclk; /* fast clk freq */
- u16 norm_sclk; /* slow clk freq */
+ int auto_mode; /* system clock auto changing? */
};
-/*
- * Global state variables
- */
-
static struct power_state w100_pwr_state;
-/* This table is specific for 12.5MHz ref crystal. */
-static struct pll_parm gPLLTable[] = {
- /*freq M N_int N_fac tfgoal lock_time */
- { 50, 0, 1, 0, 0xE0, 56}, /* 50.00 MHz */
- { 75, 0, 5, 0, 0xDE, 37}, /* 75.00 MHz */
- {100, 0, 7, 0, 0xE0, 28}, /* 100.00 MHz */
- {125, 0, 9, 0, 0xE0, 22}, /* 125.00 MHz */
- {150, 0, 11, 0, 0xE0, 17}, /* 150.00 MHz */
- { 0, 0, 0, 0, 0, 0} /* Terminator */
+/* The PLL Fout is determined by (XtalFreq/(M+1)) * ((N_int+1) + (N_fac/8)) */
+
+/* 12.5MHz Crystal PLL Table */
+static struct w100_pll_info xtal_12500000[] = {
+ /*freq M N_int N_fac tfgoal lock_time */
+ { 50, 0, 1, 0, 0xe0, 56}, /* 50.00 MHz */
+ { 75, 0, 5, 0, 0xde, 37}, /* 75.00 MHz */
+ {100, 0, 7, 0, 0xe0, 28}, /* 100.00 MHz */
+ {125, 0, 9, 0, 0xe0, 22}, /* 125.00 MHz */
+ {150, 0, 11, 0, 0xe0, 17}, /* 150.00 MHz */
+ { 0, 0, 0, 0, 0, 0}, /* Terminator */
};
+/* 14.318MHz Crystal PLL Table */
+static struct w100_pll_info xtal_14318000[] = {
+ /*freq M N_int N_fac tfgoal lock_time */
+ { 40, 4, 13, 0, 0xe0, 80}, /* tfgoal guessed */
+ { 50, 1, 6, 0, 0xe0, 64}, /* 50.05 MHz */
+ { 57, 2, 11, 0, 0xe0, 53}, /* tfgoal guessed */
+ { 75, 0, 4, 3, 0xe0, 43}, /* 75.08 MHz */
+ {100, 0, 6, 0, 0xe0, 32}, /* 100.10 MHz */
+ { 0, 0, 0, 0, 0, 0},
+};
-static u8 w100_pll_get_testcount(u8 testclk_sel)
+/* 16MHz Crystal PLL Table */
+static struct w100_pll_info xtal_16000000[] = {
+ /*freq M N_int N_fac tfgoal lock_time */
+ { 72, 1, 8, 0, 0xe0, 48}, /* tfgoal guessed */
+ { 95, 1, 10, 7, 0xe0, 38}, /* tfgoal guessed */
+ { 96, 1, 11, 0, 0xe0, 36}, /* tfgoal guessed */
+ { 0, 0, 0, 0, 0, 0},
+};
+
+static struct pll_entries {
+ int xtal_freq;
+ struct w100_pll_info *pll_table;
+} w100_pll_tables[] = {
+ { 12500000, &xtal_12500000[0] },
+ { 14318000, &xtal_14318000[0] },
+ { 16000000, &xtal_16000000[0] },
+ { 0 },
+};
+
+struct w100_pll_info *w100_get_xtal_table(unsigned int freq)
{
+ struct pll_entries *pll_entry = w100_pll_tables;
+
+ do {
+ if (freq == pll_entry->xtal_freq)
+ return pll_entry->pll_table;
+ pll_entry++;
+ } while (pll_entry->xtal_freq);
+ return 0;
+}
+
+
+static unsigned int w100_get_testcount(unsigned int testclk_sel)
+{
+ union clk_test_cntl_u clk_test_cntl;
+
udelay(5);
- w100_pwr_state.clk_test_cntl.f.start_check_freq = 0x0;
- w100_pwr_state.clk_test_cntl.f.testclk_sel = testclk_sel;
- w100_pwr_state.clk_test_cntl.f.tstcount_rst = 0x1; /*reset test count */
- writel((u32) (w100_pwr_state.clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL);
- w100_pwr_state.clk_test_cntl.f.tstcount_rst = 0x0;
- writel((u32) (w100_pwr_state.clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL);
+ /* Select the test clock source and reset */
+ clk_test_cntl.f.start_check_freq = 0x0;
+ clk_test_cntl.f.testclk_sel = testclk_sel;
+ clk_test_cntl.f.tstcount_rst = 0x1; /* set reset */
+ writel((u32) (clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL);
- w100_pwr_state.clk_test_cntl.f.start_check_freq = 0x1;
- writel((u32) (w100_pwr_state.clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL);
+ clk_test_cntl.f.tstcount_rst = 0x0; /* clear reset */
+ writel((u32) (clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL);
+ /* Run clock test */
+ clk_test_cntl.f.start_check_freq = 0x1;
+ writel((u32) (clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL);
+
+ /* Give the test time to complete */
udelay(20);
- w100_pwr_state.clk_test_cntl.val = readl(remapped_regs + mmCLK_TEST_CNTL);
- w100_pwr_state.clk_test_cntl.f.start_check_freq = 0x0;
- writel((u32) (w100_pwr_state.clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL);
+ /* Return the result */
+ clk_test_cntl.val = readl(remapped_regs + mmCLK_TEST_CNTL);
+ clk_test_cntl.f.start_check_freq = 0x0;
+ writel((u32) (clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL);
- return w100_pwr_state.clk_test_cntl.f.test_count;
+ return clk_test_cntl.f.test_count;
}
-static u8 w100_pll_adjust(void)
+static int w100_pll_adjust(struct w100_pll_info *pll)
{
+ unsigned int tf80;
+ unsigned int tf20;
+
+ /* Initial Settings */
+ w100_pwr_state.pll_cntl.f.pll_pwdn = 0x0; /* power down */
+ w100_pwr_state.pll_cntl.f.pll_reset = 0x0; /* not reset */
+ w100_pwr_state.pll_cntl.f.pll_tcpoff = 0x1; /* Hi-Z */
+ w100_pwr_state.pll_cntl.f.pll_pvg = 0x0; /* VCO gain = 0 */
+ w100_pwr_state.pll_cntl.f.pll_vcofr = 0x0; /* VCO frequency range control = off */
+ w100_pwr_state.pll_cntl.f.pll_ioffset = 0x0; /* current offset inside VCO = 0 */
+ w100_pwr_state.pll_cntl.f.pll_ring_off = 0x0;
+
+ /* Wai Ming 80 percent of VDD 1.3V gives 1.04V, minimum operating voltage is 1.08V
+ * therefore, commented out the following lines
+ * tf80 meant tf100
+ */
do {
- /* Wai Ming 80 percent of VDD 1.3V gives 1.04V, minimum operating voltage is 1.08V
- * therefore, commented out the following lines
- * tf80 meant tf100
- * set VCO input = 0.8 * VDD
- */
+ /* set VCO input = 0.8 * VDD */
w100_pwr_state.pll_cntl.f.pll_dactal = 0xd;
writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
- w100_pwr_state.tf80 = w100_pll_get_testcount(0x1); /* PLLCLK */
- if (w100_pwr_state.tf80 >= (w100_pwr_state.tfgoal)) {
+ tf80 = w100_get_testcount(TESTCLK_SRC_PLL);
+ if (tf80 >= (pll->tfgoal)) {
/* set VCO input = 0.2 * VDD */
w100_pwr_state.pll_cntl.f.pll_dactal = 0x7;
writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
- w100_pwr_state.tf20 = w100_pll_get_testcount(0x1); /* PLLCLK */
- if (w100_pwr_state.tf20 <= (w100_pwr_state.tfgoal))
- return 1; // Success
+ tf20 = w100_get_testcount(TESTCLK_SRC_PLL);
+ if (tf20 <= (pll->tfgoal))
+ return 1; /* Success */
if ((w100_pwr_state.pll_cntl.f.pll_vcofr == 0x0) &&
- ((w100_pwr_state.pll_cntl.f.pll_pvg == 0x7) ||
- (w100_pwr_state.pll_cntl.f.pll_ioffset == 0x0))) {
+ ((w100_pwr_state.pll_cntl.f.pll_pvg == 0x7) ||
+ (w100_pwr_state.pll_cntl.f.pll_ioffset == 0x0))) {
/* slow VCO config */
w100_pwr_state.pll_cntl.f.pll_vcofr = 0x1;
w100_pwr_state.pll_cntl.f.pll_pvg = 0x0;
w100_pwr_state.pll_cntl.f.pll_ioffset = 0x0;
- writel((u32) (w100_pwr_state.pll_cntl.val),
- remapped_regs + mmPLL_CNTL);
continue;
}
}
if ((w100_pwr_state.pll_cntl.f.pll_ioffset) < 0x3) {
w100_pwr_state.pll_cntl.f.pll_ioffset += 0x1;
- writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
- continue;
- }
- if ((w100_pwr_state.pll_cntl.f.pll_pvg) < 0x7) {
+ } else if ((w100_pwr_state.pll_cntl.f.pll_pvg) < 0x7) {
w100_pwr_state.pll_cntl.f.pll_ioffset = 0x0;
w100_pwr_state.pll_cntl.f.pll_pvg += 0x1;
- writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
- continue;
+ } else {
+ return 0; /* Error */
}
- return 0; // error
} while(1);
}
/*
* w100_pll_calibration
- * freq = target frequency of the PLL
- * (note: crystal = 14.3MHz)
*/
-static u8 w100_pll_calibration(u32 freq)
+static int w100_pll_calibration(struct w100_pll_info *pll)
{
- u8 status;
-
- /* initial setting */
- w100_pwr_state.pll_cntl.f.pll_pwdn = 0x0; /* power down */
- w100_pwr_state.pll_cntl.f.pll_reset = 0x0; /* not reset */
- w100_pwr_state.pll_cntl.f.pll_tcpoff = 0x1; /* Hi-Z */
- w100_pwr_state.pll_cntl.f.pll_pvg = 0x0; /* VCO gain = 0 */
- w100_pwr_state.pll_cntl.f.pll_vcofr = 0x0; /* VCO frequency range control = off */
- w100_pwr_state.pll_cntl.f.pll_ioffset = 0x0; /* current offset inside VCO = 0 */
- w100_pwr_state.pll_cntl.f.pll_ring_off = 0x0;
- writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
+ int status;
- /* check for (tf80 >= tfgoal) && (tf20 =< tfgoal) */
- if ((w100_pwr_state.tf80 < w100_pwr_state.tfgoal) || (w100_pwr_state.tf20 > w100_pwr_state.tfgoal)) {
- status=w100_pll_adjust();
- }
- /* PLL Reset And Lock */
+ status = w100_pll_adjust(pll);
+ /* PLL Reset And Lock */
/* set VCO input = 0.5 * VDD */
w100_pwr_state.pll_cntl.f.pll_dactal = 0xa;
writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
- /* reset time */
- udelay(1);
+ udelay(1); /* reset time */
/* enable charge pump */
- w100_pwr_state.pll_cntl.f.pll_tcpoff = 0x0; /* normal */
+ w100_pwr_state.pll_cntl.f.pll_tcpoff = 0x0; /* normal */
writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
- /* set VCO input = Hi-Z */
- /* disable DAC */
+ /* set VCO input = Hi-Z, disable DAC */
w100_pwr_state.pll_cntl.f.pll_dactal = 0x0;
writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
- /* lock time */
- udelay(400); /* delay 400 us */
+ udelay(400); /* lock time */
/* PLL locked */
- w100_pwr_state.sclk_cntl.f.sclk_src_sel = 0x1; /* PLL clock */
- writel((u32) (w100_pwr_state.sclk_cntl.val), remapped_regs + mmSCLK_CNTL);
-
- w100_pwr_state.tf100 = w100_pll_get_testcount(0x1); /* PLLCLK */
-
return status;
}
-static u8 w100_pll_set_clk(void)
+static int w100_pll_set_clk(struct w100_pll_info *pll)
{
- u8 status;
+ int status;
- if (w100_pwr_state.auto_mode == 1) /* auto mode */
+ if (w100_pwr_state.auto_mode == 1) /* auto mode */
{
- w100_pwr_state.pwrmgt_cntl.f.pwm_fast_noml_hw_en = 0x0; /* disable fast to normal */
- w100_pwr_state.pwrmgt_cntl.f.pwm_noml_fast_hw_en = 0x0; /* disable normal to fast */
+ w100_pwr_state.pwrmgt_cntl.f.pwm_fast_noml_hw_en = 0x0; /* disable fast to normal */
+ w100_pwr_state.pwrmgt_cntl.f.pwm_noml_fast_hw_en = 0x0; /* disable normal to fast */
writel((u32) (w100_pwr_state.pwrmgt_cntl.val), remapped_regs + mmPWRMGT_CNTL);
}
- w100_pwr_state.sclk_cntl.f.sclk_src_sel = 0x0; /* crystal clock */
+ /* Set system clock source to XTAL whilst adjusting the PLL! */
+ w100_pwr_state.sclk_cntl.f.sclk_src_sel = CLK_SRC_XTAL;
writel((u32) (w100_pwr_state.sclk_cntl.val), remapped_regs + mmSCLK_CNTL);
- w100_pwr_state.pll_ref_fb_div.f.pll_ref_div = w100_pwr_state.M;
- w100_pwr_state.pll_ref_fb_div.f.pll_fb_div_int = w100_pwr_state.N_int;
- w100_pwr_state.pll_ref_fb_div.f.pll_fb_div_frac = w100_pwr_state.N_fac;
- w100_pwr_state.pll_ref_fb_div.f.pll_lock_time = w100_pwr_state.lock_time;
+ w100_pwr_state.pll_ref_fb_div.f.pll_ref_div = pll->M;
+ w100_pwr_state.pll_ref_fb_div.f.pll_fb_div_int = pll->N_int;
+ w100_pwr_state.pll_ref_fb_div.f.pll_fb_div_frac = pll->N_fac;
+ w100_pwr_state.pll_ref_fb_div.f.pll_lock_time = pll->lock_time;
writel((u32) (w100_pwr_state.pll_ref_fb_div.val), remapped_regs + mmPLL_REF_FB_DIV);
w100_pwr_state.pwrmgt_cntl.f.pwm_mode_req = 0;
writel((u32) (w100_pwr_state.pwrmgt_cntl.val), remapped_regs + mmPWRMGT_CNTL);
- status = w100_pll_calibration (w100_pwr_state.freq);
+ status = w100_pll_calibration(pll);
- if (w100_pwr_state.auto_mode == 1) /* auto mode */
+ if (w100_pwr_state.auto_mode == 1) /* auto mode */
{
- w100_pwr_state.pwrmgt_cntl.f.pwm_fast_noml_hw_en = 0x1; /* reenable fast to normal */
- w100_pwr_state.pwrmgt_cntl.f.pwm_noml_fast_hw_en = 0x1; /* reenable normal to fast */
+ w100_pwr_state.pwrmgt_cntl.f.pwm_fast_noml_hw_en = 0x1; /* reenable fast to normal */
+ w100_pwr_state.pwrmgt_cntl.f.pwm_noml_fast_hw_en = 0x1; /* reenable normal to fast */
writel((u32) (w100_pwr_state.pwrmgt_cntl.val), remapped_regs + mmPWRMGT_CNTL);
}
return status;
}
-
-/* assume reference crystal clk is 12.5MHz,
- * and that doubling is not enabled.
- *
- * Freq = 12 == 12.5MHz.
- */
-static u16 w100_set_slowsysclk(u16 freq)
-{
- if (w100_pwr_state.norm_sclk == freq)
- return freq;
-
- if (w100_pwr_state.auto_mode == 1) /* auto mode */
- return 0;
-
- if (freq == 12) {
- w100_pwr_state.norm_sclk = freq;
- w100_pwr_state.sclk_cntl.f.sclk_post_div_slow = 0x0; /* Pslow = 1 */
- w100_pwr_state.sclk_cntl.f.sclk_src_sel = 0x0; /* crystal src */
-
- writel((u32) (w100_pwr_state.sclk_cntl.val), remapped_regs + mmSCLK_CNTL);
-
- w100_pwr_state.clk_pin_cntl.f.xtalin_pm_en = 0x1;
- writel((u32) (w100_pwr_state.clk_pin_cntl.val), remapped_regs + mmCLK_PIN_CNTL);
-
- w100_pwr_state.pwrmgt_cntl.f.pwm_enable = 0x1;
- w100_pwr_state.pwrmgt_cntl.f.pwm_mode_req = 0x1;
- writel((u32) (w100_pwr_state.pwrmgt_cntl.val), remapped_regs + mmPWRMGT_CNTL);
- w100_pwr_state.pwm_mode = 1; /* normal mode */
- return freq;
- } else
- return 0;
-}
-
-
-static u16 w100_set_fastsysclk(u16 freq)
+/* freq = target frequency of the PLL */
+static int w100_set_pll_freq(struct w100fb_par *par, unsigned int freq)
{
- u16 pll_freq;
- int i;
-
- while(1) {
- pll_freq = (u16) (freq * (w100_pwr_state.sclk_cntl.f.sclk_post_div_fast + 1));
- i = 0;
- do {
- if (pll_freq == gPLLTable[i].freq) {
- w100_pwr_state.freq = gPLLTable[i].freq * 1000000;
- w100_pwr_state.M = gPLLTable[i].M;
- w100_pwr_state.N_int = gPLLTable[i].N_int;
- w100_pwr_state.N_fac = gPLLTable[i].N_fac;
- w100_pwr_state.tfgoal = gPLLTable[i].tfgoal;
- w100_pwr_state.lock_time = gPLLTable[i].lock_time;
- w100_pwr_state.tf20 = 0xff; /* set highest */
- w100_pwr_state.tf80 = 0x00; /* set lowest */
-
- w100_pll_set_clk();
- w100_pwr_state.pwm_mode = 0; /* fast mode */
- w100_pwr_state.fast_sclk = freq;
- return freq;
- }
- i++;
- } while(gPLLTable[i].freq);
+ struct w100_pll_info *pll = par->pll_table;
- if (w100_pwr_state.auto_mode == 1)
- break;
-
- if (w100_pwr_state.sclk_cntl.f.sclk_post_div_fast == 0)
- break;
-
- w100_pwr_state.sclk_cntl.f.sclk_post_div_fast -= 1;
- writel((u32) (w100_pwr_state.sclk_cntl.val), remapped_regs + mmSCLK_CNTL);
- }
+ do {
+ if (freq == pll->freq) {
+ return w100_pll_set_clk(pll);
+ }
+ pll++;
+ } while(pll->freq);
return 0;
}
-
/* Set up an initial state. Some values/fields set
here will be overwritten. */
-static void w100_pwm_setup(void)
+static void w100_pwm_setup(struct w100fb_par *par)
{
w100_pwr_state.clk_pin_cntl.f.osc_en = 0x1;
w100_pwr_state.clk_pin_cntl.f.osc_gain = 0x1f;
w100_pwr_state.clk_pin_cntl.f.dont_use_xtalin = 0x0;
w100_pwr_state.clk_pin_cntl.f.xtalin_pm_en = 0x0;
- w100_pwr_state.clk_pin_cntl.f.xtalin_dbl_en = 0x0; /* no freq doubling */
+ w100_pwr_state.clk_pin_cntl.f.xtalin_dbl_en = par->mach->xtal_dbl ? 1 : 0;
w100_pwr_state.clk_pin_cntl.f.cg_debug = 0x0;
writel((u32) (w100_pwr_state.clk_pin_cntl.val), remapped_regs + mmCLK_PIN_CNTL);
- w100_pwr_state.sclk_cntl.f.sclk_src_sel = 0x0; /* Crystal Clk */
- w100_pwr_state.sclk_cntl.f.sclk_post_div_fast = 0x0; /* Pfast = 1 */
+ w100_pwr_state.sclk_cntl.f.sclk_src_sel = CLK_SRC_XTAL;
+ w100_pwr_state.sclk_cntl.f.sclk_post_div_fast = 0x0; /* Pfast = 1 */
w100_pwr_state.sclk_cntl.f.sclk_clkon_hys = 0x3;
- w100_pwr_state.sclk_cntl.f.sclk_post_div_slow = 0x0; /* Pslow = 1 */
+ w100_pwr_state.sclk_cntl.f.sclk_post_div_slow = 0x0; /* Pslow = 1 */
w100_pwr_state.sclk_cntl.f.disp_cg_ok2switch_en = 0x0;
- w100_pwr_state.sclk_cntl.f.sclk_force_reg = 0x0; /* Dynamic */
- w100_pwr_state.sclk_cntl.f.sclk_force_disp = 0x0; /* Dynamic */
- w100_pwr_state.sclk_cntl.f.sclk_force_mc = 0x0; /* Dynamic */
- w100_pwr_state.sclk_cntl.f.sclk_force_extmc = 0x0; /* Dynamic */
- w100_pwr_state.sclk_cntl.f.sclk_force_cp = 0x0; /* Dynamic */
- w100_pwr_state.sclk_cntl.f.sclk_force_e2 = 0x0; /* Dynamic */
- w100_pwr_state.sclk_cntl.f.sclk_force_e3 = 0x0; /* Dynamic */
- w100_pwr_state.sclk_cntl.f.sclk_force_idct = 0x0; /* Dynamic */
- w100_pwr_state.sclk_cntl.f.sclk_force_bist = 0x0; /* Dynamic */
+ w100_pwr_state.sclk_cntl.f.sclk_force_reg = 0x0; /* Dynamic */
+ w100_pwr_state.sclk_cntl.f.sclk_force_disp = 0x0; /* Dynamic */
+ w100_pwr_state.sclk_cntl.f.sclk_force_mc = 0x0; /* Dynamic */
+ w100_pwr_state.sclk_cntl.f.sclk_force_extmc = 0x0; /* Dynamic */
+ w100_pwr_state.sclk_cntl.f.sclk_force_cp = 0x0; /* Dynamic */
+ w100_pwr_state.sclk_cntl.f.sclk_force_e2 = 0x0; /* Dynamic */
+ w100_pwr_state.sclk_cntl.f.sclk_force_e3 = 0x0; /* Dynamic */
+ w100_pwr_state.sclk_cntl.f.sclk_force_idct = 0x0; /* Dynamic */
+ w100_pwr_state.sclk_cntl.f.sclk_force_bist = 0x0; /* Dynamic */
w100_pwr_state.sclk_cntl.f.busy_extend_cp = 0x0;
w100_pwr_state.sclk_cntl.f.busy_extend_e2 = 0x0;
w100_pwr_state.sclk_cntl.f.busy_extend_e3 = 0x0;
w100_pwr_state.sclk_cntl.f.busy_extend_idct = 0x0;
writel((u32) (w100_pwr_state.sclk_cntl.val), remapped_regs + mmSCLK_CNTL);
- w100_pwr_state.pclk_cntl.f.pclk_src_sel = 0x0; /* Crystal Clk */
- w100_pwr_state.pclk_cntl.f.pclk_post_div = 0x1; /* P = 2 */
- w100_pwr_state.pclk_cntl.f.pclk_force_disp = 0x0; /* Dynamic */
+ w100_pwr_state.pclk_cntl.f.pclk_src_sel = CLK_SRC_XTAL;
+ w100_pwr_state.pclk_cntl.f.pclk_post_div = 0x1; /* P = 2 */
+ w100_pwr_state.pclk_cntl.f.pclk_force_disp = 0x0; /* Dynamic */
writel((u32) (w100_pwr_state.pclk_cntl.val), remapped_regs + mmPCLK_CNTL);
- w100_pwr_state.pll_ref_fb_div.f.pll_ref_div = 0x0; /* M = 1 */
- w100_pwr_state.pll_ref_fb_div.f.pll_fb_div_int = 0x0; /* N = 1.0 */
+ w100_pwr_state.pll_ref_fb_div.f.pll_ref_div = 0x0; /* M = 1 */
+ w100_pwr_state.pll_ref_fb_div.f.pll_fb_div_int = 0x0; /* N = 1.0 */
w100_pwr_state.pll_ref_fb_div.f.pll_fb_div_frac = 0x0;
w100_pwr_state.pll_ref_fb_div.f.pll_reset_time = 0x5;
w100_pwr_state.pll_ref_fb_div.f.pll_lock_time = 0xff;
@@ -1154,7 +1089,7 @@ static void w100_pwm_setup(void)
w100_pwr_state.pll_cntl.f.pll_pwdn = 0x1;
w100_pwr_state.pll_cntl.f.pll_reset = 0x1;
w100_pwr_state.pll_cntl.f.pll_pm_en = 0x0;
- w100_pwr_state.pll_cntl.f.pll_mode = 0x0; /* uses VCO clock */
+ w100_pwr_state.pll_cntl.f.pll_mode = 0x0; /* uses VCO clock */
w100_pwr_state.pll_cntl.f.pll_refclk_sel = 0x0;
w100_pwr_state.pll_cntl.f.pll_fbclk_sel = 0x0;
w100_pwr_state.pll_cntl.f.pll_tcpoff = 0x0;
@@ -1164,220 +1099,275 @@ static void w100_pwm_setup(void)
w100_pwr_state.pll_cntl.f.pll_ioffset = 0x0;
w100_pwr_state.pll_cntl.f.pll_pecc_mode = 0x0;
w100_pwr_state.pll_cntl.f.pll_pecc_scon = 0x0;
- w100_pwr_state.pll_cntl.f.pll_dactal = 0x0; /* Hi-Z */
+ w100_pwr_state.pll_cntl.f.pll_dactal = 0x0; /* Hi-Z */
w100_pwr_state.pll_cntl.f.pll_cp_clip = 0x3;
w100_pwr_state.pll_cntl.f.pll_conf = 0x2;
w100_pwr_state.pll_cntl.f.pll_mbctrl = 0x2;
w100_pwr_state.pll_cntl.f.pll_ring_off = 0x0;
writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
- w100_pwr_state.clk_test_cntl.f.testclk_sel = 0x1; /* PLLCLK (for testing) */
- w100_pwr_state.clk_test_cntl.f.start_check_freq = 0x0;
- w100_pwr_state.clk_test_cntl.f.tstcount_rst = 0x0;
- writel((u32) (w100_pwr_state.clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL);
-
w100_pwr_state.pwrmgt_cntl.f.pwm_enable = 0x0;
- w100_pwr_state.pwrmgt_cntl.f.pwm_mode_req = 0x1; /* normal mode (0, 1, 3) */
+ w100_pwr_state.pwrmgt_cntl.f.pwm_mode_req = 0x1; /* normal mode (0, 1, 3) */
w100_pwr_state.pwrmgt_cntl.f.pwm_wakeup_cond = 0x0;
w100_pwr_state.pwrmgt_cntl.f.pwm_fast_noml_hw_en = 0x0;
w100_pwr_state.pwrmgt_cntl.f.pwm_noml_fast_hw_en = 0x0;
- w100_pwr_state.pwrmgt_cntl.f.pwm_fast_noml_cond = 0x1; /* PM4,ENG */
- w100_pwr_state.pwrmgt_cntl.f.pwm_noml_fast_cond = 0x1; /* PM4,ENG */
+ w100_pwr_state.pwrmgt_cntl.f.pwm_fast_noml_cond = 0x1; /* PM4,ENG */
+ w100_pwr_state.pwrmgt_cntl.f.pwm_noml_fast_cond = 0x1; /* PM4,ENG */
w100_pwr_state.pwrmgt_cntl.f.pwm_idle_timer = 0xFF;
w100_pwr_state.pwrmgt_cntl.f.pwm_busy_timer = 0xFF;
writel((u32) (w100_pwr_state.pwrmgt_cntl.val), remapped_regs + mmPWRMGT_CNTL);
- w100_pwr_state.auto_mode = 0; /* manual mode */
- w100_pwr_state.pwm_mode = 1; /* normal mode (0, 1, 2) */
- w100_pwr_state.freq = 50000000; /* 50 MHz */
- w100_pwr_state.M = 3; /* M = 4 */
- w100_pwr_state.N_int = 6; /* N = 7.0 */
- w100_pwr_state.N_fac = 0;
- w100_pwr_state.tfgoal = 0xE0;
- w100_pwr_state.lock_time = 56;
- w100_pwr_state.tf20 = 0xff; /* set highest */
- w100_pwr_state.tf80 = 0x00; /* set lowest */
- w100_pwr_state.tf100 = 0x00; /* set lowest */
- w100_pwr_state.fast_sclk = 50; /* 50.0 MHz */
- w100_pwr_state.norm_sclk = 12; /* 12.5 MHz */
+ w100_pwr_state.auto_mode = 0; /* manual mode */
}
-static void w100_init_sharp_lcd(u32 mode)
+/*
+ * Setup the w100 clocks for the specified mode
+ */
+static void w100_init_clocks(struct w100fb_par *par)
{
- u32 temp32;
- union disp_db_buf_cntl_wr_u disp_db_buf_wr_cntl;
+ struct w100_mode *mode = par->mode;
- /* Prevent display updates */
- disp_db_buf_wr_cntl.f.db_buf_cntl = 0x1e;
- disp_db_buf_wr_cntl.f.update_db_buf = 0;
- disp_db_buf_wr_cntl.f.en_db_buf = 0;
- writel((u32) (disp_db_buf_wr_cntl.val), remapped_regs + mmDISP_DB_BUF_CNTL);
+ if (mode->pixclk_src == CLK_SRC_PLL || mode->sysclk_src == CLK_SRC_PLL)
+ w100_set_pll_freq(par, (par->fastpll_mode && mode->fast_pll_freq) ? mode->fast_pll_freq : mode->pll_freq);
- switch(mode) {
- case LCD_SHARP_QVGA:
- w100_set_slowsysclk(12); /* use crystal -- 12.5MHz */
- /* not use PLL */
-
- writel(0x7FFF8000, remapped_regs + mmMC_EXT_MEM_LOCATION);
- writel(0x85FF8000, remapped_regs + mmMC_FB_LOCATION);
- writel(0x00000003, remapped_regs + mmLCD_FORMAT);
- writel(0x00CF1C06, remapped_regs + mmGRAPHIC_CTRL);
- writel(0x01410145, remapped_regs + mmCRTC_TOTAL);
- writel(0x01170027, remapped_regs + mmACTIVE_H_DISP);
- writel(0x01410001, remapped_regs + mmACTIVE_V_DISP);
- writel(0x01170027, remapped_regs + mmGRAPHIC_H_DISP);
- writel(0x01410001, remapped_regs + mmGRAPHIC_V_DISP);
- writel(0x81170027, remapped_regs + mmCRTC_SS);
- writel(0xA0140000, remapped_regs + mmCRTC_LS);
- writel(0x00400008, remapped_regs + mmCRTC_REV);
- writel(0xA0000000, remapped_regs + mmCRTC_DCLK);
- writel(0xC0140014, remapped_regs + mmCRTC_GS);
- writel(0x00010141, remapped_regs + mmCRTC_VPOS_GS);
- writel(0x8015010F, remapped_regs + mmCRTC_GCLK);
- writel(0x80100110, remapped_regs + mmCRTC_GOE);
- writel(0x00000000, remapped_regs + mmCRTC_FRAME);
- writel(0x00000000, remapped_regs + mmCRTC_FRAME_VPOS);
- writel(0x01CC0000, remapped_regs + mmLCDD_CNTL1);
- writel(0x0003FFFF, remapped_regs + mmLCDD_CNTL2);
- writel(0x00FFFF0D, remapped_regs + mmGENLCD_CNTL1);
- writel(0x003F3003, remapped_regs + mmGENLCD_CNTL2);
- writel(0x00000000, remapped_regs + mmCRTC_DEFAULT_COUNT);
- writel(0x0000FF00, remapped_regs + mmLCD_BACKGROUND_COLOR);
- writel(0x000102aa, remapped_regs + mmGENLCD_CNTL3);
- writel(0x00800000, remapped_regs + mmGRAPHIC_OFFSET);
- writel(0x000001e0, remapped_regs + mmGRAPHIC_PITCH);
- writel(0x000000bf, remapped_regs + mmGPIO_DATA);
- writel(0x03c0feff, remapped_regs + mmGPIO_CNTL2);
- writel(0x00000000, remapped_regs + mmGPIO_CNTL1);
- writel(0x41060010, remapped_regs + mmCRTC_PS1_ACTIVE);
- break;
- case LCD_SHARP_VGA:
- w100_set_slowsysclk(12); /* use crystal -- 12.5MHz */
- w100_set_fastsysclk(current_par->fastsysclk_mode); /* use PLL -- 75.0MHz */
- w100_pwr_state.pclk_cntl.f.pclk_src_sel = 0x1;
- w100_pwr_state.pclk_cntl.f.pclk_post_div = 0x2;
- writel((u32) (w100_pwr_state.pclk_cntl.val), remapped_regs + mmPCLK_CNTL);
- writel(0x15FF1000, remapped_regs + mmMC_FB_LOCATION);
- writel(0x9FFF8000, remapped_regs + mmMC_EXT_MEM_LOCATION);
- writel(0x00000003, remapped_regs + mmLCD_FORMAT);
- writel(0x00DE1D66, remapped_regs + mmGRAPHIC_CTRL);
-
- writel(0x0283028B, remapped_regs + mmCRTC_TOTAL);
- writel(0x02360056, remapped_regs + mmACTIVE_H_DISP);
- writel(0x02830003, remapped_regs + mmACTIVE_V_DISP);
- writel(0x02360056, remapped_regs + mmGRAPHIC_H_DISP);
- writel(0x02830003, remapped_regs + mmGRAPHIC_V_DISP);
- writel(0x82360056, remapped_regs + mmCRTC_SS);
- writel(0xA0280000, remapped_regs + mmCRTC_LS);
- writel(0x00400008, remapped_regs + mmCRTC_REV);
- writel(0xA0000000, remapped_regs + mmCRTC_DCLK);
- writel(0x80280028, remapped_regs + mmCRTC_GS);
- writel(0x02830002, remapped_regs + mmCRTC_VPOS_GS);
- writel(0x8015010F, remapped_regs + mmCRTC_GCLK);
- writel(0x80100110, remapped_regs + mmCRTC_GOE);
- writel(0x00000000, remapped_regs + mmCRTC_FRAME);
- writel(0x00000000, remapped_regs + mmCRTC_FRAME_VPOS);
- writel(0x01CC0000, remapped_regs + mmLCDD_CNTL1);
- writel(0x0003FFFF, remapped_regs + mmLCDD_CNTL2);
- writel(0x00FFFF0D, remapped_regs + mmGENLCD_CNTL1);
- writel(0x003F3003, remapped_regs + mmGENLCD_CNTL2);
- writel(0x00000000, remapped_regs + mmCRTC_DEFAULT_COUNT);
- writel(0x0000FF00, remapped_regs + mmLCD_BACKGROUND_COLOR);
- writel(0x000102aa, remapped_regs + mmGENLCD_CNTL3);
- writel(0x00800000, remapped_regs + mmGRAPHIC_OFFSET);
- writel(0x000003C0, remapped_regs + mmGRAPHIC_PITCH);
- writel(0x000000bf, remapped_regs + mmGPIO_DATA);
- writel(0x03c0feff, remapped_regs + mmGPIO_CNTL2);
- writel(0x00000000, remapped_regs + mmGPIO_CNTL1);
- writel(0x41060010, remapped_regs + mmCRTC_PS1_ACTIVE);
- break;
- default:
- break;
- }
+ w100_pwr_state.sclk_cntl.f.sclk_src_sel = mode->sysclk_src;
+ w100_pwr_state.sclk_cntl.f.sclk_post_div_fast = mode->sysclk_divider;
+ w100_pwr_state.sclk_cntl.f.sclk_post_div_slow = mode->sysclk_divider;
+ writel((u32) (w100_pwr_state.sclk_cntl.val), remapped_regs + mmSCLK_CNTL);
+}
+
+static void w100_init_lcd(struct w100fb_par *par)
+{
+ u32 temp32;
+ struct w100_mode *mode = par->mode;
+ struct w100_gen_regs *regs = par->mach->regs;
+ union active_h_disp_u active_h_disp;
+ union active_v_disp_u active_v_disp;
+ union graphic_h_disp_u graphic_h_disp;
+ union graphic_v_disp_u graphic_v_disp;
+ union crtc_total_u crtc_total;
+
+ /* w3200 doesnt like undefined bits being set so zero register values first */
+
+ active_h_disp.val = 0;
+ active_h_disp.f.active_h_start=mode->left_margin;
+ active_h_disp.f.active_h_end=mode->left_margin + mode->xres;
+ writel(active_h_disp.val, remapped_regs + mmACTIVE_H_DISP);
+
+ active_v_disp.val = 0;
+ active_v_disp.f.active_v_start=mode->upper_margin;
+ active_v_disp.f.active_v_end=mode->upper_margin + mode->yres;
+ writel(active_v_disp.val, remapped_regs + mmACTIVE_V_DISP);
+
+ graphic_h_disp.val = 0;
+ graphic_h_disp.f.graphic_h_start=mode->left_margin;
+ graphic_h_disp.f.graphic_h_end=mode->left_margin + mode->xres;
+ writel(graphic_h_disp.val, remapped_regs + mmGRAPHIC_H_DISP);
+
+ graphic_v_disp.val = 0;
+ graphic_v_disp.f.graphic_v_start=mode->upper_margin;
+ graphic_v_disp.f.graphic_v_end=mode->upper_margin + mode->yres;
+ writel(graphic_v_disp.val, remapped_regs + mmGRAPHIC_V_DISP);
+
+ crtc_total.val = 0;
+ crtc_total.f.crtc_h_total=mode->left_margin + mode->xres + mode->right_margin;
+ crtc_total.f.crtc_v_total=mode->upper_margin + mode->yres + mode->lower_margin;
+ writel(crtc_total.val, remapped_regs + mmCRTC_TOTAL);
+
+ writel(mode->crtc_ss, remapped_regs + mmCRTC_SS);
+ writel(mode->crtc_ls, remapped_regs + mmCRTC_LS);
+ writel(mode->crtc_gs, remapped_regs + mmCRTC_GS);
+ writel(mode->crtc_vpos_gs, remapped_regs + mmCRTC_VPOS_GS);
+ writel(mode->crtc_rev, remapped_regs + mmCRTC_REV);
+ writel(mode->crtc_dclk, remapped_regs + mmCRTC_DCLK);
+ writel(mode->crtc_gclk, remapped_regs + mmCRTC_GCLK);
+ writel(mode->crtc_goe, remapped_regs + mmCRTC_GOE);
+ writel(mode->crtc_ps1_active, remapped_regs + mmCRTC_PS1_ACTIVE);
+
+ writel(regs->lcd_format, remapped_regs + mmLCD_FORMAT);
+ writel(regs->lcdd_cntl1, remapped_regs + mmLCDD_CNTL1);
+ writel(regs->lcdd_cntl2, remapped_regs + mmLCDD_CNTL2);
+ writel(regs->genlcd_cntl1, remapped_regs + mmGENLCD_CNTL1);
+ writel(regs->genlcd_cntl2, remapped_regs + mmGENLCD_CNTL2);
+ writel(regs->genlcd_cntl3, remapped_regs + mmGENLCD_CNTL3);
+
+ writel(0x00000000, remapped_regs + mmCRTC_FRAME);
+ writel(0x00000000, remapped_regs + mmCRTC_FRAME_VPOS);
+ writel(0x00000000, remapped_regs + mmCRTC_DEFAULT_COUNT);
+ writel(0x0000FF00, remapped_regs + mmLCD_BACKGROUND_COLOR);
/* Hack for overlay in ext memory */
temp32 = readl(remapped_regs + mmDISP_DEBUG2);
temp32 |= 0xc0000000;
writel(temp32, remapped_regs + mmDISP_DEBUG2);
-
- /* Re-enable display updates */
- disp_db_buf_wr_cntl.f.db_buf_cntl = 0x1e;
- disp_db_buf_wr_cntl.f.update_db_buf = 1;
- disp_db_buf_wr_cntl.f.en_db_buf = 1;
- writel((u32) (disp_db_buf_wr_cntl.val), remapped_regs + mmDISP_DB_BUF_CNTL);
}
-static void w100_set_vga_rotation_regs(u16 divider, unsigned long ctrl, unsigned long offset, unsigned long pitch)
+static void w100_setup_memory(struct w100fb_par *par)
{
- w100_pwr_state.pclk_cntl.f.pclk_src_sel = 0x1;
- w100_pwr_state.pclk_cntl.f.pclk_post_div = divider;
- writel((u32) (w100_pwr_state.pclk_cntl.val), remapped_regs + mmPCLK_CNTL);
+ union mc_ext_mem_location_u extmem_location;
+ union mc_fb_location_u intmem_location;
+ struct w100_mem_info *mem = par->mach->mem;
+ struct w100_bm_mem_info *bm_mem = par->mach->bm_mem;
- writel(ctrl, remapped_regs + mmGRAPHIC_CTRL);
- writel(offset, remapped_regs + mmGRAPHIC_OFFSET);
- writel(pitch, remapped_regs + mmGRAPHIC_PITCH);
+ if (!par->extmem_active) {
+ w100_suspend(W100_SUSPEND_EXTMEM);
- /* Re-enable display updates */
- writel(0x0000007b, remapped_regs + mmDISP_DB_BUF_CNTL);
-}
+ /* Map Internal Memory at FB Base */
+ intmem_location.f.mc_fb_start = W100_FB_BASE >> 8;
+ intmem_location.f.mc_fb_top = (W100_FB_BASE+MEM_INT_SIZE) >> 8;
+ writel((u32) (intmem_location.val), remapped_regs + mmMC_FB_LOCATION);
+ /* Unmap External Memory - value is *probably* irrelevant but may have meaning
+ to acceleration libraries */
+ extmem_location.f.mc_ext_mem_start = MEM_EXT_BASE_VALUE >> 8;
+ extmem_location.f.mc_ext_mem_top = (MEM_EXT_BASE_VALUE-1) >> 8;
+ writel((u32) (extmem_location.val), remapped_regs + mmMC_EXT_MEM_LOCATION);
+ } else {
+ /* Map Internal Memory to its default location */
+ intmem_location.f.mc_fb_start = MEM_INT_BASE_VALUE >> 8;
+ intmem_location.f.mc_fb_top = (MEM_INT_BASE_VALUE+MEM_INT_SIZE) >> 8;
+ writel((u32) (intmem_location.val), remapped_regs + mmMC_FB_LOCATION);
-static void w100_init_vga_rotation(u16 deg)
-{
- switch(deg) {
- case 0:
- w100_set_vga_rotation_regs(0x02, 0x00DE1D66, 0x00800000, 0x000003c0);
- break;
- case 90:
- w100_set_vga_rotation_regs(0x06, 0x00DE1D0e, 0x00895b00, 0x00000500);
- break;
- case 180:
- w100_set_vga_rotation_regs(0x02, 0x00DE1D7e, 0x00895ffc, 0x000003c0);
- break;
- case 270:
- w100_set_vga_rotation_regs(0x06, 0x00DE1D16, 0x008004fc, 0x00000500);
- break;
- default:
- /* not-support */
- break;
+ /* Map External Memory at FB Base */
+ extmem_location.f.mc_ext_mem_start = W100_FB_BASE >> 8;
+ extmem_location.f.mc_ext_mem_top = (W100_FB_BASE+par->mach->mem->size) >> 8;
+ writel((u32) (extmem_location.val), remapped_regs + mmMC_EXT_MEM_LOCATION);
+
+ writel(0x00007800, remapped_regs + mmMC_BIST_CTRL);
+ writel(mem->ext_cntl, remapped_regs + mmMEM_EXT_CNTL);
+ writel(0x00200021, remapped_regs + mmMEM_SDRAM_MODE_REG);
+ udelay(100);
+ writel(0x80200021, remapped_regs + mmMEM_SDRAM_MODE_REG);
+ udelay(100);
+ writel(mem->sdram_mode_reg, remapped_regs + mmMEM_SDRAM_MODE_REG);
+ udelay(100);
+ writel(mem->ext_timing_cntl, remapped_regs + mmMEM_EXT_TIMING_CNTL);
+ writel(mem->io_cntl, remapped_regs + mmMEM_IO_CNTL);
+ if (bm_mem) {
+ writel(bm_mem->ext_mem_bw, remapped_regs + mmBM_EXT_MEM_BANDWIDTH);
+ writel(bm_mem->offset, remapped_regs + mmBM_OFFSET);
+ writel(bm_mem->ext_timing_ctl, remapped_regs + mmBM_MEM_EXT_TIMING_CNTL);
+ writel(bm_mem->ext_cntl, remapped_regs + mmBM_MEM_EXT_CNTL);
+ writel(bm_mem->mode_reg, remapped_regs + mmBM_MEM_MODE_REG);
+ writel(bm_mem->io_cntl, remapped_regs + mmBM_MEM_IO_CNTL);
+ writel(bm_mem->config, remapped_regs + mmBM_CONFIG);
+ }
}
}
-
-static void w100_set_qvga_rotation_regs(unsigned long ctrl, unsigned long offset, unsigned long pitch)
+static void w100_set_dispregs(struct w100fb_par *par)
{
- writel(ctrl, remapped_regs + mmGRAPHIC_CTRL);
- writel(offset, remapped_regs + mmGRAPHIC_OFFSET);
- writel(pitch, remapped_regs + mmGRAPHIC_PITCH);
+ unsigned long rot=0, divider, offset=0;
+ union graphic_ctrl_u graphic_ctrl;
+
+ /* See if the mode has been rotated */
+ if (par->xres == par->mode->xres) {
+ if (par->flip) {
+ rot=3; /* 180 degree */
+ offset=(par->xres * par->yres) - 1;
+ } /* else 0 degree */
+ divider = par->mode->pixclk_divider;
+ } else {
+ if (par->flip) {
+ rot=2; /* 270 degree */
+ offset=par->xres - 1;
+ } else {
+ rot=1; /* 90 degree */
+ offset=par->xres * (par->yres - 1);
+ }
+ divider = par->mode->pixclk_divider_rotated;
+ }
- /* Re-enable display updates */
- writel(0x0000007b, remapped_regs + mmDISP_DB_BUF_CNTL);
+ graphic_ctrl.val = 0; /* w32xx doesn't like undefined bits */
+ switch (par->chip_id) {
+ case CHIP_ID_W100:
+ graphic_ctrl.f_w100.color_depth=6;
+ graphic_ctrl.f_w100.en_crtc=1;
+ graphic_ctrl.f_w100.en_graphic_req=1;
+ graphic_ctrl.f_w100.en_graphic_crtc=1;
+ graphic_ctrl.f_w100.lcd_pclk_on=1;
+ graphic_ctrl.f_w100.lcd_sclk_on=1;
+ graphic_ctrl.f_w100.low_power_on=0;
+ graphic_ctrl.f_w100.req_freq=0;
+ graphic_ctrl.f_w100.portrait_mode=rot;
+
+ /* Zaurus needs this */
+ switch(par->xres) {
+ case 240:
+ case 320:
+ default:
+ graphic_ctrl.f_w100.total_req_graphic=0xa0;
+ break;
+ case 480:
+ case 640:
+ switch(rot) {
+ case 0: /* 0 */
+ case 3: /* 180 */
+ graphic_ctrl.f_w100.low_power_on=1;
+ graphic_ctrl.f_w100.req_freq=5;
+ break;
+ case 1: /* 90 */
+ case 2: /* 270 */
+ graphic_ctrl.f_w100.req_freq=4;
+ break;
+ default:
+ break;
+ }
+ graphic_ctrl.f_w100.total_req_graphic=0xf0;
+ break;
+ }
+ break;
+ case CHIP_ID_W3200:
+ case CHIP_ID_W3220:
+ graphic_ctrl.f_w32xx.color_depth=6;
+ graphic_ctrl.f_w32xx.en_crtc=1;
+ graphic_ctrl.f_w32xx.en_graphic_req=1;
+ graphic_ctrl.f_w32xx.en_graphic_crtc=1;
+ graphic_ctrl.f_w32xx.lcd_pclk_on=1;
+ graphic_ctrl.f_w32xx.lcd_sclk_on=1;
+ graphic_ctrl.f_w32xx.low_power_on=0;
+ graphic_ctrl.f_w32xx.req_freq=0;
+ graphic_ctrl.f_w32xx.total_req_graphic=par->mode->xres >> 1; /* panel xres, not mode */
+ graphic_ctrl.f_w32xx.portrait_mode=rot;
+ break;
+ }
+
+ /* Set the pixel clock source and divider */
+ w100_pwr_state.pclk_cntl.f.pclk_src_sel = par->mode->pixclk_src;
+ w100_pwr_state.pclk_cntl.f.pclk_post_div = divider;
+ writel((u32) (w100_pwr_state.pclk_cntl.val), remapped_regs + mmPCLK_CNTL);
+
+ writel(graphic_ctrl.val, remapped_regs + mmGRAPHIC_CTRL);
+ writel(W100_FB_BASE + ((offset * BITS_PER_PIXEL/8)&~0x03UL), remapped_regs + mmGRAPHIC_OFFSET);
+ writel((par->xres*BITS_PER_PIXEL/8), remapped_regs + mmGRAPHIC_PITCH);
}
-static void w100_init_qvga_rotation(u16 deg)
+/*
+ * Work out how long the sync pulse lasts
+ * Value is 1/(time in seconds)
+ */
+static void calc_hsync(struct w100fb_par *par)
{
- switch(deg) {
- case 0:
- w100_set_qvga_rotation_regs(0x00d41c06, 0x00800000, 0x000001e0);
- break;
- case 90:
- w100_set_qvga_rotation_regs(0x00d41c0E, 0x00825580, 0x00000280);
- break;
- case 180:
- w100_set_qvga_rotation_regs(0x00d41c1e, 0x008257fc, 0x000001e0);
- break;
- case 270:
- w100_set_qvga_rotation_regs(0x00d41c16, 0x0080027c, 0x00000280);
- break;
- default:
- /* not-support */
- break;
- }
-}
+ unsigned long hsync;
+ struct w100_mode *mode = par->mode;
+ union crtc_ss_u crtc_ss;
+
+ if (mode->pixclk_src == CLK_SRC_XTAL)
+ hsync=par->mach->xtal_freq;
+ else
+ hsync=((par->fastpll_mode && mode->fast_pll_freq) ? mode->fast_pll_freq : mode->pll_freq)*100000;
+ hsync /= (w100_pwr_state.pclk_cntl.f.pclk_post_div + 1);
+
+ crtc_ss.val = readl(remapped_regs + mmCRTC_SS);
+ if (crtc_ss.val)
+ par->hsync_len = hsync / (crtc_ss.f.ss_end-crtc_ss.f.ss_start);
+ else
+ par->hsync_len = 0;
+}
static void w100_suspend(u32 mode)
{
@@ -1387,30 +1377,28 @@ static void w100_suspend(u32 mode)
writel(0x00FF0000, remapped_regs + mmMC_PERF_MON_CNTL);
val = readl(remapped_regs + mmMEM_EXT_TIMING_CNTL);
- val &= ~(0x00100000); /* bit20=0 */
- val |= 0xFF000000; /* bit31:24=0xff */
+ val &= ~(0x00100000); /* bit20=0 */
+ val |= 0xFF000000; /* bit31:24=0xff */
writel(val, remapped_regs + mmMEM_EXT_TIMING_CNTL);
val = readl(remapped_regs + mmMEM_EXT_CNTL);
- val &= ~(0x00040000); /* bit18=0 */
- val |= 0x00080000; /* bit19=1 */
+ val &= ~(0x00040000); /* bit18=0 */
+ val |= 0x00080000; /* bit19=1 */
writel(val, remapped_regs + mmMEM_EXT_CNTL);
- udelay(1); /* wait 1us */
+ udelay(1); /* wait 1us */
if (mode == W100_SUSPEND_EXTMEM) {
-
/* CKE: Tri-State */
val = readl(remapped_regs + mmMEM_EXT_CNTL);
- val |= 0x40000000; /* bit30=1 */
+ val |= 0x40000000; /* bit30=1 */
writel(val, remapped_regs + mmMEM_EXT_CNTL);
/* CLK: Stop */
val = readl(remapped_regs + mmMEM_EXT_CNTL);
- val &= ~(0x00000001); /* bit0=0 */
+ val &= ~(0x00000001); /* bit0=0 */
writel(val, remapped_regs + mmMEM_EXT_CNTL);
} else {
-
writel(0x00000000, remapped_regs + mmSCLK_CNTL);
writel(0x000000BF, remapped_regs + mmCLK_PIN_CNTL);
writel(0x00000015, remapped_regs + mmPWRMGT_CNTL);
@@ -1418,43 +1406,16 @@ static void w100_suspend(u32 mode)
udelay(5);
val = readl(remapped_regs + mmPLL_CNTL);
- val |= 0x00000004; /* bit2=1 */
+ val |= 0x00000004; /* bit2=1 */
writel(val, remapped_regs + mmPLL_CNTL);
writel(0x0000001d, remapped_regs + mmPWRMGT_CNTL);
}
}
-
-static void w100_resume(void)
-{
- u32 temp32;
-
- w100_hw_init();
- w100_pwm_setup();
-
- temp32 = readl(remapped_regs + mmDISP_DEBUG2);
- temp32 &= 0xff7fffff;
- temp32 |= 0x00800000;
- writel(temp32, remapped_regs + mmDISP_DEBUG2);
-
- if (current_par->lcdMode == LCD_MODE_480 || current_par->lcdMode == LCD_MODE_640) {
- w100_init_sharp_lcd(LCD_SHARP_VGA);
- if (current_par->lcdMode == LCD_MODE_640) {
- w100_init_vga_rotation(current_par->rotation_flag ? 270 : 90);
- }
- } else {
- w100_init_sharp_lcd(LCD_SHARP_QVGA);
- if (current_par->lcdMode == LCD_MODE_320) {
- w100_init_qvga_rotation(current_par->rotation_flag ? 270 : 90);
- }
- }
-}
-
-
static void w100_vsync(void)
{
u32 tmp;
- int timeout = 30000; /* VSync timeout = 30[ms] > 16.8[ms] */
+ int timeout = 30000; /* VSync timeout = 30[ms] > 16.8[ms] */
tmp = readl(remapped_regs + mmACTIVE_V_DISP);
@@ -1490,363 +1451,6 @@ static void w100_vsync(void)
writel(0x00000002, remapped_regs + mmGEN_INT_STATUS);
}
-
-static void w100_InitExtMem(u32 mode)
-{
- switch(mode) {
- case LCD_SHARP_QVGA:
- /* QVGA doesn't use external memory
- nothing to do, really. */
- break;
- case LCD_SHARP_VGA:
- writel(0x00007800, remapped_regs + mmMC_BIST_CTRL);
- writel(0x00040003, remapped_regs + mmMEM_EXT_CNTL);
- writel(0x00200021, remapped_regs + mmMEM_SDRAM_MODE_REG);
- udelay(100);
- writel(0x80200021, remapped_regs + mmMEM_SDRAM_MODE_REG);
- udelay(100);
- writel(0x00650021, remapped_regs + mmMEM_SDRAM_MODE_REG);
- udelay(100);
- writel(0x10002a4a, remapped_regs + mmMEM_EXT_TIMING_CNTL);
- writel(0x7ff87012, remapped_regs + mmMEM_IO_CNTL);
- break;
- default:
- break;
- }
-}
-
-
-#define RESCTL_ADRS 0x00
-#define PHACTRL_ADRS 0x01
-#define DUTYCTRL_ADRS 0x02
-#define POWERREG0_ADRS 0x03
-#define POWERREG1_ADRS 0x04
-#define GPOR3_ADRS 0x05
-#define PICTRL_ADRS 0x06
-#define POLCTRL_ADRS 0x07
-
-#define RESCTL_QVGA 0x01
-#define RESCTL_VGA 0x00
-
-#define POWER1_VW_ON 0x01 /* VW Supply FET ON */
-#define POWER1_GVSS_ON 0x02 /* GVSS(-8V) Power Supply ON */
-#define POWER1_VDD_ON 0x04 /* VDD(8V),SVSS(-4V) Power Supply ON */
-
-#define POWER1_VW_OFF 0x00 /* VW Supply FET OFF */
-#define POWER1_GVSS_OFF 0x00 /* GVSS(-8V) Power Supply OFF */
-#define POWER1_VDD_OFF 0x00 /* VDD(8V),SVSS(-4V) Power Supply OFF */
-
-#define POWER0_COM_DCLK 0x01 /* COM Voltage DC Bias DAC Serial Data Clock */
-#define POWER0_COM_DOUT 0x02 /* COM Voltage DC Bias DAC Serial Data Out */
-#define POWER0_DAC_ON 0x04 /* DAC Power Supply ON */
-#define POWER0_COM_ON 0x08 /* COM Powewr Supply ON */
-#define POWER0_VCC5_ON 0x10 /* VCC5 Power Supply ON */
-
-#define POWER0_DAC_OFF 0x00 /* DAC Power Supply OFF */
-#define POWER0_COM_OFF 0x00 /* COM Powewr Supply OFF */
-#define POWER0_VCC5_OFF 0x00 /* VCC5 Power Supply OFF */
-
-#define PICTRL_INIT_STATE 0x01
-#define PICTRL_INIOFF 0x02
-#define PICTRL_POWER_DOWN 0x04
-#define PICTRL_COM_SIGNAL_OFF 0x08
-#define PICTRL_DAC_SIGNAL_OFF 0x10
-
-#define PICTRL_POWER_ACTIVE (0)
-
-#define POLCTRL_SYNC_POL_FALL 0x01
-#define POLCTRL_EN_POL_FALL 0x02
-#define POLCTRL_DATA_POL_FALL 0x04
-#define POLCTRL_SYNC_ACT_H 0x08
-#define POLCTRL_EN_ACT_L 0x10
-
-#define POLCTRL_SYNC_POL_RISE 0x00
-#define POLCTRL_EN_POL_RISE 0x00
-#define POLCTRL_DATA_POL_RISE 0x00
-#define POLCTRL_SYNC_ACT_L 0x00
-#define POLCTRL_EN_ACT_H 0x00
-
-#define PHACTRL_PHASE_MANUAL 0x01
-
-#define PHAD_QVGA_DEFAULT_VAL (9)
-#define COMADJ_DEFAULT (125)
-
-static void lcdtg_ssp_send(u8 adrs, u8 data)
-{
- w100fb_ssp_send(adrs,data);
-}
-
-/*
- * This is only a psuedo I2C interface. We can't use the standard kernel
- * routines as the interface is write only. We just assume the data is acked...
- */
-static void lcdtg_ssp_i2c_send(u8 data)
-{
- lcdtg_ssp_send(POWERREG0_ADRS, data);
- udelay(10);
-}
-
-static void lcdtg_i2c_send_bit(u8 data)
-{
- lcdtg_ssp_i2c_send(data);
- lcdtg_ssp_i2c_send(data | POWER0_COM_DCLK);
- lcdtg_ssp_i2c_send(data);
-}
-
-static void lcdtg_i2c_send_start(u8 base)
-{
- lcdtg_ssp_i2c_send(base | POWER0_COM_DCLK | POWER0_COM_DOUT);
- lcdtg_ssp_i2c_send(base | POWER0_COM_DCLK);
- lcdtg_ssp_i2c_send(base);
-}
-
-static void lcdtg_i2c_send_stop(u8 base)
-{
- lcdtg_ssp_i2c_send(base);
- lcdtg_ssp_i2c_send(base | POWER0_COM_DCLK);
- lcdtg_ssp_i2c_send(base | POWER0_COM_DCLK | POWER0_COM_DOUT);
-}
-
-static void lcdtg_i2c_send_byte(u8 base, u8 data)
-{
- int i;
- for (i = 0; i < 8; i++) {
- if (data & 0x80)
- lcdtg_i2c_send_bit(base | POWER0_COM_DOUT);
- else
- lcdtg_i2c_send_bit(base);
- data <<= 1;
- }
-}
-
-static void lcdtg_i2c_wait_ack(u8 base)
-{
- lcdtg_i2c_send_bit(base);
-}
-
-static void lcdtg_set_common_voltage(u8 base_data, u8 data)
-{
- /* Set Common Voltage to M62332FP via I2C */
- lcdtg_i2c_send_start(base_data);
- lcdtg_i2c_send_byte(base_data, 0x9c);
- lcdtg_i2c_wait_ack(base_data);
- lcdtg_i2c_send_byte(base_data, 0x00);
- lcdtg_i2c_wait_ack(base_data);
- lcdtg_i2c_send_byte(base_data, data);
- lcdtg_i2c_wait_ack(base_data);
- lcdtg_i2c_send_stop(base_data);
-}
-
-static struct lcdtg_register_setting {
- u8 adrs;
- u8 data;
- u32 wait;
-} lcdtg_power_on_table[] = {
-
- /* Initialize Internal Logic & Port */
- { PICTRL_ADRS,
- PICTRL_POWER_DOWN | PICTRL_INIOFF | PICTRL_INIT_STATE |
- PICTRL_COM_SIGNAL_OFF | PICTRL_DAC_SIGNAL_OFF,
- 0 },
-
- { POWERREG0_ADRS,
- POWER0_COM_DCLK | POWER0_COM_DOUT | POWER0_DAC_OFF | POWER0_COM_OFF |
- POWER0_VCC5_OFF,
- 0 },
-
- { POWERREG1_ADRS,
- POWER1_VW_OFF | POWER1_GVSS_OFF | POWER1_VDD_OFF,
- 0 },
-
- /* VDD(+8V),SVSS(-4V) ON */
- { POWERREG1_ADRS,
- POWER1_VW_OFF | POWER1_GVSS_OFF | POWER1_VDD_ON /* VDD ON */,
- 3000 },
-
- /* DAC ON */
- { POWERREG0_ADRS,
- POWER0_COM_DCLK | POWER0_COM_DOUT | POWER0_DAC_ON /* DAC ON */ |
- POWER0_COM_OFF | POWER0_VCC5_OFF,
- 0 },
-
- /* INIB = H, INI = L */
- { PICTRL_ADRS,
- /* PICTL[0] = H , PICTL[1] = PICTL[2] = PICTL[4] = L */
- PICTRL_INIT_STATE | PICTRL_COM_SIGNAL_OFF,
- 0 },
-
- /* Set Common Voltage */
- { 0xfe, 0, 0 },
-
- /* VCC5 ON */
- { POWERREG0_ADRS,
- POWER0_COM_DCLK | POWER0_COM_DOUT | POWER0_DAC_ON /* DAC ON */ |
- POWER0_COM_OFF | POWER0_VCC5_ON /* VCC5 ON */,
- 0 },
-
- /* GVSS(-8V) ON */
- { POWERREG1_ADRS,
- POWER1_VW_OFF | POWER1_GVSS_ON /* GVSS ON */ |
- POWER1_VDD_ON /* VDD ON */,
- 2000 },
-
- /* COM SIGNAL ON (PICTL[3] = L) */
- { PICTRL_ADRS,
- PICTRL_INIT_STATE,
- 0 },
-
- /* COM ON */
- { POWERREG0_ADRS,
- POWER0_COM_DCLK | POWER0_COM_DOUT | POWER0_DAC_ON /* DAC ON */ |
- POWER0_COM_ON /* COM ON */ | POWER0_VCC5_ON /* VCC5_ON */,
- 0 },
-
- /* VW ON */
- { POWERREG1_ADRS,
- POWER1_VW_ON /* VW ON */ | POWER1_GVSS_ON /* GVSS ON */ |
- POWER1_VDD_ON /* VDD ON */,
- 0 /* Wait 100ms */ },
-
- /* Signals output enable */
- { PICTRL_ADRS,
- 0 /* Signals output enable */,
- 0 },
-
- { PHACTRL_ADRS,
- PHACTRL_PHASE_MANUAL,
- 0 },
-
- /* Initialize for Input Signals from ATI */
- { POLCTRL_ADRS,
- POLCTRL_SYNC_POL_RISE | POLCTRL_EN_POL_RISE | POLCTRL_DATA_POL_RISE |
- POLCTRL_SYNC_ACT_L | POLCTRL_EN_ACT_H,
- 1000 /*100000*/ /* Wait 100ms */ },
-
- /* end mark */
- { 0xff, 0, 0 }
-};
-
-static void lcdtg_resume(void)
-{
- if (current_par->lcdMode == LCD_MODE_480 || current_par->lcdMode == LCD_MODE_640) {
- lcdtg_hw_init(LCD_SHARP_VGA);
- } else {
- lcdtg_hw_init(LCD_SHARP_QVGA);
- }
-}
-
-static void lcdtg_suspend(void)
-{
- int i;
-
- for (i = 0; i < (current_par->xres * current_par->yres); i++) {
- writew(0xffff, remapped_fbuf + (2*i));
- }
-
- /* 60Hz x 2 frame = 16.7msec x 2 = 33.4 msec */
- mdelay(34);
-
- /* (1)VW OFF */
- lcdtg_ssp_send(POWERREG1_ADRS, POWER1_VW_OFF | POWER1_GVSS_ON | POWER1_VDD_ON);
-
- /* (2)COM OFF */
- lcdtg_ssp_send(PICTRL_ADRS, PICTRL_COM_SIGNAL_OFF);
- lcdtg_ssp_send(POWERREG0_ADRS, POWER0_DAC_ON | POWER0_COM_OFF | POWER0_VCC5_ON);
-
- /* (3)Set Common Voltage Bias 0V */
- lcdtg_set_common_voltage(POWER0_DAC_ON | POWER0_COM_OFF | POWER0_VCC5_ON, 0);
-
- /* (4)GVSS OFF */
- lcdtg_ssp_send(POWERREG1_ADRS, POWER1_VW_OFF | POWER1_GVSS_OFF | POWER1_VDD_ON);
-
- /* (5)VCC5 OFF */
- lcdtg_ssp_send(POWERREG0_ADRS, POWER0_DAC_ON | POWER0_COM_OFF | POWER0_VCC5_OFF);
-
- /* (6)Set PDWN, INIOFF, DACOFF */
- lcdtg_ssp_send(PICTRL_ADRS, PICTRL_INIOFF | PICTRL_DAC_SIGNAL_OFF |
- PICTRL_POWER_DOWN | PICTRL_COM_SIGNAL_OFF);
-
- /* (7)DAC OFF */
- lcdtg_ssp_send(POWERREG0_ADRS, POWER0_DAC_OFF | POWER0_COM_OFF | POWER0_VCC5_OFF);
-
- /* (8)VDD OFF */
- lcdtg_ssp_send(POWERREG1_ADRS, POWER1_VW_OFF | POWER1_GVSS_OFF | POWER1_VDD_OFF);
-
-}
-
-static void lcdtg_set_phadadj(u32 mode)
-{
- int adj;
-
- if (mode == LCD_SHARP_VGA) {
- /* Setting for VGA */
- adj = current_par->phadadj;
- if (adj < 0) {
- adj = PHACTRL_PHASE_MANUAL;
- } else {
- adj = ((adj & 0x0f) << 1) | PHACTRL_PHASE_MANUAL;
- }
- } else {
- /* Setting for QVGA */
- adj = (PHAD_QVGA_DEFAULT_VAL << 1) | PHACTRL_PHASE_MANUAL;
- }
- lcdtg_ssp_send(PHACTRL_ADRS, adj);
-}
-
-static void lcdtg_hw_init(u32 mode)
-{
- int i;
- int comadj;
-
- i = 0;
- while(lcdtg_power_on_table[i].adrs != 0xff) {
- if (lcdtg_power_on_table[i].adrs == 0xfe) {
- /* Set Common Voltage */
- comadj = current_par->comadj;
- if (comadj < 0) {
- comadj = COMADJ_DEFAULT;
- }
- lcdtg_set_common_voltage((POWER0_DAC_ON | POWER0_COM_OFF | POWER0_VCC5_OFF), comadj);
- } else if (lcdtg_power_on_table[i].adrs == PHACTRL_ADRS) {
- /* Set Phase Adjuct */
- lcdtg_set_phadadj(mode);
- } else {
- /* Other */
- lcdtg_ssp_send(lcdtg_power_on_table[i].adrs, lcdtg_power_on_table[i].data);
- }
- if (lcdtg_power_on_table[i].wait != 0)
- udelay(lcdtg_power_on_table[i].wait);
- i++;
- }
-
- switch(mode) {
- case LCD_SHARP_QVGA:
- /* Set Lcd Resolution (QVGA) */
- lcdtg_ssp_send(RESCTL_ADRS, RESCTL_QVGA);
- break;
- case LCD_SHARP_VGA:
- /* Set Lcd Resolution (VGA) */
- lcdtg_ssp_send(RESCTL_ADRS, RESCTL_VGA);
- break;
- default:
- break;
- }
-}
-
-static void lcdtg_lcd_change(u32 mode)
-{
- /* Set Phase Adjuct */
- lcdtg_set_phadadj(mode);
-
- if (mode == LCD_SHARP_VGA)
- /* Set Lcd Resolution (VGA) */
- lcdtg_ssp_send(RESCTL_ADRS, RESCTL_VGA);
- else if (mode == LCD_SHARP_QVGA)
- /* Set Lcd Resolution (QVGA) */
- lcdtg_ssp_send(RESCTL_ADRS, RESCTL_QVGA);
-}
-
-
static struct device_driver w100fb_driver = {
.name = "w100fb",
.bus = &platform_bus_type,
@@ -1870,4 +1474,4 @@ module_init(w100fb_init);
module_exit(w100fb_cleanup);
MODULE_DESCRIPTION("ATI Imageon w100 framebuffer driver");
-MODULE_LICENSE("GPLv2");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/w100fb.h b/drivers/video/w100fb.h
index 41624f961237..7a58a1e3e427 100644
--- a/drivers/video/w100fb.h
+++ b/drivers/video/w100fb.h
@@ -5,9 +5,12 @@
*
* Copyright (C) 2002, ATI Corp.
* Copyright (C) 2004-2005 Richard Purdie
+ * Copyright (c) 2005 Ian Molton <spyro@f2s.com>
*
* Modified to work with 2.6 by Richard Purdie <rpurdie@rpsys.net>
*
+ * w32xx support by Ian Molton
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
@@ -19,7 +22,7 @@
/* Block CIF Start: */
#define mmCHIP_ID 0x0000
-#define mmREVISION_ID 0x0004
+#define mmREVISION_ID 0x0004
#define mmWRAP_BUF_A 0x0008
#define mmWRAP_BUF_B 0x000C
#define mmWRAP_TOP_DIR 0x0010
@@ -88,7 +91,7 @@
#define mmDISP_DEBUG 0x04D4
#define mmDISP_DB_BUF_CNTL 0x04D8
#define mmDISP_CRC_SIG 0x04DC
-#define mmCRTC_DEFAULT_COUNT 0x04E0
+#define mmCRTC_DEFAULT_COUNT 0x04E0
#define mmLCD_BACKGROUND_COLOR 0x04E4
#define mmCRTC_PS2 0x04E8
#define mmCRTC_PS2_VPOS 0x04EC
@@ -119,17 +122,17 @@
/* Block DISPLAY End: */
/* Block GFX Start: */
-#define mmBRUSH_OFFSET 0x108C
-#define mmBRUSH_Y_X 0x1074
-#define mmDEFAULT_PITCH_OFFSET 0x10A0
-#define mmDEFAULT_SC_BOTTOM_RIGHT 0x10A8
-#define mmDEFAULT2_SC_BOTTOM_RIGHT 0x10AC
-#define mmGLOBAL_ALPHA 0x1210
-#define mmFILTER_COEF 0x1214
-#define mmMVC_CNTL_START 0x11E0
-#define mmE2_ARITHMETIC_CNTL 0x1220
-#define mmENG_CNTL 0x13E8
-#define mmENG_PERF_CNT 0x13F0
+#define mmBRUSH_OFFSET 0x108C
+#define mmBRUSH_Y_X 0x1074
+#define mmDEFAULT_PITCH_OFFSET 0x10A0
+#define mmDEFAULT_SC_BOTTOM_RIGHT 0x10A8
+#define mmDEFAULT2_SC_BOTTOM_RIGHT 0x10AC
+#define mmGLOBAL_ALPHA 0x1210
+#define mmFILTER_COEF 0x1214
+#define mmMVC_CNTL_START 0x11E0
+#define mmE2_ARITHMETIC_CNTL 0x1220
+#define mmENG_CNTL 0x13E8
+#define mmENG_PERF_CNT 0x13F0
/* Block GFX End: */
/* Block IDCT Start: */
@@ -141,22 +144,38 @@
/* Block IDCT End: */
/* Block MC Start: */
-#define mmMEM_CNTL 0x0180
-#define mmMEM_ARB 0x0184
-#define mmMC_FB_LOCATION 0x0188
-#define mmMEM_EXT_CNTL 0x018C
-#define mmMC_EXT_MEM_LOCATION 0x0190
-#define mmMEM_EXT_TIMING_CNTL 0x0194
-#define mmMEM_SDRAM_MODE_REG 0x0198
-#define mmMEM_IO_CNTL 0x019C
-#define mmMC_DEBUG 0x01A0
-#define mmMC_BIST_CTRL 0x01A4
-#define mmMC_BIST_COLLAR_READ 0x01A8
-#define mmTC_MISMATCH 0x01AC
-#define mmMC_PERF_MON_CNTL 0x01B0
-#define mmMC_PERF_COUNTERS 0x01B4
+#define mmMEM_CNTL 0x0180
+#define mmMEM_ARB 0x0184
+#define mmMC_FB_LOCATION 0x0188
+#define mmMEM_EXT_CNTL 0x018C
+#define mmMC_EXT_MEM_LOCATION 0x0190
+#define mmMEM_EXT_TIMING_CNTL 0x0194
+#define mmMEM_SDRAM_MODE_REG 0x0198
+#define mmMEM_IO_CNTL 0x019C
+#define mmMC_DEBUG 0x01A0
+#define mmMC_BIST_CTRL 0x01A4
+#define mmMC_BIST_COLLAR_READ 0x01A8
+#define mmTC_MISMATCH 0x01AC
+#define mmMC_PERF_MON_CNTL 0x01B0
+#define mmMC_PERF_COUNTERS 0x01B4
/* Block MC End: */
+/* Block BM Start: */
+#define mmBM_EXT_MEM_BANDWIDTH 0x0A00
+#define mmBM_OFFSET 0x0A04
+#define mmBM_MEM_EXT_TIMING_CNTL 0x0A08
+#define mmBM_MEM_EXT_CNTL 0x0A0C
+#define mmBM_MEM_MODE_REG 0x0A10
+#define mmBM_MEM_IO_CNTL 0x0A18
+#define mmBM_CONFIG 0x0A1C
+#define mmBM_STATUS 0x0A20
+#define mmBM_DEBUG 0x0A24
+#define mmBM_PERF_MON_CNTL 0x0A28
+#define mmBM_PERF_COUNTERS 0x0A2C
+#define mmBM_PERF2_MON_CNTL 0x0A30
+#define mmBM_PERF2_COUNTERS 0x0A34
+/* Block BM End: */
+
/* Block RBBM Start: */
#define mmWAIT_UNTIL 0x1400
#define mmISYNC_CNTL 0x1404
@@ -176,439 +195,575 @@
/* Block CG End: */
/* default value definitions */
-#define defWRAP_TOP_DIR 0x00000000
-#define defWRAP_START_DIR 0x00000000
-#define defCFGREG_BASE 0x00000000
-#define defCIF_IO 0x000C0902
-#define defINTF_CNTL 0x00000011
-#define defCPU_DEFAULTS 0x00000006
-#define defHW_INT 0x00000000
-#define defMC_EXT_MEM_LOCATION 0x07ff0000
-#define defTC_MISMATCH 0x00000000
+#define defWRAP_TOP_DIR 0x00000000
+#define defWRAP_START_DIR 0x00000000
+#define defCFGREG_BASE 0x00000000
+#define defCIF_IO 0x000C0902
+#define defINTF_CNTL 0x00000011
+#define defCPU_DEFAULTS 0x00000006
+#define defHW_INT 0x00000000
+#define defMC_EXT_MEM_LOCATION 0x07ff0000
+#define defTC_MISMATCH 0x00000000
#define W100_CFG_BASE 0x0
#define W100_CFG_LEN 0x10
#define W100_REG_BASE 0x10000
#define W100_REG_LEN 0x2000
#define MEM_INT_BASE_VALUE 0x100000
-#define MEM_INT_TOP_VALUE_W100 0x15ffff
#define MEM_EXT_BASE_VALUE 0x800000
-#define MEM_EXT_TOP_VALUE 0x9fffff
+#define MEM_INT_SIZE 0x05ffff
+#define MEM_WINDOW_BASE 0x100000
+#define MEM_WINDOW_SIZE 0xf00000
+
#define WRAP_BUF_BASE_VALUE 0x80000
#define WRAP_BUF_TOP_VALUE 0xbffff
+#define CHIP_ID_W100 0x57411002
+#define CHIP_ID_W3200 0x56441002
+#define CHIP_ID_W3220 0x57441002
-/* data structure definitions */
+/* Register structure definitions */
struct wrap_top_dir_t {
- unsigned long top_addr : 23;
- unsigned long : 9;
+ unsigned long top_addr : 23;
+ unsigned long : 9;
} __attribute__((packed));
union wrap_top_dir_u {
- unsigned long val : 32;
- struct wrap_top_dir_t f;
+ unsigned long val : 32;
+ struct wrap_top_dir_t f;
} __attribute__((packed));
struct wrap_start_dir_t {
- unsigned long start_addr : 23;
- unsigned long : 9;
+ unsigned long start_addr : 23;
+ unsigned long : 9;
} __attribute__((packed));
union wrap_start_dir_u {
- unsigned long val : 32;
- struct wrap_start_dir_t f;
+ unsigned long val : 32;
+ struct wrap_start_dir_t f;
} __attribute__((packed));
struct cif_cntl_t {
- unsigned long swap_reg : 2;
- unsigned long swap_fbuf_1 : 2;
- unsigned long swap_fbuf_2 : 2;
- unsigned long swap_fbuf_3 : 2;
- unsigned long pmi_int_disable : 1;
- unsigned long pmi_schmen_disable : 1;
- unsigned long intb_oe : 1;
- unsigned long en_wait_to_compensate_dq_prop_dly : 1;
- unsigned long compensate_wait_rd_size : 2;
- unsigned long wait_asserted_timeout_val : 2;
- unsigned long wait_masked_val : 2;
- unsigned long en_wait_timeout : 1;
- unsigned long en_one_clk_setup_before_wait : 1;
- unsigned long interrupt_active_high : 1;
- unsigned long en_overwrite_straps : 1;
- unsigned long strap_wait_active_hi : 1;
- unsigned long lat_busy_count : 2;
- unsigned long lat_rd_pm4_sclk_busy : 1;
- unsigned long dis_system_bits : 1;
- unsigned long dis_mr : 1;
- unsigned long cif_spare_1 : 4;
+ unsigned long swap_reg : 2;
+ unsigned long swap_fbuf_1 : 2;
+ unsigned long swap_fbuf_2 : 2;
+ unsigned long swap_fbuf_3 : 2;
+ unsigned long pmi_int_disable : 1;
+ unsigned long pmi_schmen_disable : 1;
+ unsigned long intb_oe : 1;
+ unsigned long en_wait_to_compensate_dq_prop_dly : 1;
+ unsigned long compensate_wait_rd_size : 2;
+ unsigned long wait_asserted_timeout_val : 2;
+ unsigned long wait_masked_val : 2;
+ unsigned long en_wait_timeout : 1;
+ unsigned long en_one_clk_setup_before_wait : 1;
+ unsigned long interrupt_active_high : 1;
+ unsigned long en_overwrite_straps : 1;
+ unsigned long strap_wait_active_hi : 1;
+ unsigned long lat_busy_count : 2;
+ unsigned long lat_rd_pm4_sclk_busy : 1;
+ unsigned long dis_system_bits : 1;
+ unsigned long dis_mr : 1;
+ unsigned long cif_spare_1 : 4;
} __attribute__((packed));
union cif_cntl_u {
- unsigned long val : 32;
- struct cif_cntl_t f;
+ unsigned long val : 32;
+ struct cif_cntl_t f;
} __attribute__((packed));
struct cfgreg_base_t {
- unsigned long cfgreg_base : 24;
- unsigned long : 8;
+ unsigned long cfgreg_base : 24;
+ unsigned long : 8;
} __attribute__((packed));
union cfgreg_base_u {
- unsigned long val : 32;
- struct cfgreg_base_t f;
+ unsigned long val : 32;
+ struct cfgreg_base_t f;
} __attribute__((packed));
struct cif_io_t {
- unsigned long dq_srp : 1;
- unsigned long dq_srn : 1;
- unsigned long dq_sp : 4;
- unsigned long dq_sn : 4;
- unsigned long waitb_srp : 1;
- unsigned long waitb_srn : 1;
- unsigned long waitb_sp : 4;
- unsigned long waitb_sn : 4;
- unsigned long intb_srp : 1;
- unsigned long intb_srn : 1;
- unsigned long intb_sp : 4;
- unsigned long intb_sn : 4;
- unsigned long : 2;
+ unsigned long dq_srp : 1;
+ unsigned long dq_srn : 1;
+ unsigned long dq_sp : 4;
+ unsigned long dq_sn : 4;
+ unsigned long waitb_srp : 1;
+ unsigned long waitb_srn : 1;
+ unsigned long waitb_sp : 4;
+ unsigned long waitb_sn : 4;
+ unsigned long intb_srp : 1;
+ unsigned long intb_srn : 1;
+ unsigned long intb_sp : 4;
+ unsigned long intb_sn : 4;
+ unsigned long : 2;
} __attribute__((packed));
union cif_io_u {
- unsigned long val : 32;
- struct cif_io_t f;
+ unsigned long val : 32;
+ struct cif_io_t f;
} __attribute__((packed));
struct cif_read_dbg_t {
- unsigned long unpacker_pre_fetch_trig_gen : 2;
- unsigned long dly_second_rd_fetch_trig : 1;
- unsigned long rst_rd_burst_id : 1;
- unsigned long dis_rd_burst_id : 1;
- unsigned long en_block_rd_when_packer_is_not_emp : 1;
- unsigned long dis_pre_fetch_cntl_sm : 1;
- unsigned long rbbm_chrncy_dis : 1;
- unsigned long rbbm_rd_after_wr_lat : 2;
- unsigned long dis_be_during_rd : 1;
- unsigned long one_clk_invalidate_pulse : 1;
- unsigned long dis_chnl_priority : 1;
- unsigned long rst_read_path_a_pls : 1;
- unsigned long rst_read_path_b_pls : 1;
- unsigned long dis_reg_rd_fetch_trig : 1;
- unsigned long dis_rd_fetch_trig_from_ind_addr : 1;
- unsigned long dis_rd_same_byte_to_trig_fetch : 1;
- unsigned long dis_dir_wrap : 1;
- unsigned long dis_ring_buf_to_force_dec : 1;
- unsigned long dis_addr_comp_in_16bit : 1;
- unsigned long clr_w : 1;
- unsigned long err_rd_tag_is_3 : 1;
- unsigned long err_load_when_ful_a : 1;
- unsigned long err_load_when_ful_b : 1;
- unsigned long : 7;
+ unsigned long unpacker_pre_fetch_trig_gen : 2;
+ unsigned long dly_second_rd_fetch_trig : 1;
+ unsigned long rst_rd_burst_id : 1;
+ unsigned long dis_rd_burst_id : 1;
+ unsigned long en_block_rd_when_packer_is_not_emp : 1;
+ unsigned long dis_pre_fetch_cntl_sm : 1;
+ unsigned long rbbm_chrncy_dis : 1;
+ unsigned long rbbm_rd_after_wr_lat : 2;
+ unsigned long dis_be_during_rd : 1;
+ unsigned long one_clk_invalidate_pulse : 1;
+ unsigned long dis_chnl_priority : 1;
+ unsigned long rst_read_path_a_pls : 1;
+ unsigned long rst_read_path_b_pls : 1;
+ unsigned long dis_reg_rd_fetch_trig : 1;
+ unsigned long dis_rd_fetch_trig_from_ind_addr : 1;
+ unsigned long dis_rd_same_byte_to_trig_fetch : 1;
+ unsigned long dis_dir_wrap : 1;
+ unsigned long dis_ring_buf_to_force_dec : 1;
+ unsigned long dis_addr_comp_in_16bit : 1;
+ unsigned long clr_w : 1;
+ unsigned long err_rd_tag_is_3 : 1;
+ unsigned long err_load_when_ful_a : 1;
+ unsigned long err_load_when_ful_b : 1;
+ unsigned long : 7;
} __attribute__((packed));
union cif_read_dbg_u {
- unsigned long val : 32;
- struct cif_read_dbg_t f;
+ unsigned long val : 32;
+ struct cif_read_dbg_t f;
} __attribute__((packed));
struct cif_write_dbg_t {
- unsigned long packer_timeout_count : 2;
- unsigned long en_upper_load_cond : 1;
- unsigned long en_chnl_change_cond : 1;
- unsigned long dis_addr_comp_cond : 1;
- unsigned long dis_load_same_byte_addr_cond : 1;
- unsigned long dis_timeout_cond : 1;
- unsigned long dis_timeout_during_rbbm : 1;
- unsigned long dis_packer_ful_during_rbbm_timeout : 1;
- unsigned long en_dword_split_to_rbbm : 1;
- unsigned long en_dummy_val : 1;
- unsigned long dummy_val_sel : 1;
- unsigned long mask_pm4_wrptr_dec : 1;
- unsigned long dis_mc_clean_cond : 1;
- unsigned long err_two_reqi_during_ful : 1;
- unsigned long err_reqi_during_idle_clk : 1;
- unsigned long err_global : 1;
- unsigned long en_wr_buf_dbg_load : 1;
- unsigned long en_wr_buf_dbg_path : 1;
- unsigned long sel_wr_buf_byte : 3;
- unsigned long dis_rd_flush_wr : 1;
- unsigned long dis_packer_ful_cond : 1;
- unsigned long dis_invalidate_by_ops_chnl : 1;
- unsigned long en_halt_when_reqi_err : 1;
- unsigned long cif_spare_2 : 5;
- unsigned long : 1;
+ unsigned long packer_timeout_count : 2;
+ unsigned long en_upper_load_cond : 1;
+ unsigned long en_chnl_change_cond : 1;
+ unsigned long dis_addr_comp_cond : 1;
+ unsigned long dis_load_same_byte_addr_cond : 1;
+ unsigned long dis_timeout_cond : 1;
+ unsigned long dis_timeout_during_rbbm : 1;
+ unsigned long dis_packer_ful_during_rbbm_timeout : 1;
+ unsigned long en_dword_split_to_rbbm : 1;
+ unsigned long en_dummy_val : 1;
+ unsigned long dummy_val_sel : 1;
+ unsigned long mask_pm4_wrptr_dec : 1;
+ unsigned long dis_mc_clean_cond : 1;
+ unsigned long err_two_reqi_during_ful : 1;
+ unsigned long err_reqi_during_idle_clk : 1;
+ unsigned long err_global : 1;
+ unsigned long en_wr_buf_dbg_load : 1;
+ unsigned long en_wr_buf_dbg_path : 1;
+ unsigned long sel_wr_buf_byte : 3;
+ unsigned long dis_rd_flush_wr : 1;
+ unsigned long dis_packer_ful_cond : 1;
+ unsigned long dis_invalidate_by_ops_chnl : 1;
+ unsigned long en_halt_when_reqi_err : 1;
+ unsigned long cif_spare_2 : 5;
+ unsigned long : 1;
} __attribute__((packed));
union cif_write_dbg_u {
- unsigned long val : 32;
- struct cif_write_dbg_t f;
+ unsigned long val : 32;
+ struct cif_write_dbg_t f;
} __attribute__((packed));
struct intf_cntl_t {
- unsigned char ad_inc_a : 1;
- unsigned char ring_buf_a : 1;
- unsigned char rd_fetch_trigger_a : 1;
- unsigned char rd_data_rdy_a : 1;
- unsigned char ad_inc_b : 1;
- unsigned char ring_buf_b : 1;
- unsigned char rd_fetch_trigger_b : 1;
- unsigned char rd_data_rdy_b : 1;
+ unsigned char ad_inc_a : 1;
+ unsigned char ring_buf_a : 1;
+ unsigned char rd_fetch_trigger_a : 1;
+ unsigned char rd_data_rdy_a : 1;
+ unsigned char ad_inc_b : 1;
+ unsigned char ring_buf_b : 1;
+ unsigned char rd_fetch_trigger_b : 1;
+ unsigned char rd_data_rdy_b : 1;
} __attribute__((packed));
union intf_cntl_u {
- unsigned char val : 8;
- struct intf_cntl_t f;
+ unsigned char val : 8;
+ struct intf_cntl_t f;
} __attribute__((packed));
struct cpu_defaults_t {
- unsigned char unpack_rd_data : 1;
- unsigned char access_ind_addr_a: 1;
- unsigned char access_ind_addr_b: 1;
- unsigned char access_scratch_reg : 1;
- unsigned char pack_wr_data : 1;
- unsigned char transition_size : 1;
- unsigned char en_read_buf_mode : 1;
- unsigned char rd_fetch_scratch : 1;
+ unsigned char unpack_rd_data : 1;
+ unsigned char access_ind_addr_a : 1;
+ unsigned char access_ind_addr_b : 1;
+ unsigned char access_scratch_reg : 1;
+ unsigned char pack_wr_data : 1;
+ unsigned char transition_size : 1;
+ unsigned char en_read_buf_mode : 1;
+ unsigned char rd_fetch_scratch : 1;
} __attribute__((packed));
union cpu_defaults_u {
- unsigned char val : 8;
- struct cpu_defaults_t f;
+ unsigned char val : 8;
+ struct cpu_defaults_t f;
+} __attribute__((packed));
+
+struct crtc_total_t {
+ unsigned long crtc_h_total : 10;
+ unsigned long : 6;
+ unsigned long crtc_v_total : 10;
+ unsigned long : 6;
+} __attribute__((packed));
+
+union crtc_total_u {
+ unsigned long val : 32;
+ struct crtc_total_t f;
+} __attribute__((packed));
+
+struct crtc_ss_t {
+ unsigned long ss_start : 10;
+ unsigned long : 6;
+ unsigned long ss_end : 10;
+ unsigned long : 2;
+ unsigned long ss_align : 1;
+ unsigned long ss_pol : 1;
+ unsigned long ss_run_mode : 1;
+ unsigned long ss_en : 1;
+} __attribute__((packed));
+
+union crtc_ss_u {
+ unsigned long val : 32;
+ struct crtc_ss_t f;
+} __attribute__((packed));
+
+struct active_h_disp_t {
+ unsigned long active_h_start : 10;
+ unsigned long : 6;
+ unsigned long active_h_end : 10;
+ unsigned long : 6;
+} __attribute__((packed));
+
+union active_h_disp_u {
+ unsigned long val : 32;
+ struct active_h_disp_t f;
+} __attribute__((packed));
+
+struct active_v_disp_t {
+ unsigned long active_v_start : 10;
+ unsigned long : 6;
+ unsigned long active_v_end : 10;
+ unsigned long : 6;
+} __attribute__((packed));
+
+union active_v_disp_u {
+ unsigned long val : 32;
+ struct active_v_disp_t f;
+} __attribute__((packed));
+
+struct graphic_h_disp_t {
+ unsigned long graphic_h_start : 10;
+ unsigned long : 6;
+ unsigned long graphic_h_end : 10;
+ unsigned long : 6;
+} __attribute__((packed));
+
+union graphic_h_disp_u {
+ unsigned long val : 32;
+ struct graphic_h_disp_t f;
+} __attribute__((packed));
+
+struct graphic_v_disp_t {
+ unsigned long graphic_v_start : 10;
+ unsigned long : 6;
+ unsigned long graphic_v_end : 10;
+ unsigned long : 6;
+} __attribute__((packed));
+
+union graphic_v_disp_u{
+ unsigned long val : 32;
+ struct graphic_v_disp_t f;
+} __attribute__((packed));
+
+struct graphic_ctrl_t_w100 {
+ unsigned long color_depth : 3;
+ unsigned long portrait_mode : 2;
+ unsigned long low_power_on : 1;
+ unsigned long req_freq : 4;
+ unsigned long en_crtc : 1;
+ unsigned long en_graphic_req : 1;
+ unsigned long en_graphic_crtc : 1;
+ unsigned long total_req_graphic : 9;
+ unsigned long lcd_pclk_on : 1;
+ unsigned long lcd_sclk_on : 1;
+ unsigned long pclk_running : 1;
+ unsigned long sclk_running : 1;
+ unsigned long : 6;
+} __attribute__((packed));
+
+struct graphic_ctrl_t_w32xx {
+ unsigned long color_depth : 3;
+ unsigned long portrait_mode : 2;
+ unsigned long low_power_on : 1;
+ unsigned long req_freq : 4;
+ unsigned long en_crtc : 1;
+ unsigned long en_graphic_req : 1;
+ unsigned long en_graphic_crtc : 1;
+ unsigned long total_req_graphic : 10;
+ unsigned long lcd_pclk_on : 1;
+ unsigned long lcd_sclk_on : 1;
+ unsigned long pclk_running : 1;
+ unsigned long sclk_running : 1;
+ unsigned long : 5;
+} __attribute__((packed));
+
+union graphic_ctrl_u {
+ unsigned long val : 32;
+ struct graphic_ctrl_t_w100 f_w100;
+ struct graphic_ctrl_t_w32xx f_w32xx;
} __attribute__((packed));
struct video_ctrl_t {
- unsigned long video_mode : 1;
- unsigned long keyer_en : 1;
- unsigned long en_video_req : 1;
- unsigned long en_graphic_req_video : 1;
- unsigned long en_video_crtc : 1;
- unsigned long video_hor_exp : 2;
- unsigned long video_ver_exp : 2;
- unsigned long uv_combine : 1;
- unsigned long total_req_video : 9;
- unsigned long video_ch_sel : 1;
- unsigned long video_portrait : 2;
- unsigned long yuv2rgb_en : 1;
- unsigned long yuv2rgb_option : 1;
- unsigned long video_inv_hor : 1;
- unsigned long video_inv_ver : 1;
- unsigned long gamma_sel : 2;
- unsigned long dis_limit : 1;
- unsigned long en_uv_hblend : 1;
- unsigned long rgb_gamma_sel : 2;
+ unsigned long video_mode : 1;
+ unsigned long keyer_en : 1;
+ unsigned long en_video_req : 1;
+ unsigned long en_graphic_req_video : 1;
+ unsigned long en_video_crtc : 1;
+ unsigned long video_hor_exp : 2;
+ unsigned long video_ver_exp : 2;
+ unsigned long uv_combine : 1;
+ unsigned long total_req_video : 9;
+ unsigned long video_ch_sel : 1;
+ unsigned long video_portrait : 2;
+ unsigned long yuv2rgb_en : 1;
+ unsigned long yuv2rgb_option : 1;
+ unsigned long video_inv_hor : 1;
+ unsigned long video_inv_ver : 1;
+ unsigned long gamma_sel : 2;
+ unsigned long dis_limit : 1;
+ unsigned long en_uv_hblend : 1;
+ unsigned long rgb_gamma_sel : 2;
} __attribute__((packed));
union video_ctrl_u {
- unsigned long val : 32;
- struct video_ctrl_t f;
+ unsigned long val : 32;
+ struct video_ctrl_t f;
} __attribute__((packed));
struct disp_db_buf_cntl_rd_t {
- unsigned long en_db_buf : 1;
- unsigned long update_db_buf_done : 1;
- unsigned long db_buf_cntl : 6;
- unsigned long : 24;
+ unsigned long en_db_buf : 1;
+ unsigned long update_db_buf_done : 1;
+ unsigned long db_buf_cntl : 6;
+ unsigned long : 24;
} __attribute__((packed));
union disp_db_buf_cntl_rd_u {
- unsigned long val : 32;
- struct disp_db_buf_cntl_rd_t f;
+ unsigned long val : 32;
+ struct disp_db_buf_cntl_rd_t f;
} __attribute__((packed));
struct disp_db_buf_cntl_wr_t {
- unsigned long en_db_buf : 1;
- unsigned long update_db_buf : 1;
- unsigned long db_buf_cntl : 6;
- unsigned long : 24;
+ unsigned long en_db_buf : 1;
+ unsigned long update_db_buf : 1;
+ unsigned long db_buf_cntl : 6;
+ unsigned long : 24;
} __attribute__((packed));
union disp_db_buf_cntl_wr_u {
- unsigned long val : 32;
- struct disp_db_buf_cntl_wr_t f;
+ unsigned long val : 32;
+ struct disp_db_buf_cntl_wr_t f;
} __attribute__((packed));
struct gamma_value1_t {
- unsigned long gamma1 : 8;
- unsigned long gamma2 : 8;
- unsigned long gamma3 : 8;
- unsigned long gamma4 : 8;
+ unsigned long gamma1 : 8;
+ unsigned long gamma2 : 8;
+ unsigned long gamma3 : 8;
+ unsigned long gamma4 : 8;
} __attribute__((packed));
union gamma_value1_u {
- unsigned long val : 32;
- struct gamma_value1_t f;
+ unsigned long val : 32;
+ struct gamma_value1_t f;
} __attribute__((packed));
struct gamma_value2_t {
- unsigned long gamma5 : 8;
- unsigned long gamma6 : 8;
- unsigned long gamma7 : 8;
- unsigned long gamma8 : 8;
+ unsigned long gamma5 : 8;
+ unsigned long gamma6 : 8;
+ unsigned long gamma7 : 8;
+ unsigned long gamma8 : 8;
} __attribute__((packed));
union gamma_value2_u {
- unsigned long val : 32;
- struct gamma_value2_t f;
+ unsigned long val : 32;
+ struct gamma_value2_t f;
} __attribute__((packed));
struct gamma_slope_t {
- unsigned long slope1 : 3;
- unsigned long slope2 : 3;
- unsigned long slope3 : 3;
- unsigned long slope4 : 3;
- unsigned long slope5 : 3;
- unsigned long slope6 : 3;
- unsigned long slope7 : 3;
- unsigned long slope8 : 3;
- unsigned long : 8;
+ unsigned long slope1 : 3;
+ unsigned long slope2 : 3;
+ unsigned long slope3 : 3;
+ unsigned long slope4 : 3;
+ unsigned long slope5 : 3;
+ unsigned long slope6 : 3;
+ unsigned long slope7 : 3;
+ unsigned long slope8 : 3;
+ unsigned long : 8;
} __attribute__((packed));
union gamma_slope_u {
- unsigned long val : 32;
- struct gamma_slope_t f;
+ unsigned long val : 32;
+ struct gamma_slope_t f;
} __attribute__((packed));
struct mc_ext_mem_location_t {
- unsigned long mc_ext_mem_start : 16;
- unsigned long mc_ext_mem_top : 16;
+ unsigned long mc_ext_mem_start : 16;
+ unsigned long mc_ext_mem_top : 16;
} __attribute__((packed));
union mc_ext_mem_location_u {
- unsigned long val : 32;
- struct mc_ext_mem_location_t f;
+ unsigned long val : 32;
+ struct mc_ext_mem_location_t f;
+} __attribute__((packed));
+
+struct mc_fb_location_t {
+ unsigned long mc_fb_start : 16;
+ unsigned long mc_fb_top : 16;
+} __attribute__((packed));
+
+union mc_fb_location_u {
+ unsigned long val : 32;
+ struct mc_fb_location_t f;
} __attribute__((packed));
struct clk_pin_cntl_t {
- unsigned long osc_en : 1;
- unsigned long osc_gain : 5;
- unsigned long dont_use_xtalin : 1;
- unsigned long xtalin_pm_en : 1;
- unsigned long xtalin_dbl_en : 1;
- unsigned long : 7;
- unsigned long cg_debug : 16;
+ unsigned long osc_en : 1;
+ unsigned long osc_gain : 5;
+ unsigned long dont_use_xtalin : 1;
+ unsigned long xtalin_pm_en : 1;
+ unsigned long xtalin_dbl_en : 1;
+ unsigned long : 7;
+ unsigned long cg_debug : 16;
} __attribute__((packed));
union clk_pin_cntl_u {
- unsigned long val : 32;
- struct clk_pin_cntl_t f;
+ unsigned long val : 32;
+ struct clk_pin_cntl_t f;
} __attribute__((packed));
struct pll_ref_fb_div_t {
- unsigned long pll_ref_div : 4;
- unsigned long : 4;
- unsigned long pll_fb_div_int : 6;
- unsigned long : 2;
- unsigned long pll_fb_div_frac : 3;
- unsigned long : 1;
- unsigned long pll_reset_time : 4;
- unsigned long pll_lock_time : 8;
+ unsigned long pll_ref_div : 4;
+ unsigned long : 4;
+ unsigned long pll_fb_div_int : 6;
+ unsigned long : 2;
+ unsigned long pll_fb_div_frac : 3;
+ unsigned long : 1;
+ unsigned long pll_reset_time : 4;
+ unsigned long pll_lock_time : 8;
} __attribute__((packed));
union pll_ref_fb_div_u {
- unsigned long val : 32;
- struct pll_ref_fb_div_t f;
+ unsigned long val : 32;
+ struct pll_ref_fb_div_t f;
} __attribute__((packed));
struct pll_cntl_t {
- unsigned long pll_pwdn : 1;
- unsigned long pll_reset : 1;
- unsigned long pll_pm_en : 1;
- unsigned long pll_mode : 1;
- unsigned long pll_refclk_sel : 1;
- unsigned long pll_fbclk_sel : 1;
- unsigned long pll_tcpoff : 1;
- unsigned long pll_pcp : 3;
- unsigned long pll_pvg : 3;
- unsigned long pll_vcofr : 1;
- unsigned long pll_ioffset : 2;
- unsigned long pll_pecc_mode : 2;
- unsigned long pll_pecc_scon : 2;
- unsigned long pll_dactal : 4;
- unsigned long pll_cp_clip : 2;
- unsigned long pll_conf : 3;
- unsigned long pll_mbctrl : 2;
- unsigned long pll_ring_off : 1;
+ unsigned long pll_pwdn : 1;
+ unsigned long pll_reset : 1;
+ unsigned long pll_pm_en : 1;
+ unsigned long pll_mode : 1;
+ unsigned long pll_refclk_sel : 1;
+ unsigned long pll_fbclk_sel : 1;
+ unsigned long pll_tcpoff : 1;
+ unsigned long pll_pcp : 3;
+ unsigned long pll_pvg : 3;
+ unsigned long pll_vcofr : 1;
+ unsigned long pll_ioffset : 2;
+ unsigned long pll_pecc_mode : 2;
+ unsigned long pll_pecc_scon : 2;
+ unsigned long pll_dactal : 4;
+ unsigned long pll_cp_clip : 2;
+ unsigned long pll_conf : 3;
+ unsigned long pll_mbctrl : 2;
+ unsigned long pll_ring_off : 1;
} __attribute__((packed));
union pll_cntl_u {
- unsigned long val : 32;
- struct pll_cntl_t f;
+ unsigned long val : 32;
+ struct pll_cntl_t f;
} __attribute__((packed));
struct sclk_cntl_t {
- unsigned long sclk_src_sel : 2;
- unsigned long : 2;
- unsigned long sclk_post_div_fast : 4;
- unsigned long sclk_clkon_hys : 3;
- unsigned long sclk_post_div_slow : 4;
- unsigned long disp_cg_ok2switch_en : 1;
- unsigned long sclk_force_reg : 1;
- unsigned long sclk_force_disp : 1;
- unsigned long sclk_force_mc : 1;
- unsigned long sclk_force_extmc : 1;
- unsigned long sclk_force_cp : 1;
- unsigned long sclk_force_e2 : 1;
- unsigned long sclk_force_e3 : 1;
- unsigned long sclk_force_idct : 1;
- unsigned long sclk_force_bist : 1;
- unsigned long busy_extend_cp : 1;
- unsigned long busy_extend_e2 : 1;
- unsigned long busy_extend_e3 : 1;
- unsigned long busy_extend_idct : 1;
- unsigned long : 3;
+ unsigned long sclk_src_sel : 2;
+ unsigned long : 2;
+ unsigned long sclk_post_div_fast : 4;
+ unsigned long sclk_clkon_hys : 3;
+ unsigned long sclk_post_div_slow : 4;
+ unsigned long disp_cg_ok2switch_en : 1;
+ unsigned long sclk_force_reg : 1;
+ unsigned long sclk_force_disp : 1;
+ unsigned long sclk_force_mc : 1;
+ unsigned long sclk_force_extmc : 1;
+ unsigned long sclk_force_cp : 1;
+ unsigned long sclk_force_e2 : 1;
+ unsigned long sclk_force_e3 : 1;
+ unsigned long sclk_force_idct : 1;
+ unsigned long sclk_force_bist : 1;
+ unsigned long busy_extend_cp : 1;
+ unsigned long busy_extend_e2 : 1;
+ unsigned long busy_extend_e3 : 1;
+ unsigned long busy_extend_idct : 1;
+ unsigned long : 3;
} __attribute__((packed));
union sclk_cntl_u {
- unsigned long val : 32;
- struct sclk_cntl_t f;
+ unsigned long val : 32;
+ struct sclk_cntl_t f;
} __attribute__((packed));
struct pclk_cntl_t {
- unsigned long pclk_src_sel : 2;
- unsigned long : 2;
- unsigned long pclk_post_div : 4;
- unsigned long : 8;
- unsigned long pclk_force_disp : 1;
- unsigned long : 15;
+ unsigned long pclk_src_sel : 2;
+ unsigned long : 2;
+ unsigned long pclk_post_div : 4;
+ unsigned long : 8;
+ unsigned long pclk_force_disp : 1;
+ unsigned long : 15;
} __attribute__((packed));
union pclk_cntl_u {
- unsigned long val : 32;
- struct pclk_cntl_t f;
+ unsigned long val : 32;
+ struct pclk_cntl_t f;
} __attribute__((packed));
+
+#define TESTCLK_SRC_PLL 0x01
+#define TESTCLK_SRC_SCLK 0x02
+#define TESTCLK_SRC_PCLK 0x03
+/* 4 and 5 seem to by XTAL/M */
+#define TESTCLK_SRC_XTAL 0x06
+
struct clk_test_cntl_t {
- unsigned long testclk_sel : 4;
- unsigned long : 3;
- unsigned long start_check_freq : 1;
- unsigned long tstcount_rst : 1;
- unsigned long : 15;
- unsigned long test_count : 8;
+ unsigned long testclk_sel : 4;
+ unsigned long : 3;
+ unsigned long start_check_freq : 1;
+ unsigned long tstcount_rst : 1;
+ unsigned long : 15;
+ unsigned long test_count : 8;
} __attribute__((packed));
union clk_test_cntl_u {
- unsigned long val : 32;
- struct clk_test_cntl_t f;
+ unsigned long val : 32;
+ struct clk_test_cntl_t f;
} __attribute__((packed));
struct pwrmgt_cntl_t {
- unsigned long pwm_enable : 1;
- unsigned long : 1;
- unsigned long pwm_mode_req : 2;
- unsigned long pwm_wakeup_cond : 2;
- unsigned long pwm_fast_noml_hw_en : 1;
- unsigned long pwm_noml_fast_hw_en : 1;
- unsigned long pwm_fast_noml_cond : 4;
- unsigned long pwm_noml_fast_cond : 4;
- unsigned long pwm_idle_timer : 8;
- unsigned long pwm_busy_timer : 8;
+ unsigned long pwm_enable : 1;
+ unsigned long : 1;
+ unsigned long pwm_mode_req : 2;
+ unsigned long pwm_wakeup_cond : 2;
+ unsigned long pwm_fast_noml_hw_en : 1;
+ unsigned long pwm_noml_fast_hw_en : 1;
+ unsigned long pwm_fast_noml_cond : 4;
+ unsigned long pwm_noml_fast_cond : 4;
+ unsigned long pwm_idle_timer : 8;
+ unsigned long pwm_busy_timer : 8;
} __attribute__((packed));
union pwrmgt_cntl_u {
- unsigned long val : 32;
- struct pwrmgt_cntl_t f;
+ unsigned long val : 32;
+ struct pwrmgt_cntl_t f;
} __attribute__((packed));
#endif