Merge branch 'for-linus' of git://gitorious.org/linux-omap-dss2/linux
[safe/jmp/linux-2.6] / drivers / platform / x86 / thinkpad_acpi.c
index e0fbe73..e67e4fe 100644 (file)
@@ -21,7 +21,7 @@
  *  02110-1301, USA.
  */
 
-#define TPACPI_VERSION "0.23"
+#define TPACPI_VERSION "0.24"
 #define TPACPI_SYSFS_VERSION 0x020700
 
 /*
@@ -61,6 +61,7 @@
 
 #include <linux/nvram.h>
 #include <linux/proc_fs.h>
+#include <linux/seq_file.h>
 #include <linux/sysfs.h>
 #include <linux/backlight.h>
 #include <linux/fb.h>
@@ -261,7 +262,7 @@ struct tp_acpi_drv_struct {
 struct ibm_struct {
        char *name;
 
-       int (*read) (char *);
+       int (*read) (struct seq_file *);
        int (*write) (char *);
        void (*exit) (void);
        void (*resume) (void);
@@ -789,36 +790,25 @@ static int __init register_tpacpi_subdriver(struct ibm_struct *ibm)
  ****************************************************************************
  ****************************************************************************/
 
-static int dispatch_procfs_read(char *page, char **start, off_t off,
-                       int count, int *eof, void *data)
+static int dispatch_proc_show(struct seq_file *m, void *v)
 {
-       struct ibm_struct *ibm = data;
-       int len;
+       struct ibm_struct *ibm = m->private;
 
        if (!ibm || !ibm->read)
                return -EINVAL;
+       return ibm->read(m);
+}
 
-       len = ibm->read(page);
-       if (len < 0)
-               return len;
-
-       if (len <= off + count)
-               *eof = 1;
-       *start = page + off;
-       len -= off;
-       if (len > count)
-               len = count;
-       if (len < 0)
-               len = 0;
-
-       return len;
+static int dispatch_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, dispatch_proc_show, PDE(inode)->data);
 }
 
-static int dispatch_procfs_write(struct file *file,
+static ssize_t dispatch_proc_write(struct file *file,
                        const char __user *userbuf,
-                       unsigned long count, void *data)
+                       size_t count, loff_t *pos)
 {
-       struct ibm_struct *ibm = data;
+       struct ibm_struct *ibm = PDE(file->f_path.dentry->d_inode)->data;
        char *kernbuf;
        int ret;
 
@@ -847,6 +837,15 @@ static int dispatch_procfs_write(struct file *file,
        return ret;
 }
 
+static const struct file_operations dispatch_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = dispatch_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+       .write          = dispatch_proc_write,
+};
+
 static char *next_cmd(char **cmds)
 {
        char *start = *cmds;
@@ -1019,11 +1018,8 @@ static int parse_strtoul(const char *buf,
 {
        char *endp;
 
-       while (*buf && isspace(*buf))
-               buf++;
-       *value = simple_strtoul(buf, &endp, 0);
-       while (*endp && isspace(*endp))
-               endp++;
+       *value = simple_strtoul(skip_spaces(buf), &endp, 0);
+       endp = skip_spaces(endp);
        if (*endp || *value > max)
                return -EINVAL;
 
@@ -1100,7 +1096,7 @@ static int __init tpacpi_check_std_acpi_brightness_support(void)
         */
 
        status = acpi_walk_namespace(ACPI_TYPE_METHOD, vid_handle, 3,
-                                    tpacpi_acpi_walk_find_bcl, NULL,
+                                    tpacpi_acpi_walk_find_bcl, NULL, NULL,
                                     &bcl_ptr);
 
        if (ACPI_SUCCESS(status) && bcl_levels > 2) {
@@ -1401,12 +1397,10 @@ static ssize_t tpacpi_rfk_sysfs_enable_store(const enum tpacpi_rfk_id id,
 }
 
 /* procfs -------------------------------------------------------------- */
-static int tpacpi_rfk_procfs_read(const enum tpacpi_rfk_id id, char *p)
+static int tpacpi_rfk_procfs_read(const enum tpacpi_rfk_id id, struct seq_file *m)
 {
-       int len = 0;
-
        if (id >= TPACPI_RFK_SW_MAX)
-               len += sprintf(p + len, "status:\t\tnot supported\n");
+               seq_printf(m, "status:\t\tnot supported\n");
        else {
                int status;
 
@@ -1420,13 +1414,13 @@ static int tpacpi_rfk_procfs_read(const enum tpacpi_rfk_id id, char *p)
                                return status;
                }
 
-               len += sprintf(p + len, "status:\t\t%s\n",
+               seq_printf(m, "status:\t\t%s\n",
                                (status == TPACPI_RFK_RADIO_ON) ?
                                        "enabled" : "disabled");
-               len += sprintf(p + len, "commands:\tenable, disable\n");
+               seq_printf(m, "commands:\tenable, disable\n");
        }
 
-       return len;
+       return 0;
 }
 
 static int tpacpi_rfk_procfs_write(const enum tpacpi_rfk_id id, char *buf)
@@ -1904,14 +1898,11 @@ static int __init thinkpad_acpi_driver_init(struct ibm_init_struct *iibm)
        return 0;
 }
 
-static int thinkpad_acpi_driver_read(char *p)
+static int thinkpad_acpi_driver_read(struct seq_file *m)
 {
-       int len = 0;
-
-       len += sprintf(p + len, "driver:\t\t%s\n", TPACPI_DESC);
-       len += sprintf(p + len, "version:\t%s\n", TPACPI_VERSION);
-
-       return len;
+       seq_printf(m, "driver:\t\t%s\n", TPACPI_DESC);
+       seq_printf(m, "version:\t%s\n", TPACPI_VERSION);
+       return 0;
 }
 
 static struct ibm_struct thinkpad_acpi_driver_data = {
@@ -3759,14 +3750,13 @@ static void hotkey_resume(void)
 }
 
 /* procfs -------------------------------------------------------------- */
-static int hotkey_read(char *p)
+static int hotkey_read(struct seq_file *m)
 {
        int res, status;
-       int len = 0;
 
        if (!tp_features.hotkey) {
-               len += sprintf(p + len, "status:\t\tnot supported\n");
-               return len;
+               seq_printf(m, "status:\t\tnot supported\n");
+               return 0;
        }
 
        if (mutex_lock_killable(&hotkey_mutex))
@@ -3778,17 +3768,16 @@ static int hotkey_read(char *p)
        if (res)
                return res;
 
-       len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 0));
+       seq_printf(m, "status:\t\t%s\n", enabled(status, 0));
        if (hotkey_all_mask) {
-               len += sprintf(p + len, "mask:\t\t0x%08x\n", hotkey_user_mask);
-               len += sprintf(p + len,
-                              "commands:\tenable, disable, reset, <mask>\n");
+               seq_printf(m, "mask:\t\t0x%08x\n", hotkey_user_mask);
+               seq_printf(m, "commands:\tenable, disable, reset, <mask>\n");
        } else {
-               len += sprintf(p + len, "mask:\t\tnot supported\n");
-               len += sprintf(p + len, "commands:\tenable, disable, reset\n");
+               seq_printf(m, "mask:\t\tnot supported\n");
+               seq_printf(m, "commands:\tenable, disable, reset\n");
        }
 
-       return len;
+       return 0;
 }
 
 static void hotkey_enabledisable_warn(bool enable)
@@ -4054,9 +4043,9 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm)
 }
 
 /* procfs -------------------------------------------------------------- */
-static int bluetooth_read(char *p)
+static int bluetooth_read(struct seq_file *m)
 {
-       return tpacpi_rfk_procfs_read(TPACPI_RFK_BLUETOOTH_SW_ID, p);
+       return tpacpi_rfk_procfs_read(TPACPI_RFK_BLUETOOTH_SW_ID, m);
 }
 
 static int bluetooth_write(char *buf)
@@ -4244,9 +4233,9 @@ static int __init wan_init(struct ibm_init_struct *iibm)
 }
 
 /* procfs -------------------------------------------------------------- */
-static int wan_read(char *p)
+static int wan_read(struct seq_file *m)
 {
-       return tpacpi_rfk_procfs_read(TPACPI_RFK_WWAN_SW_ID, p);
+       return tpacpi_rfk_procfs_read(TPACPI_RFK_WWAN_SW_ID, m);
 }
 
 static int wan_write(char *buf)
@@ -4621,14 +4610,13 @@ static int video_expand_toggle(void)
        /* not reached */
 }
 
-static int video_read(char *p)
+static int video_read(struct seq_file *m)
 {
        int status, autosw;
-       int len = 0;
 
        if (video_supported == TPACPI_VIDEO_NONE) {
-               len += sprintf(p + len, "status:\t\tnot supported\n");
-               return len;
+               seq_printf(m, "status:\t\tnot supported\n");
+               return 0;
        }
 
        status = video_outputsw_get();
@@ -4639,20 +4627,20 @@ static int video_read(char *p)
        if (autosw < 0)
                return autosw;
 
-       len += sprintf(p + len, "status:\t\tsupported\n");
-       len += sprintf(p + len, "lcd:\t\t%s\n", enabled(status, 0));
-       len += sprintf(p + len, "crt:\t\t%s\n", enabled(status, 1));
+       seq_printf(m, "status:\t\tsupported\n");
+       seq_printf(m, "lcd:\t\t%s\n", enabled(status, 0));
+       seq_printf(m, "crt:\t\t%s\n", enabled(status, 1));
        if (video_supported == TPACPI_VIDEO_NEW)
-               len += sprintf(p + len, "dvi:\t\t%s\n", enabled(status, 3));
-       len += sprintf(p + len, "auto:\t\t%s\n", enabled(autosw, 0));
-       len += sprintf(p + len, "commands:\tlcd_enable, lcd_disable\n");
-       len += sprintf(p + len, "commands:\tcrt_enable, crt_disable\n");
+               seq_printf(m, "dvi:\t\t%s\n", enabled(status, 3));
+       seq_printf(m, "auto:\t\t%s\n", enabled(autosw, 0));
+       seq_printf(m, "commands:\tlcd_enable, lcd_disable\n");
+       seq_printf(m, "commands:\tcrt_enable, crt_disable\n");
        if (video_supported == TPACPI_VIDEO_NEW)
-               len += sprintf(p + len, "commands:\tdvi_enable, dvi_disable\n");
-       len += sprintf(p + len, "commands:\tauto_enable, auto_disable\n");
-       len += sprintf(p + len, "commands:\tvideo_switch, expand_toggle\n");
+               seq_printf(m, "commands:\tdvi_enable, dvi_disable\n");
+       seq_printf(m, "commands:\tauto_enable, auto_disable\n");
+       seq_printf(m, "commands:\tvideo_switch, expand_toggle\n");
 
-       return len;
+       return 0;
 }
 
 static int video_write(char *buf)
@@ -4844,25 +4832,24 @@ static void light_exit(void)
                flush_workqueue(tpacpi_wq);
 }
 
-static int light_read(char *p)
+static int light_read(struct seq_file *m)
 {
-       int len = 0;
        int status;
 
        if (!tp_features.light) {
-               len += sprintf(p + len, "status:\t\tnot supported\n");
+               seq_printf(m, "status:\t\tnot supported\n");
        } else if (!tp_features.light_status) {
-               len += sprintf(p + len, "status:\t\tunknown\n");
-               len += sprintf(p + len, "commands:\ton, off\n");
+               seq_printf(m, "status:\t\tunknown\n");
+               seq_printf(m, "commands:\ton, off\n");
        } else {
                status = light_get_status();
                if (status < 0)
                        return status;
-               len += sprintf(p + len, "status:\t\t%s\n", onoff(status, 0));
-               len += sprintf(p + len, "commands:\ton, off\n");
+               seq_printf(m, "status:\t\t%s\n", onoff(status, 0));
+               seq_printf(m, "commands:\ton, off\n");
        }
 
-       return len;
+       return 0;
 }
 
 static int light_write(char *buf)
@@ -4940,20 +4927,18 @@ static void cmos_exit(void)
        device_remove_file(&tpacpi_pdev->dev, &dev_attr_cmos_command);
 }
 
-static int cmos_read(char *p)
+static int cmos_read(struct seq_file *m)
 {
-       int len = 0;
-
        /* cmos not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
           R30, R31, T20-22, X20-21 */
        if (!cmos_handle)
-               len += sprintf(p + len, "status:\t\tnot supported\n");
+               seq_printf(m, "status:\t\tnot supported\n");
        else {
-               len += sprintf(p + len, "status:\t\tsupported\n");
-               len += sprintf(p + len, "commands:\t<cmd> (<cmd> is 0-21)\n");
+               seq_printf(m, "status:\t\tsupported\n");
+               seq_printf(m, "commands:\t<cmd> (<cmd> is 0-21)\n");
        }
 
-       return len;
+       return 0;
 }
 
 static int cmos_write(char *buf)
@@ -5328,15 +5313,13 @@ static int __init led_init(struct ibm_init_struct *iibm)
        ((s) == TPACPI_LED_OFF ? "off" : \
                ((s) == TPACPI_LED_ON ? "on" : "blinking"))
 
-static int led_read(char *p)
+static int led_read(struct seq_file *m)
 {
-       int len = 0;
-
        if (!led_supported) {
-               len += sprintf(p + len, "status:\t\tnot supported\n");
-               return len;
+               seq_printf(m, "status:\t\tnot supported\n");
+               return 0;
        }
-       len += sprintf(p + len, "status:\t\tsupported\n");
+       seq_printf(m, "status:\t\tsupported\n");
 
        if (led_supported == TPACPI_LED_570) {
                /* 570 */
@@ -5345,15 +5328,15 @@ static int led_read(char *p)
                        status = led_get_status(i);
                        if (status < 0)
                                return -EIO;
-                       len += sprintf(p + len, "%d:\t\t%s\n",
+                       seq_printf(m, "%d:\t\t%s\n",
                                       i, str_led_status(status));
                }
        }
 
-       len += sprintf(p + len, "commands:\t"
+       seq_printf(m, "commands:\t"
                       "<led> on, <led> off, <led> blink (<led> is 0-15)\n");
 
-       return len;
+       return 0;
 }
 
 static int led_write(char *buf)
@@ -5426,18 +5409,16 @@ static int __init beep_init(struct ibm_init_struct *iibm)
        return (beep_handle)? 0 : 1;
 }
 
-static int beep_read(char *p)
+static int beep_read(struct seq_file *m)
 {
-       int len = 0;
-
        if (!beep_handle)
-               len += sprintf(p + len, "status:\t\tnot supported\n");
+               seq_printf(m, "status:\t\tnot supported\n");
        else {
-               len += sprintf(p + len, "status:\t\tsupported\n");
-               len += sprintf(p + len, "commands:\t<cmd> (<cmd> is 0-17)\n");
+               seq_printf(m, "status:\t\tsupported\n");
+               seq_printf(m, "commands:\t<cmd> (<cmd> is 0-17)\n");
        }
 
-       return len;
+       return 0;
 }
 
 static int beep_write(char *buf)
@@ -5798,9 +5779,8 @@ static void thermal_exit(void)
        }
 }
 
-static int thermal_read(char *p)
+static int thermal_read(struct seq_file *m)
 {
-       int len = 0;
        int n, i;
        struct ibm_thermal_sensors_struct t;
 
@@ -5808,16 +5788,16 @@ static int thermal_read(char *p)
        if (unlikely(n < 0))
                return n;
 
-       len += sprintf(p + len, "temperatures:\t");
+       seq_printf(m, "temperatures:\t");
 
        if (n > 0) {
                for (i = 0; i < (n - 1); i++)
-                       len += sprintf(p + len, "%d ", t.temp[i] / 1000);
-               len += sprintf(p + len, "%d\n", t.temp[i] / 1000);
+                       seq_printf(m, "%d ", t.temp[i] / 1000);
+               seq_printf(m, "%d\n", t.temp[i] / 1000);
        } else
-               len += sprintf(p + len, "not supported\n");
+               seq_printf(m, "not supported\n");
 
-       return len;
+       return 0;
 }
 
 static struct ibm_struct thermal_driver_data = {
@@ -5832,39 +5812,38 @@ static struct ibm_struct thermal_driver_data = {
 
 static u8 ecdump_regs[256];
 
-static int ecdump_read(char *p)
+static int ecdump_read(struct seq_file *m)
 {
-       int len = 0;
        int i, j;
        u8 v;
 
-       len += sprintf(p + len, "EC      "
+       seq_printf(m, "EC      "
                       " +00 +01 +02 +03 +04 +05 +06 +07"
                       " +08 +09 +0a +0b +0c +0d +0e +0f\n");
        for (i = 0; i < 256; i += 16) {
-               len += sprintf(p + len, "EC 0x%02x:", i);
+               seq_printf(m, "EC 0x%02x:", i);
                for (j = 0; j < 16; j++) {
                        if (!acpi_ec_read(i + j, &v))
                                break;
                        if (v != ecdump_regs[i + j])
-                               len += sprintf(p + len, " *%02x", v);
+                               seq_printf(m, " *%02x", v);
                        else
-                               len += sprintf(p + len, "  %02x", v);
+                               seq_printf(m, "  %02x", v);
                        ecdump_regs[i + j] = v;
                }
-               len += sprintf(p + len, "\n");
+               seq_putc(m, '\n');
                if (j != 16)
                        break;
        }
 
        /* These are way too dangerous to advertise openly... */
 #if 0
-       len += sprintf(p + len, "commands:\t0x<offset> 0x<value>"
+       seq_printf(m, "commands:\t0x<offset> 0x<value>"
                       " (<offset> is 00-ff, <value> is 00-ff)\n");
-       len += sprintf(p + len, "commands:\t0x<offset> <value>  "
+       seq_printf(m, "commands:\t0x<offset> <value>  "
                       " (<offset> is 00-ff, <value> is 0-255)\n");
 #endif
-       return len;
+       return 0;
 }
 
 static int ecdump_write(char *buf)
@@ -6317,23 +6296,22 @@ static void brightness_exit(void)
        tpacpi_brightness_checkpoint_nvram();
 }
 
-static int brightness_read(char *p)
+static int brightness_read(struct seq_file *m)
 {
-       int len = 0;
        int level;
 
        level = brightness_get(NULL);
        if (level < 0) {
-               len += sprintf(p + len, "level:\t\tunreadable\n");
+               seq_printf(m, "level:\t\tunreadable\n");
        } else {
-               len += sprintf(p + len, "level:\t\t%d\n", level);
-               len += sprintf(p + len, "commands:\tup, down\n");
-               len += sprintf(p + len, "commands:\tlevel <level>"
+               seq_printf(m, "level:\t\t%d\n", level);
+               seq_printf(m, "commands:\tup, down\n");
+               seq_printf(m, "commands:\tlevel <level>"
                               " (<level> is 0-%d)\n",
                               (tp_features.bright_16levels) ? 15 : 7);
        }
 
-       return len;
+       return 0;
 }
 
 static int brightness_write(char *buf)
@@ -6406,11 +6384,13 @@ static struct ibm_struct brightness_driver_data = {
  * and we leave them unchanged.
  */
 
+#ifdef CONFIG_THINKPAD_ACPI_ALSA_SUPPORT
+
 #define TPACPI_ALSA_DRVNAME  "ThinkPad EC"
 #define TPACPI_ALSA_SHRTNAME "ThinkPad Console Audio Control"
 #define TPACPI_ALSA_MIXERNAME TPACPI_ALSA_SHRTNAME
 
-static int alsa_index = SNDRV_DEFAULT_IDX1;
+static int alsa_index = ~((1 << (SNDRV_CARDS - 3)) - 1); /* last three slots */
 static char *alsa_id = "ThinkPadEC";
 static int alsa_enable = SNDRV_DEFAULT_ENABLE1;
 
@@ -6727,10 +6707,11 @@ static int __init volume_create_alsa_mixer(void)
 
        rc = snd_card_create(alsa_index, alsa_id, THIS_MODULE,
                            sizeof(struct tpacpi_alsa_data), &card);
-       if (rc < 0)
-               return rc;
-       if (!card)
-               return -ENOMEM;
+       if (rc < 0 || !card) {
+               printk(TPACPI_ERR
+                       "Failed to create ALSA card structures: %d\n", rc);
+               return 1;
+       }
 
        BUG_ON(!card->private_data);
        data = card->private_data;
@@ -6763,8 +6744,9 @@ static int __init volume_create_alsa_mixer(void)
                rc = snd_ctl_add(card, ctl_vol);
                if (rc < 0) {
                        printk(TPACPI_ERR
-                               "Failed to create ALSA volume control\n");
-                       goto err_out;
+                               "Failed to create ALSA volume control: %d\n",
+                               rc);
+                       goto err_exit;
                }
                data->ctl_vol_id = &ctl_vol->id;
        }
@@ -6772,22 +6754,25 @@ static int __init volume_create_alsa_mixer(void)
        ctl_mute = snd_ctl_new1(&volume_alsa_control_mute, NULL);
        rc = snd_ctl_add(card, ctl_mute);
        if (rc < 0) {
-               printk(TPACPI_ERR "Failed to create ALSA mute control\n");
-               goto err_out;
+               printk(TPACPI_ERR "Failed to create ALSA mute control: %d\n",
+                       rc);
+               goto err_exit;
        }
        data->ctl_mute_id = &ctl_mute->id;
 
        snd_card_set_dev(card, &tpacpi_pdev->dev);
        rc = snd_card_register(card);
-
-err_out:
        if (rc < 0) {
-               snd_card_free(card);
-               card = NULL;
+               printk(TPACPI_ERR "Failed to register ALSA card: %d\n", rc);
+               goto err_exit;
        }
 
        alsa_card = card;
-       return rc;
+       return 0;
+
+err_exit:
+       snd_card_free(card);
+       return 1;
 }
 
 #define TPACPI_VOL_Q_MUTEONLY  0x0001  /* Mute-only control available */
@@ -6921,29 +6906,28 @@ static int __init volume_init(struct ibm_init_struct *iibm)
        return 0;
 }
 
-static int volume_read(char *p)
+static int volume_read(struct seq_file *m)
 {
-       int len = 0;
        u8 status;
 
        if (volume_get_status(&status) < 0) {
-               len += sprintf(p + len, "level:\t\tunreadable\n");
+               seq_printf(m, "level:\t\tunreadable\n");
        } else {
                if (tp_features.mixer_no_level_control)
-                       len += sprintf(p + len, "level:\t\tunsupported\n");
+                       seq_printf(m, "level:\t\tunsupported\n");
                else
-                       len += sprintf(p + len, "level:\t\t%d\n",
+                       seq_printf(m, "level:\t\t%d\n",
                                        status & TP_EC_AUDIO_LVL_MSK);
 
-               len += sprintf(p + len, "mute:\t\t%s\n",
+               seq_printf(m, "mute:\t\t%s\n",
                                onoff(status, TP_EC_AUDIO_MUTESW));
 
                if (volume_control_allowed) {
-                       len += sprintf(p + len, "commands:\tunmute, mute\n");
+                       seq_printf(m, "commands:\tunmute, mute\n");
                        if (!tp_features.mixer_no_level_control) {
-                               len += sprintf(p + len,
+                               seq_printf(m,
                                               "commands:\tup, down\n");
-                               len += sprintf(p + len,
+                               seq_printf(m,
                                               "commands:\tlevel <level>"
                                               " (<level> is 0-%d)\n",
                                               TP_EC_VOLUME_MAX);
@@ -6951,7 +6935,7 @@ static int volume_read(char *p)
                }
        }
 
-       return len;
+       return 0;
 }
 
 static int volume_write(char *buf)
@@ -7039,6 +7023,28 @@ static struct ibm_struct volume_driver_data = {
        .shutdown = volume_shutdown,
 };
 
+#else /* !CONFIG_THINKPAD_ACPI_ALSA_SUPPORT */
+
+#define alsa_card NULL
+
+static void inline volume_alsa_notify_change(void)
+{
+}
+
+static int __init volume_init(struct ibm_init_struct *iibm)
+{
+       printk(TPACPI_INFO
+               "volume: disabled as there is no ALSA support in this kernel\n");
+
+       return 1;
+}
+
+static struct ibm_struct volume_driver_data = {
+       .name = "volume",
+};
+
+#endif /* CONFIG_THINKPAD_ACPI_ALSA_SUPPORT */
+
 /*************************************************************************
  * Fan subdriver
  */
@@ -7148,7 +7154,7 @@ static struct ibm_struct volume_driver_data = {
  *     The speeds are stored on handles
  *     (FANA:FAN9), (FANC:FANB), (FANE:FAND).
  *
- *     There are three default speed sets, acessible as handles:
+ *     There are three default speed sets, accessible as handles:
  *     FS1L,FS1M,FS1H; FS2L,FS2M,FS2H; FS3L,FS3M,FS3H
  *
  *     ACPI DSDT switches which set is in use depending on various
@@ -8113,9 +8119,8 @@ static void fan_resume(void)
        }
 }
 
-static int fan_read(char *p)
+static int fan_read(struct seq_file *m)
 {
-       int len = 0;
        int rc;
        u8 status;
        unsigned int speed = 0;
@@ -8127,7 +8132,7 @@ static int fan_read(char *p)
                if (rc < 0)
                        return rc;
 
-               len += sprintf(p + len, "status:\t\t%s\n"
+               seq_printf(m, "status:\t\t%s\n"
                               "level:\t\t%d\n",
                               (status != 0) ? "enabled" : "disabled", status);
                break;
@@ -8138,54 +8143,54 @@ static int fan_read(char *p)
                if (rc < 0)
                        return rc;
 
-               len += sprintf(p + len, "status:\t\t%s\n",
+               seq_printf(m, "status:\t\t%s\n",
                               (status != 0) ? "enabled" : "disabled");
 
                rc = fan_get_speed(&speed);
                if (rc < 0)
                        return rc;
 
-               len += sprintf(p + len, "speed:\t\t%d\n", speed);
+               seq_printf(m, "speed:\t\t%d\n", speed);
 
                if (status & TP_EC_FAN_FULLSPEED)
                        /* Disengaged mode takes precedence */
-                       len += sprintf(p + len, "level:\t\tdisengaged\n");
+                       seq_printf(m, "level:\t\tdisengaged\n");
                else if (status & TP_EC_FAN_AUTO)
-                       len += sprintf(p + len, "level:\t\tauto\n");
+                       seq_printf(m, "level:\t\tauto\n");
                else
-                       len += sprintf(p + len, "level:\t\t%d\n", status);
+                       seq_printf(m, "level:\t\t%d\n", status);
                break;
 
        case TPACPI_FAN_NONE:
        default:
-               len += sprintf(p + len, "status:\t\tnot supported\n");
+               seq_printf(m, "status:\t\tnot supported\n");
        }
 
        if (fan_control_commands & TPACPI_FAN_CMD_LEVEL) {
-               len += sprintf(p + len, "commands:\tlevel <level>");
+               seq_printf(m, "commands:\tlevel <level>");
 
                switch (fan_control_access_mode) {
                case TPACPI_FAN_WR_ACPI_SFAN:
-                       len += sprintf(p + len, " (<level> is 0-7)\n");
+                       seq_printf(m, " (<level> is 0-7)\n");
                        break;
 
                default:
-                       len += sprintf(p + len, " (<level> is 0-7, "
+                       seq_printf(m, " (<level> is 0-7, "
                                       "auto, disengaged, full-speed)\n");
                        break;
                }
        }
 
        if (fan_control_commands & TPACPI_FAN_CMD_ENABLE)
-               len += sprintf(p + len, "commands:\tenable, disable\n"
+               seq_printf(m, "commands:\tenable, disable\n"
                               "commands:\twatchdog <timeout> (<timeout> "
                               "is 0 (off), 1-120 (seconds))\n");
 
        if (fan_control_commands & TPACPI_FAN_CMD_SPEED)
-               len += sprintf(p + len, "commands:\tspeed <speed>"
+               seq_printf(m, "commands:\tspeed <speed>"
                               " (<speed> is 0-65535)\n");
 
-       return len;
+       return 0;
 }
 
 static int fan_write_cmd_level(const char *cmd, int *rc)
@@ -8472,19 +8477,19 @@ static int __init ibm_init(struct ibm_init_struct *iibm)
                "%s installed\n", ibm->name);
 
        if (ibm->read) {
-               entry = create_proc_entry(ibm->name,
-                                         S_IFREG | S_IRUGO | S_IWUSR,
-                                         proc_dir);
+               mode_t mode;
+
+               mode = S_IRUGO;
+               if (ibm->write)
+                       mode |= S_IWUSR;
+               entry = proc_create_data(ibm->name, mode, proc_dir,
+                                        &dispatch_proc_fops, ibm);
                if (!entry) {
                        printk(TPACPI_ERR "unable to create proc entry %s\n",
                               ibm->name);
                        ret = -ENODEV;
                        goto err_out;
                }
-               entry->data = ibm;
-               entry->read_proc = &dispatch_procfs_read;
-               if (ibm->write)
-                       entry->write_proc = &dispatch_procfs_write;
                ibm->flags.proc_created = 1;
        }
 
@@ -8762,6 +8767,7 @@ MODULE_PARM_DESC(hotkey_report_mode,
                 "used for backwards compatibility with userspace, "
                 "see documentation");
 
+#ifdef CONFIG_THINKPAD_ACPI_ALSA_SUPPORT
 module_param_named(volume_mode, volume_mode, uint, 0444);
 MODULE_PARM_DESC(volume_mode,
                 "Selects volume control strategy: "
@@ -8784,6 +8790,7 @@ module_param_named(id, alsa_id, charp, 0444);
 MODULE_PARM_DESC(id, "ALSA id for the ACPI EC Mixer");
 module_param_named(enable, alsa_enable, bool, 0444);
 MODULE_PARM_DESC(enable, "Enable the ALSA interface for the ACPI EC Mixer");
+#endif /* CONFIG_THINKPAD_ACPI_ALSA_SUPPORT */
 
 #define TPACPI_PARAM(feature) \
        module_param_call(feature, set_ibm_param, NULL, NULL, 0); \