diff options
author | Peter Hurley <peter@hurleysoftware.com> | 2013-01-28 22:34:38 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-01-29 23:28:45 -0500 |
commit | fa1da242c3d24801ae946f4664406f679865388f (patch) | |
tree | 7d5e014ce72e7320a64345c09b00c90bc139f43a | |
parent | a3d9ad474ef391166a48128bea753f455e9a7d69 (diff) |
staging/fwserial: Create loop device the 'tty' way
Register a second tty driver to create loopback devices for
each firewire node. Note that the loopback devices are numbered
from 0; the tty->index is transformed when used to index the
port table.
Remove the hack that previously enabled this.
Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | drivers/staging/fwserial/TODO | 13 | ||||
-rw-r--r-- | drivers/staging/fwserial/fwserial.c | 176 |
2 files changed, 93 insertions, 96 deletions
diff --git a/drivers/staging/fwserial/TODO b/drivers/staging/fwserial/TODO index dc61d9773c6f..382a7959407c 100644 --- a/drivers/staging/fwserial/TODO +++ b/drivers/staging/fwserial/TODO | |||
@@ -12,16 +12,3 @@ TODOs prior to this driver moving out of staging | |||
12 | 1. This driver uses the same unregistered vendor id that the firewire core does | 12 | 1. This driver uses the same unregistered vendor id that the firewire core does |
13 | (0xd00d1e). Perhaps this could be exposed as a define in | 13 | (0xd00d1e). Perhaps this could be exposed as a define in |
14 | firewire.h? | 14 | firewire.h? |
15 | |||
16 | -- Issues with TTY core -- | ||
17 | 1. Hack for alternate device name scheme | ||
18 | - because udev no longer allows device renaming, devices should have | ||
19 | their proper names on creation. This is an issue for creating the | ||
20 | fwloop<n> device with the fwtty<n> devices because although duplicating | ||
21 | roughly the same operations as tty_port_register_device() isn't difficult, | ||
22 | access to the tty_class & tty_fops is restricted in scope. | ||
23 | |||
24 | This is currently being worked around in create_loop_device() by | ||
25 | extracting the tty_class ptr and tty_fops ptr from the previously created | ||
26 | tty devices. Perhaps an add'l api can be added -- eg., | ||
27 | tty_{port_}register_named_device(). | ||
diff --git a/drivers/staging/fwserial/fwserial.c b/drivers/staging/fwserial/fwserial.c index a9e814e5cbdd..3f2d26e7a008 100644 --- a/drivers/staging/fwserial/fwserial.c +++ b/drivers/staging/fwserial/fwserial.c | |||
@@ -72,6 +72,9 @@ static DEFINE_MUTEX(port_table_lock); | |||
72 | static bool port_table_corrupt; | 72 | static bool port_table_corrupt; |
73 | #define FWTTY_INVALID_INDEX MAX_TOTAL_PORTS | 73 | #define FWTTY_INVALID_INDEX MAX_TOTAL_PORTS |
74 | 74 | ||
75 | #define loop_idx(port) (((port)->index) / num_ports) | ||
76 | #define table_idx(loop) ((loop) * num_ports + num_ttys) | ||
77 | |||
75 | /* total # of tty ports created per fw_card */ | 78 | /* total # of tty ports created per fw_card */ |
76 | static int num_ports; | 79 | static int num_ports; |
77 | 80 | ||
@@ -79,6 +82,7 @@ static int num_ports; | |||
79 | static struct kmem_cache *fwtty_txn_cache; | 82 | static struct kmem_cache *fwtty_txn_cache; |
80 | 83 | ||
81 | struct tty_driver *fwtty_driver; | 84 | struct tty_driver *fwtty_driver; |
85 | static struct tty_driver *fwloop_driver; | ||
82 | 86 | ||
83 | struct fwtty_transaction; | 87 | struct fwtty_transaction; |
84 | typedef void (*fwtty_transaction_cb)(struct fw_card *card, int rcode, | 88 | typedef void (*fwtty_transaction_cb)(struct fw_card *card, int rcode, |
@@ -1165,6 +1169,19 @@ static int fwtty_install(struct tty_driver *driver, struct tty_struct *tty) | |||
1165 | return err; | 1169 | return err; |
1166 | } | 1170 | } |
1167 | 1171 | ||
1172 | static int fwloop_install(struct tty_driver *driver, struct tty_struct *tty) | ||
1173 | { | ||
1174 | struct fwtty_port *port = fwtty_port_get(table_idx(tty->index)); | ||
1175 | int err; | ||
1176 | |||
1177 | err = tty_standard_install(driver, tty); | ||
1178 | if (!err) | ||
1179 | tty->driver_data = port; | ||
1180 | else | ||
1181 | fwtty_port_put(port); | ||
1182 | return err; | ||
1183 | } | ||
1184 | |||
1168 | static int fwtty_write(struct tty_struct *tty, const unsigned char *buf, int c) | 1185 | static int fwtty_write(struct tty_struct *tty, const unsigned char *buf, int c) |
1169 | { | 1186 | { |
1170 | struct fwtty_port *port = tty->driver_data; | 1187 | struct fwtty_port *port = tty->driver_data; |
@@ -1601,6 +1618,26 @@ static const struct tty_operations fwtty_ops = { | |||
1601 | .proc_fops = &fwtty_proc_fops, | 1618 | .proc_fops = &fwtty_proc_fops, |
1602 | }; | 1619 | }; |
1603 | 1620 | ||
1621 | static const struct tty_operations fwloop_ops = { | ||
1622 | .open = fwtty_open, | ||
1623 | .close = fwtty_close, | ||
1624 | .hangup = fwtty_hangup, | ||
1625 | .cleanup = fwtty_cleanup, | ||
1626 | .install = fwloop_install, | ||
1627 | .write = fwtty_write, | ||
1628 | .write_room = fwtty_write_room, | ||
1629 | .chars_in_buffer = fwtty_chars_in_buffer, | ||
1630 | .send_xchar = fwtty_send_xchar, | ||
1631 | .throttle = fwtty_throttle, | ||
1632 | .unthrottle = fwtty_unthrottle, | ||
1633 | .ioctl = fwtty_ioctl, | ||
1634 | .set_termios = fwtty_set_termios, | ||
1635 | .break_ctl = fwtty_break_ctl, | ||
1636 | .tiocmget = fwtty_tiocmget, | ||
1637 | .tiocmset = fwtty_tiocmset, | ||
1638 | .get_icount = fwtty_get_icount, | ||
1639 | }; | ||
1640 | |||
1604 | static inline int mgmt_pkt_expected_len(__be16 code) | 1641 | static inline int mgmt_pkt_expected_len(__be16 code) |
1605 | { | 1642 | { |
1606 | static const struct fwserial_mgmt_pkt pkt; | 1643 | static const struct fwserial_mgmt_pkt pkt; |
@@ -1897,7 +1934,8 @@ free_pkt: | |||
1897 | * The port reference is put by fwtty_cleanup (if a reference was | 1934 | * The port reference is put by fwtty_cleanup (if a reference was |
1898 | * ever taken). | 1935 | * ever taken). |
1899 | */ | 1936 | */ |
1900 | static void fwserial_close_port(struct fwtty_port *port) | 1937 | static void fwserial_close_port(struct tty_driver *driver, |
1938 | struct fwtty_port *port) | ||
1901 | { | 1939 | { |
1902 | struct tty_struct *tty; | 1940 | struct tty_struct *tty; |
1903 | 1941 | ||
@@ -1909,7 +1947,10 @@ static void fwserial_close_port(struct fwtty_port *port) | |||
1909 | } | 1947 | } |
1910 | mutex_unlock(&port->port.mutex); | 1948 | mutex_unlock(&port->port.mutex); |
1911 | 1949 | ||
1912 | tty_unregister_device(fwtty_driver, port->index); | 1950 | if (driver == fwloop_driver) |
1951 | tty_unregister_device(driver, loop_idx(port)); | ||
1952 | else | ||
1953 | tty_unregister_device(driver, port->index); | ||
1913 | } | 1954 | } |
1914 | 1955 | ||
1915 | /** | 1956 | /** |
@@ -2167,78 +2208,6 @@ static void fwserial_remove_peer(struct fwtty_peer *peer) | |||
2167 | } | 2208 | } |
2168 | 2209 | ||
2169 | /** | 2210 | /** |
2170 | * create_loop_device - create a loopback tty device | ||
2171 | * @tty_driver: tty_driver to own loopback device | ||
2172 | * @prototype: ptr to already-assigned 'prototype' tty port | ||
2173 | * @index: index to associate this device with the tty port | ||
2174 | * @parent: device to child to | ||
2175 | * | ||
2176 | * HACK - this is basically tty_port_register_device() with an | ||
2177 | * alternate naming scheme. Suggest tty_port_register_named_device() | ||
2178 | * helper api. | ||
2179 | * | ||
2180 | * Creates a loopback tty device named 'fwloop<n>' which is attached to | ||
2181 | * the local unit in fwserial_add_peer(). Note that <n> in the device | ||
2182 | * name advances in increments of port allocation blocks, ie., for port | ||
2183 | * indices 0..3, the device name will be 'fwloop0'; for 4..7, 'fwloop1', | ||
2184 | * and so on. | ||
2185 | * | ||
2186 | * Only one loopback device should be created per fw_card. | ||
2187 | */ | ||
2188 | static void release_loop_device(struct device *dev) | ||
2189 | { | ||
2190 | kfree(dev); | ||
2191 | } | ||
2192 | |||
2193 | static struct device *create_loop_device(struct tty_driver *driver, | ||
2194 | struct fwtty_port *prototype, | ||
2195 | struct fwtty_port *port, | ||
2196 | struct device *parent) | ||
2197 | { | ||
2198 | char name[64]; | ||
2199 | int index = port->index; | ||
2200 | dev_t devt = MKDEV(driver->major, driver->minor_start) + index; | ||
2201 | struct device *dev = NULL; | ||
2202 | int err; | ||
2203 | |||
2204 | if (index >= fwtty_driver->num) | ||
2205 | return ERR_PTR(-EINVAL); | ||
2206 | |||
2207 | snprintf(name, 64, "%s%d", loop_dev_name, index / num_ports); | ||
2208 | |||
2209 | tty_port_link_device(&port->port, driver, index); | ||
2210 | |||
2211 | cdev_init(&driver->cdevs[index], driver->cdevs[prototype->index].ops); | ||
2212 | driver->cdevs[index].owner = driver->owner; | ||
2213 | err = cdev_add(&driver->cdevs[index], devt, 1); | ||
2214 | if (err) | ||
2215 | return ERR_PTR(err); | ||
2216 | |||
2217 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); | ||
2218 | if (!dev) { | ||
2219 | cdev_del(&driver->cdevs[index]); | ||
2220 | return ERR_PTR(-ENOMEM); | ||
2221 | } | ||
2222 | |||
2223 | dev->devt = devt; | ||
2224 | dev->class = prototype->device->class; | ||
2225 | dev->parent = parent; | ||
2226 | dev->release = release_loop_device; | ||
2227 | dev_set_name(dev, "%s", name); | ||
2228 | dev->groups = NULL; | ||
2229 | dev_set_drvdata(dev, NULL); | ||
2230 | |||
2231 | err = device_register(dev); | ||
2232 | if (err) { | ||
2233 | put_device(dev); | ||
2234 | cdev_del(&driver->cdevs[index]); | ||
2235 | return ERR_PTR(err); | ||
2236 | } | ||
2237 | |||
2238 | return dev; | ||
2239 | } | ||
2240 | |||
2241 | /** | ||
2242 | * fwserial_create - init everything to create TTYs for a specific fw_card | 2211 | * fwserial_create - init everything to create TTYs for a specific fw_card |
2243 | * @unit: fw_unit for first 'serial' unit device probed for this fw_card | 2212 | * @unit: fw_unit for first 'serial' unit device probed for this fw_card |
2244 | * | 2213 | * |
@@ -2336,17 +2305,17 @@ static int fwserial_create(struct fw_unit *unit) | |||
2336 | if (create_loop_dev) { | 2305 | if (create_loop_dev) { |
2337 | struct device *loop_dev; | 2306 | struct device *loop_dev; |
2338 | 2307 | ||
2339 | loop_dev = create_loop_device(fwtty_driver, | 2308 | loop_dev = tty_port_register_device(&serial->ports[j]->port, |
2340 | serial->ports[0], | 2309 | fwloop_driver, |
2341 | serial->ports[num_ttys], | 2310 | loop_idx(serial->ports[j]), |
2342 | card->device); | 2311 | card->device); |
2343 | if (IS_ERR(loop_dev)) { | 2312 | if (IS_ERR(loop_dev)) { |
2344 | err = PTR_ERR(loop_dev); | 2313 | err = PTR_ERR(loop_dev); |
2345 | fwtty_err(&unit, "create loop device failed (%d)", err); | 2314 | fwtty_err(&unit, "create loop device failed (%d)", err); |
2346 | goto unregister_ttys; | 2315 | goto unregister_ttys; |
2347 | } | 2316 | } |
2348 | serial->ports[num_ttys]->device = loop_dev; | 2317 | serial->ports[j]->device = loop_dev; |
2349 | serial->ports[num_ttys]->loopback = true; | 2318 | serial->ports[j]->loopback = true; |
2350 | } | 2319 | } |
2351 | 2320 | ||
2352 | list_add_rcu(&serial->list, &fwserial_list); | 2321 | list_add_rcu(&serial->list, &fwserial_list); |
@@ -2362,6 +2331,8 @@ static int fwserial_create(struct fw_unit *unit) | |||
2362 | 2331 | ||
2363 | /* fall-through to error processing */ | 2332 | /* fall-through to error processing */ |
2364 | list_del_rcu(&serial->list); | 2333 | list_del_rcu(&serial->list); |
2334 | if (create_loop_dev) | ||
2335 | tty_unregister_device(fwloop_driver, loop_idx(serial->ports[j])); | ||
2365 | unregister_ttys: | 2336 | unregister_ttys: |
2366 | for (--j; j >= 0; --j) | 2337 | for (--j; j >= 0; --j) |
2367 | tty_unregister_device(fwtty_driver, serial->ports[j]->index); | 2338 | tty_unregister_device(fwtty_driver, serial->ports[j]->index); |
@@ -2450,8 +2421,10 @@ static int fwserial_remove(struct device *dev) | |||
2450 | /* unlink from the fwserial_list here */ | 2421 | /* unlink from the fwserial_list here */ |
2451 | list_del_rcu(&serial->list); | 2422 | list_del_rcu(&serial->list); |
2452 | 2423 | ||
2453 | for (i = 0; i < num_ports; ++i) | 2424 | for (i = 0; i < num_ttys; ++i) |
2454 | fwserial_close_port(serial->ports[i]); | 2425 | fwserial_close_port(fwtty_driver, serial->ports[i]); |
2426 | if (create_loop_dev) | ||
2427 | fwserial_close_port(fwloop_driver, serial->ports[i]); | ||
2455 | kref_put(&serial->kref, fwserial_destroy); | 2428 | kref_put(&serial->kref, fwserial_destroy); |
2456 | } | 2429 | } |
2457 | mutex_unlock(&fwserial_list_mutex); | 2430 | mutex_unlock(&fwserial_list_mutex); |
@@ -2872,12 +2845,39 @@ static int __init fwserial_init(void) | |||
2872 | goto put_tty; | 2845 | goto put_tty; |
2873 | } | 2846 | } |
2874 | 2847 | ||
2848 | if (create_loop_dev) { | ||
2849 | fwloop_driver = alloc_tty_driver(MAX_TOTAL_PORTS / num_ports); | ||
2850 | if (!fwloop_driver) { | ||
2851 | err = -ENOMEM; | ||
2852 | goto unregister_driver; | ||
2853 | } | ||
2854 | |||
2855 | fwloop_driver->driver_name = KBUILD_MODNAME "_loop"; | ||
2856 | fwloop_driver->name = loop_dev_name; | ||
2857 | fwloop_driver->major = 0; | ||
2858 | fwloop_driver->minor_start = 0; | ||
2859 | fwloop_driver->type = TTY_DRIVER_TYPE_SERIAL; | ||
2860 | fwloop_driver->subtype = SERIAL_TYPE_NORMAL; | ||
2861 | fwloop_driver->flags = TTY_DRIVER_REAL_RAW | | ||
2862 | TTY_DRIVER_DYNAMIC_DEV; | ||
2863 | |||
2864 | fwloop_driver->init_termios = tty_std_termios; | ||
2865 | fwloop_driver->init_termios.c_cflag |= CLOCAL; | ||
2866 | tty_set_operations(fwloop_driver, &fwloop_ops); | ||
2867 | |||
2868 | err = tty_register_driver(fwloop_driver); | ||
2869 | if (err) { | ||
2870 | driver_err("register loop driver failed (%d)", err); | ||
2871 | goto put_loop; | ||
2872 | } | ||
2873 | } | ||
2874 | |||
2875 | fwtty_txn_cache = kmem_cache_create("fwtty_txn_cache", | 2875 | fwtty_txn_cache = kmem_cache_create("fwtty_txn_cache", |
2876 | sizeof(struct fwtty_transaction), | 2876 | sizeof(struct fwtty_transaction), |
2877 | 0, 0, fwtty_txn_constructor); | 2877 | 0, 0, fwtty_txn_constructor); |
2878 | if (!fwtty_txn_cache) { | 2878 | if (!fwtty_txn_cache) { |
2879 | err = -ENOMEM; | 2879 | err = -ENOMEM; |
2880 | goto unregister_driver; | 2880 | goto unregister_loop; |
2881 | } | 2881 | } |
2882 | 2882 | ||
2883 | /* | 2883 | /* |
@@ -2919,6 +2919,12 @@ remove_handler: | |||
2919 | fw_core_remove_address_handler(&fwserial_mgmt_addr_handler); | 2919 | fw_core_remove_address_handler(&fwserial_mgmt_addr_handler); |
2920 | destroy_cache: | 2920 | destroy_cache: |
2921 | kmem_cache_destroy(fwtty_txn_cache); | 2921 | kmem_cache_destroy(fwtty_txn_cache); |
2922 | unregister_loop: | ||
2923 | if (create_loop_dev) | ||
2924 | tty_unregister_driver(fwloop_driver); | ||
2925 | put_loop: | ||
2926 | if (create_loop_dev) | ||
2927 | put_tty_driver(fwloop_driver); | ||
2922 | unregister_driver: | 2928 | unregister_driver: |
2923 | tty_unregister_driver(fwtty_driver); | 2929 | tty_unregister_driver(fwtty_driver); |
2924 | put_tty: | 2930 | put_tty: |
@@ -2932,6 +2938,10 @@ static void __exit fwserial_exit(void) | |||
2932 | fw_core_remove_descriptor(&fwserial_unit_directory); | 2938 | fw_core_remove_descriptor(&fwserial_unit_directory); |
2933 | fw_core_remove_address_handler(&fwserial_mgmt_addr_handler); | 2939 | fw_core_remove_address_handler(&fwserial_mgmt_addr_handler); |
2934 | kmem_cache_destroy(fwtty_txn_cache); | 2940 | kmem_cache_destroy(fwtty_txn_cache); |
2941 | if (create_loop_dev) { | ||
2942 | tty_unregister_driver(fwloop_driver); | ||
2943 | put_tty_driver(fwloop_driver); | ||
2944 | } | ||
2935 | tty_unregister_driver(fwtty_driver); | 2945 | tty_unregister_driver(fwtty_driver); |
2936 | put_tty_driver(fwtty_driver); | 2946 | put_tty_driver(fwtty_driver); |
2937 | } | 2947 | } |