1 #include <linux/cdev.h>
2 #include <linux/device.h>
4 #include <linux/list.h>
5 #include <linux/kernel.h>
6 #include <linux/module.h>
7 #include <linux/slab.h>
9 #include <linux/tapi/tapi.h>
10 #include <linux/tapi/tapi-ioctl.h>
12 /* FIXME Does it acutally make sense to allow more then one application at a
13 * time to open the control device? For example calling sync from one app will
14 * also sync all others. */
16 struct tapi_control_file {
17 struct tapi_device *tdev;
18 struct list_head links;
21 static struct tapi_endpoint *tapi_lookup_endpoint(struct tapi_device *tdev,
24 struct tapi_stream *stream;
26 if (ep_id < tdev->num_ports)
27 return &tdev->ports[ep_id].ep;
29 list_for_each_entry(stream, &tdev->streams, head) {
30 if (stream->ep.id == ep_id)
34 return ERR_PTR(-ENOENT);
37 static inline struct tapi_device *inode_to_tdev(struct inode *inode)
39 return container_of(inode->i_cdev, struct tapi_char_device, cdev)->tdev;
42 static int tapi_control_open(struct inode *inode, struct file *file)
45 struct tapi_device *tdev = inode_to_tdev(inode);
46 struct tapi_control_file *tctrl;
48 get_device(&tdev->dev);
50 tctrl = kzalloc(sizeof(*tctrl), GFP_KERNEL);
56 INIT_LIST_HEAD(&tctrl->links);
59 file->private_data = tctrl;
64 put_device(&tdev->dev);
69 static int tapi_control_release(struct inode *inode, struct file *file)
71 struct tapi_control_file *tctrl = file->private_data;
72 struct tapi_link *link;
75 list_for_each_entry(link, &tctrl->links, head)
76 tapi_link_free(tctrl->tdev, link);
78 put_device(&tctrl->tdev->dev);
84 static long tapi_control_ioctl_link_alloc(struct tapi_control_file *tctrl,
87 struct tapi_link *link;
88 struct tapi_endpoint *ep1, *ep2;
90 ep1 = tapi_lookup_endpoint(tctrl->tdev, arg >> 16);
91 ep2 = tapi_lookup_endpoint(tctrl->tdev, arg & 0xffff);
93 link = tapi_link_alloc(tctrl->tdev, ep1, ep2);
97 list_add_tail(&link->head, &tctrl->links);
102 struct tapi_link *tapi_control_lookup_link(struct tapi_control_file *tctrl,
105 struct tapi_link *link;
107 list_for_each_entry(link, &tctrl->links, head) {
115 static long tapi_control_ioctl_link_free(struct tapi_control_file *tctrl,
118 struct tapi_link *link = tapi_control_lookup_link(tctrl, arg);
122 tapi_link_free(tctrl->tdev, link);
123 list_del(&link->head);
128 static long tapi_control_ioctl_link_enable(struct tapi_control_file *tctrl,
131 struct tapi_link *link = tapi_control_lookup_link(tctrl, arg);
135 return tapi_link_enable(tctrl->tdev, link);
138 static long tapi_control_ioctl_link_disable(struct tapi_control_file *tctrl,
141 struct tapi_link *link = tapi_control_lookup_link(tctrl, arg);
145 return tapi_link_disable(tctrl->tdev, link);
148 static long tapi_control_ioctl_sync(struct tapi_control_file *tctrl)
150 return tapi_sync(tctrl->tdev);
153 static long tapi_control_ioctl(struct file *file, unsigned int cmd,
157 struct tapi_control_file *tctrl = file->private_data;
160 case TAPI_CONTROL_IOCTL_LINK_ALLOC:
161 ret = tapi_control_ioctl_link_alloc(tctrl, arg);
163 case TAPI_CONTROL_IOCTL_LINK_FREE:
164 ret = tapi_control_ioctl_link_free(tctrl, arg);
166 case TAPI_CONTROL_IOCTL_LINK_ENABLE:
167 ret = tapi_control_ioctl_link_enable(tctrl, arg);
169 case TAPI_CONTROL_IOCTL_LINK_DISABLE:
170 ret = tapi_control_ioctl_link_disable(tctrl, arg);
172 case TAPI_CONTROL_IOCTL_SYNC:
173 ret = tapi_control_ioctl_sync(tctrl);
182 static const struct file_operations tapi_control_file_ops = {
183 .owner = THIS_MODULE,
184 .open = tapi_control_open,
185 .release = tapi_control_release,
186 .unlocked_ioctl = tapi_control_ioctl,
189 int tapi_register_control_device(struct tapi_device* tdev)
191 dev_set_name(&tdev->control_dev.dev, "tapi%uC", tdev->id);
192 return tapi_char_device_register(tdev, &tdev->control_dev, &tapi_control_file_ops);