[PATCH] fix semaphore handling in __unregister_chrdev_region
[linux/fpc-iii.git] / sound / oss / dmasound / tas_common.c
blobd36a1fe2fcf34a93f8d8a9bbe2677a683a449ccb
1 #include <linux/module.h>
2 #include <linux/slab.h>
3 #include <linux/proc_fs.h>
4 #include <linux/ioport.h>
5 #include <linux/sysctl.h>
6 #include <linux/types.h>
7 #include <linux/i2c.h>
8 #include <linux/init.h>
9 #include <linux/soundcard.h>
10 #include <asm/uaccess.h>
11 #include <asm/errno.h>
12 #include <asm/io.h>
13 #include <asm/prom.h>
15 #include "tas_common.h"
17 #define CALL0(proc) \
18 do { \
19 struct tas_data_t *self; \
20 if (!tas_client || driver_hooks == NULL) \
21 return -1; \
22 self = dev_get_drvdata(&tas_client->dev); \
23 if (driver_hooks->proc) \
24 return driver_hooks->proc(self); \
25 else \
26 return -EINVAL; \
27 } while (0)
29 #define CALL(proc,arg...) \
30 do { \
31 struct tas_data_t *self; \
32 if (!tas_client || driver_hooks == NULL) \
33 return -1; \
34 self = dev_get_drvdata(&tas_client->dev); \
35 if (driver_hooks->proc) \
36 return driver_hooks->proc(self, ## arg); \
37 else \
38 return -EINVAL; \
39 } while (0)
42 static u8 tas_i2c_address = 0x34;
43 static struct i2c_client *tas_client;
44 static struct device_node* tas_node;
46 static int tas_attach_adapter(struct i2c_adapter *);
47 static int tas_detach_client(struct i2c_client *);
49 struct i2c_driver tas_driver = {
50 .owner = THIS_MODULE,
51 .name = "tas",
52 .flags = I2C_DF_NOTIFY,
53 .attach_adapter = tas_attach_adapter,
54 .detach_client = tas_detach_client,
57 struct tas_driver_hooks_t *driver_hooks;
59 int
60 tas_register_driver(struct tas_driver_hooks_t *hooks)
62 driver_hooks = hooks;
63 return 0;
66 int
67 tas_get_mixer_level(int mixer, uint *level)
69 CALL(get_mixer_level,mixer,level);
72 int
73 tas_set_mixer_level(int mixer,uint level)
75 CALL(set_mixer_level,mixer,level);
78 int
79 tas_enter_sleep(void)
81 CALL0(enter_sleep);
84 int
85 tas_leave_sleep(void)
87 CALL0(leave_sleep);
90 int
91 tas_supported_mixers(void)
93 CALL0(supported_mixers);
96 int
97 tas_mixer_is_stereo(int mixer)
99 CALL(mixer_is_stereo,mixer);
103 tas_stereo_mixers(void)
105 CALL0(stereo_mixers);
109 tas_output_device_change(int device_id,int layout_id,int speaker_id)
111 CALL(output_device_change,device_id,layout_id,speaker_id);
115 tas_device_ioctl(u_int cmd, u_long arg)
117 CALL(device_ioctl,cmd,arg);
121 tas_post_init(void)
123 CALL0(post_init);
126 static int
127 tas_detect_client(struct i2c_adapter *adapter, int address)
129 static const char *client_name = "tas Digital Equalizer";
130 struct i2c_client *new_client;
131 int rc = -ENODEV;
133 if (!driver_hooks) {
134 printk(KERN_ERR "tas_detect_client called with no hooks !\n");
135 return -ENODEV;
138 new_client = kmalloc(sizeof(*new_client), GFP_KERNEL);
139 if (!new_client)
140 return -ENOMEM;
141 memset(new_client, 0, sizeof(*new_client));
143 new_client->addr = address;
144 new_client->adapter = adapter;
145 new_client->driver = &tas_driver;
146 strlcpy(new_client->name, client_name, DEVICE_NAME_SIZE);
148 if (driver_hooks->init(new_client))
149 goto bail;
151 /* Tell the i2c layer a new client has arrived */
152 if (i2c_attach_client(new_client)) {
153 driver_hooks->uninit(dev_get_drvdata(&new_client->dev));
154 goto bail;
157 tas_client = new_client;
158 return 0;
159 bail:
160 tas_client = NULL;
161 kfree(new_client);
162 return rc;
165 static int
166 tas_attach_adapter(struct i2c_adapter *adapter)
168 if (!strncmp(adapter->name, "mac-io", 6))
169 return tas_detect_client(adapter, tas_i2c_address);
170 return 0;
173 static int
174 tas_detach_client(struct i2c_client *client)
176 if (client == tas_client) {
177 driver_hooks->uninit(dev_get_drvdata(&client->dev));
179 i2c_detach_client(client);
180 kfree(client);
182 return 0;
185 void
186 tas_cleanup(void)
188 i2c_del_driver(&tas_driver);
191 int __init
192 tas_init(int driver_id, const char *driver_name)
194 u32* paddr;
196 printk(KERN_INFO "tas driver [%s])\n", driver_name);
198 #ifndef CONFIG_I2C_KEYWEST
199 request_module("i2c-keywest");
200 #endif
201 tas_node = find_devices("deq");
202 if (tas_node == NULL)
203 return -ENODEV;
204 paddr = (u32 *)get_property(tas_node, "i2c-address", NULL);
205 if (paddr) {
206 tas_i2c_address = (*paddr) >> 1;
207 printk(KERN_INFO "using i2c address: 0x%x from device-tree\n",
208 tas_i2c_address);
209 } else
210 printk(KERN_INFO "using i2c address: 0x%x (default)\n",
211 tas_i2c_address);
213 return i2c_add_driver(&tas_driver);