tegra: Make tegra_vi01_device accessible
[linux-2.6.git] / drivers / switch / switch_class.c
1 /*
2  *  drivers/switch/switch_class.c
3  *
4  * Copyright (C) 2008 Google, Inc.
5  * Copyright (C) 2012 - NVIDIA, Inc.
6  * Author: Mike Lockwood <lockwood@android.com>
7  *
8  * This software is licensed under the terms of the GNU General Public
9  * License version 2, as published by the Free Software Foundation, and
10  * may be copied, distributed, and modified under those terms.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17 */
18
19 #include <linux/module.h>
20 #include <linux/types.h>
21 #include <linux/init.h>
22 #include <linux/device.h>
23 #include <linux/fs.h>
24 #include <linux/err.h>
25 #include <linux/switch.h>
26
27 struct class *switch_class;
28 static atomic_t device_count;
29
30 static ssize_t state_show(struct device *dev, struct device_attribute *attr,
31                 char *buf)
32 {
33         struct switch_dev *sdev = (struct switch_dev *)
34                 dev_get_drvdata(dev);
35
36         if (sdev->print_state) {
37                 int ret = sdev->print_state(sdev, buf);
38                 if (ret >= 0)
39                         return ret;
40         }
41         return sprintf(buf, "%d\n", sdev->state);
42 }
43
44 static ssize_t name_show(struct device *dev, struct device_attribute *attr,
45                 char *buf)
46 {
47         struct switch_dev *sdev = (struct switch_dev *)
48                 dev_get_drvdata(dev);
49
50         if (sdev->print_name) {
51                 int ret = sdev->print_name(sdev, buf);
52                 if (ret >= 0)
53                         return ret;
54         }
55         return sprintf(buf, "%s\n", sdev->name);
56 }
57
58 static DEVICE_ATTR(state, S_IRUGO | S_IWUSR, state_show, NULL);
59 static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, name_show, NULL);
60
61 void switch_set_state(struct switch_dev *sdev, int state)
62 {
63         char name_buf[120];
64         char state_buf[120];
65         char *prop_buf;
66         char *envp[3];
67         int env_offset = 0;
68         int length;
69
70         if (sdev->state != state) {
71                 sdev->state = state;
72
73                 prop_buf = (char *)get_zeroed_page(GFP_KERNEL);
74                 if (prop_buf) {
75                         length = name_show(sdev->dev, NULL, prop_buf);
76                         if (length > 0) {
77                                 if (prop_buf[length - 1] == '\n')
78                                         prop_buf[length - 1] = 0;
79                                 snprintf(name_buf, sizeof(name_buf),
80                                         "SWITCH_NAME=%s", prop_buf);
81                                 envp[env_offset++] = name_buf;
82                         }
83                         length = state_show(sdev->dev, NULL, prop_buf);
84                         if (length > 0) {
85                                 if (prop_buf[length - 1] == '\n')
86                                         prop_buf[length - 1] = 0;
87                                 snprintf(state_buf, sizeof(state_buf),
88                                         "SWITCH_STATE=%s", prop_buf);
89                                 envp[env_offset++] = state_buf;
90                         }
91                         envp[env_offset] = NULL;
92                         kobject_uevent_env(&sdev->dev->kobj, KOBJ_CHANGE, envp);
93                         free_page((unsigned long)prop_buf);
94                 } else {
95                         printk(KERN_ERR "out of memory in switch_set_state\n");
96                         kobject_uevent(&sdev->dev->kobj, KOBJ_CHANGE);
97                 }
98         }
99 }
100 EXPORT_SYMBOL_GPL(switch_set_state);
101
102 static int create_switch_class(void)
103 {
104         if (!switch_class) {
105                 switch_class = class_create(THIS_MODULE, "switch");
106                 if (IS_ERR(switch_class))
107                         return PTR_ERR(switch_class);
108                 atomic_set(&device_count, 0);
109         }
110
111         return 0;
112 }
113
114 int switch_dev_register(struct switch_dev *sdev)
115 {
116         int ret;
117
118         if (!switch_class) {
119                 ret = create_switch_class();
120                 if (ret < 0)
121                         return ret;
122         }
123
124         sdev->index = atomic_inc_return(&device_count);
125         sdev->dev = device_create(switch_class, NULL,
126                 MKDEV(0, sdev->index), NULL, sdev->name);
127         if (IS_ERR(sdev->dev))
128                 return PTR_ERR(sdev->dev);
129
130         ret = device_create_file(sdev->dev, &dev_attr_state);
131         if (ret < 0)
132                 goto err_create_file_1;
133         ret = device_create_file(sdev->dev, &dev_attr_name);
134         if (ret < 0)
135                 goto err_create_file_2;
136
137         dev_set_drvdata(sdev->dev, sdev);
138         sdev->state = 0;
139         return 0;
140
141 err_create_file_2:
142         device_remove_file(sdev->dev, &dev_attr_state);
143 err_create_file_1:
144         device_destroy(switch_class, MKDEV(0, sdev->index));
145         printk(KERN_ERR "switch: Failed to register driver %s\n", sdev->name);
146
147         return ret;
148 }
149 EXPORT_SYMBOL_GPL(switch_dev_register);
150
151 void switch_dev_unregister(struct switch_dev *sdev)
152 {
153         device_remove_file(sdev->dev, &dev_attr_name);
154         device_remove_file(sdev->dev, &dev_attr_state);
155         dev_set_drvdata(sdev->dev, NULL);
156         device_destroy(switch_class, MKDEV(0, sdev->index));
157 }
158 EXPORT_SYMBOL_GPL(switch_dev_unregister);
159
160 static int __init switch_class_init(void)
161 {
162         return create_switch_class();
163 }
164
165 static void __exit switch_class_exit(void)
166 {
167         class_destroy(switch_class);
168 }
169
170 module_init(switch_class_init);
171 module_exit(switch_class_exit);
172
173 MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>");
174 MODULE_DESCRIPTION("Switch class driver");
175 MODULE_LICENSE("GPL");