fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / char / snsc.c
index 9d027ec..52753e7 100644 (file)
@@ -5,7 +5,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2004 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2004, 2006 Silicon Graphics, Inc. All rights reserved.
  */
 
 /*
@@ -34,7 +34,7 @@
 #define SCDRV_TIMEOUT  1000
 
 static irqreturn_t
-scdrv_interrupt(int irq, void *subch_data, struct pt_regs *regs)
+scdrv_interrupt(int irq, void *subch_data)
 {
        struct subch_data_s *sd = subch_data;
        unsigned long flags;
@@ -77,7 +77,7 @@ scdrv_open(struct inode *inode, struct file *file)
        scd = container_of(inode->i_cdev, struct sysctl_data_s, scd_cdev);
 
        /* allocate memory for subchannel data */
-       sd = kmalloc(sizeof (struct subch_data_s), GFP_KERNEL);
+       sd = kzalloc(sizeof (struct subch_data_s), GFP_KERNEL);
        if (sd == NULL) {
                printk("%s: couldn't allocate subchannel data\n",
                       __FUNCTION__);
@@ -85,7 +85,6 @@ scdrv_open(struct inode *inode, struct file *file)
        }
 
        /* initialize subch_data_s fields */
-       memset(sd, 0, sizeof (struct subch_data_s));
        sd->sd_nasid = scd->scd_nasid;
        sd->sd_subch = ia64_sn_irtr_open(scd->scd_nasid);
 
@@ -106,7 +105,7 @@ scdrv_open(struct inode *inode, struct file *file)
 
        /* hook this subchannel up to the system controller interrupt */
        rv = request_irq(SGI_UART_VECTOR, scdrv_interrupt,
-                        SA_SHIRQ | SA_INTERRUPT,
+                        IRQF_SHARED | IRQF_DISABLED,
                         SYSCTL_BASENAME, sd);
        if (rv) {
                ia64_sn_irtr_close(sd->sd_nasid, sd->sd_subch);
@@ -192,8 +191,8 @@ scdrv_read(struct file *file, char __user *buf, size_t count, loff_t *f_pos)
                }
 
                len = CHUNKSIZE;
-               add_wait_queue(&sd->sd_rq, &wait);
                set_current_state(TASK_INTERRUPTIBLE);
+               add_wait_queue(&sd->sd_rq, &wait);
                spin_unlock_irqrestore(&sd->sd_rlock, flags);
 
                schedule_timeout(SCDRV_TIMEOUT);
@@ -288,8 +287,8 @@ scdrv_write(struct file *file, const char __user *buf,
                        return -EAGAIN;
                }
 
-               add_wait_queue(&sd->sd_wq, &wait);
                set_current_state(TASK_INTERRUPTIBLE);
+               add_wait_queue(&sd->sd_wq, &wait);
                spin_unlock_irqrestore(&sd->sd_wlock, flags);
 
                schedule_timeout(SCDRV_TIMEOUT);
@@ -348,7 +347,7 @@ scdrv_poll(struct file *file, struct poll_table_struct *wait)
        return mask;
 }
 
-static struct file_operations scdrv_fops = {
+static const struct file_operations scdrv_fops = {
        .owner =        THIS_MODULE,
        .read =         scdrv_read,
        .write =        scdrv_write,
@@ -357,6 +356,8 @@ static struct file_operations scdrv_fops = {
        .release =      scdrv_release,
 };
 
+static struct class *snsc_class;
+
 /*
  * scdrv_init
  *
@@ -372,27 +373,33 @@ scdrv_init(void)
        char *devnamep;
        struct sysctl_data_s *scd;
        void *salbuf;
-       struct class_simple *snsc_class;
        dev_t first_dev, dev;
+       nasid_t event_nasid;
 
-       if (alloc_chrdev_region(&first_dev, 0, numionodes,
+       if (!ia64_platform_is("sn2"))
+               return -ENODEV;
+
+       event_nasid = ia64_sn_get_console_nasid();
+
+       if (alloc_chrdev_region(&first_dev, 0, num_cnodes,
                                SYSCTL_BASENAME) < 0) {
                printk("%s: failed to register SN system controller device\n",
                       __FUNCTION__);
                return -ENODEV;
        }
-       snsc_class = class_simple_create(THIS_MODULE, SYSCTL_BASENAME);
+       snsc_class = class_create(THIS_MODULE, SYSCTL_BASENAME);
 
-       for (cnode = 0; cnode < numionodes; cnode++) {
+       for (cnode = 0; cnode < num_cnodes; cnode++) {
                        geoid = cnodeid_get_geoid(cnode);
                        devnamep = devname;
                        format_module_id(devnamep, geo_module(geoid),
                                         MODULE_FORMAT_BRIEF);
                        devnamep = devname + strlen(devname);
-                       sprintf(devnamep, "#%d", geo_slab(geoid));
+                       sprintf(devnamep, "^%d#%d", geo_slot(geoid),
+                               geo_slab(geoid));
 
                        /* allocate sysctl device data */
-                       scd = kmalloc(sizeof (struct sysctl_data_s),
+                       scd = kzalloc(sizeof (struct sysctl_data_s),
                                      GFP_KERNEL);
                        if (!scd) {
                                printk("%s: failed to allocate device info"
@@ -400,7 +407,6 @@ scdrv_init(void)
                                       SYSCTL_BASENAME, devname);
                                continue;
                        }
-                       memset(scd, 0, sizeof (struct sysctl_data_s));
 
                        /* initialize sysctl device data fields */
                        scd->scd_nasid = cnodeid_to_nasid(cnode);
@@ -435,12 +441,19 @@ scdrv_init(void)
                                continue;
                        }
 
-                       class_simple_device_add(snsc_class, dev, NULL,
+                       class_device_create(snsc_class, NULL, dev, NULL,
                                                "%s", devname);
 
                        ia64_sn_irtr_intr_enable(scd->scd_nasid,
                                                 0 /*ignored */ ,
                                                 SAL_IROUTER_INTR_RECV);
+
+                        /* on the console nasid, prepare to receive
+                         * system controller environmental events
+                         */
+                        if(scd->scd_nasid == event_nasid) {
+                                scdrv_event_init(scd);
+                        }
        }
        return 0;
 }