Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Peter Hurley and committed by
Greg Kroah-Hartman
fa1da242 a3d9ad47

+93 -96
-13
drivers/staging/fwserial/TODO
··· 12 12 1. This driver uses the same unregistered vendor id that the firewire core does 13 13 (0xd00d1e). Perhaps this could be exposed as a define in 14 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().
+93 -83
drivers/staging/fwserial/fwserial.c
··· 72 72 static bool port_table_corrupt; 73 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 78 /* total # of tty ports created per fw_card */ 76 79 static int num_ports; 77 80 ··· 82 79 static struct kmem_cache *fwtty_txn_cache; 83 80 84 81 struct tty_driver *fwtty_driver; 82 + static struct tty_driver *fwloop_driver; 85 83 86 84 struct fwtty_transaction; 87 85 typedef void (*fwtty_transaction_cb)(struct fw_card *card, int rcode, ··· 1169 1165 return err; 1170 1166 } 1171 1167 1168 + static int fwloop_install(struct tty_driver *driver, struct tty_struct *tty) 1169 + { 1170 + struct fwtty_port *port = fwtty_port_get(table_idx(tty->index)); 1171 + int err; 1172 + 1173 + err = tty_standard_install(driver, tty); 1174 + if (!err) 1175 + tty->driver_data = port; 1176 + else 1177 + fwtty_port_put(port); 1178 + return err; 1179 + } 1180 + 1172 1181 static int fwtty_write(struct tty_struct *tty, const unsigned char *buf, int c) 1173 1182 { 1174 1183 struct fwtty_port *port = tty->driver_data; ··· 1618 1601 .proc_fops = &fwtty_proc_fops, 1619 1602 }; 1620 1603 1604 + static const struct tty_operations fwloop_ops = { 1605 + .open = fwtty_open, 1606 + .close = fwtty_close, 1607 + .hangup = fwtty_hangup, 1608 + .cleanup = fwtty_cleanup, 1609 + .install = fwloop_install, 1610 + .write = fwtty_write, 1611 + .write_room = fwtty_write_room, 1612 + .chars_in_buffer = fwtty_chars_in_buffer, 1613 + .send_xchar = fwtty_send_xchar, 1614 + .throttle = fwtty_throttle, 1615 + .unthrottle = fwtty_unthrottle, 1616 + .ioctl = fwtty_ioctl, 1617 + .set_termios = fwtty_set_termios, 1618 + .break_ctl = fwtty_break_ctl, 1619 + .tiocmget = fwtty_tiocmget, 1620 + .tiocmset = fwtty_tiocmset, 1621 + .get_icount = fwtty_get_icount, 1622 + }; 1623 + 1621 1624 static inline int mgmt_pkt_expected_len(__be16 code) 1622 1625 { 1623 1626 static const struct fwserial_mgmt_pkt pkt; ··· 1934 1897 * The port reference is put by fwtty_cleanup (if a reference was 1935 1898 * ever taken). 1936 1899 */ 1937 - static void fwserial_close_port(struct fwtty_port *port) 1900 + static void fwserial_close_port(struct tty_driver *driver, 1901 + struct fwtty_port *port) 1938 1902 { 1939 1903 struct tty_struct *tty; 1940 1904 ··· 1947 1909 } 1948 1910 mutex_unlock(&port->port.mutex); 1949 1911 1950 - tty_unregister_device(fwtty_driver, port->index); 1912 + if (driver == fwloop_driver) 1913 + tty_unregister_device(driver, loop_idx(port)); 1914 + else 1915 + tty_unregister_device(driver, port->index); 1951 1916 } 1952 1917 1953 1918 /** ··· 2208 2167 } 2209 2168 2210 2169 /** 2211 - * create_loop_device - create a loopback tty device 2212 - * @tty_driver: tty_driver to own loopback device 2213 - * @prototype: ptr to already-assigned 'prototype' tty port 2214 - * @index: index to associate this device with the tty port 2215 - * @parent: device to child to 2216 - * 2217 - * HACK - this is basically tty_port_register_device() with an 2218 - * alternate naming scheme. Suggest tty_port_register_named_device() 2219 - * helper api. 2220 - * 2221 - * Creates a loopback tty device named 'fwloop<n>' which is attached to 2222 - * the local unit in fwserial_add_peer(). Note that <n> in the device 2223 - * name advances in increments of port allocation blocks, ie., for port 2224 - * indices 0..3, the device name will be 'fwloop0'; for 4..7, 'fwloop1', 2225 - * and so on. 2226 - * 2227 - * Only one loopback device should be created per fw_card. 2228 - */ 2229 - static void release_loop_device(struct device *dev) 2230 - { 2231 - kfree(dev); 2232 - } 2233 - 2234 - static struct device *create_loop_device(struct tty_driver *driver, 2235 - struct fwtty_port *prototype, 2236 - struct fwtty_port *port, 2237 - struct device *parent) 2238 - { 2239 - char name[64]; 2240 - int index = port->index; 2241 - dev_t devt = MKDEV(driver->major, driver->minor_start) + index; 2242 - struct device *dev = NULL; 2243 - int err; 2244 - 2245 - if (index >= fwtty_driver->num) 2246 - return ERR_PTR(-EINVAL); 2247 - 2248 - snprintf(name, 64, "%s%d", loop_dev_name, index / num_ports); 2249 - 2250 - tty_port_link_device(&port->port, driver, index); 2251 - 2252 - cdev_init(&driver->cdevs[index], driver->cdevs[prototype->index].ops); 2253 - driver->cdevs[index].owner = driver->owner; 2254 - err = cdev_add(&driver->cdevs[index], devt, 1); 2255 - if (err) 2256 - return ERR_PTR(err); 2257 - 2258 - dev = kzalloc(sizeof(*dev), GFP_KERNEL); 2259 - if (!dev) { 2260 - cdev_del(&driver->cdevs[index]); 2261 - return ERR_PTR(-ENOMEM); 2262 - } 2263 - 2264 - dev->devt = devt; 2265 - dev->class = prototype->device->class; 2266 - dev->parent = parent; 2267 - dev->release = release_loop_device; 2268 - dev_set_name(dev, "%s", name); 2269 - dev->groups = NULL; 2270 - dev_set_drvdata(dev, NULL); 2271 - 2272 - err = device_register(dev); 2273 - if (err) { 2274 - put_device(dev); 2275 - cdev_del(&driver->cdevs[index]); 2276 - return ERR_PTR(err); 2277 - } 2278 - 2279 - return dev; 2280 - } 2281 - 2282 - /** 2283 2170 * fwserial_create - init everything to create TTYs for a specific fw_card 2284 2171 * @unit: fw_unit for first 'serial' unit device probed for this fw_card 2285 2172 * ··· 2305 2336 if (create_loop_dev) { 2306 2337 struct device *loop_dev; 2307 2338 2308 - loop_dev = create_loop_device(fwtty_driver, 2309 - serial->ports[0], 2310 - serial->ports[num_ttys], 2311 - card->device); 2339 + loop_dev = tty_port_register_device(&serial->ports[j]->port, 2340 + fwloop_driver, 2341 + loop_idx(serial->ports[j]), 2342 + card->device); 2312 2343 if (IS_ERR(loop_dev)) { 2313 2344 err = PTR_ERR(loop_dev); 2314 2345 fwtty_err(&unit, "create loop device failed (%d)", err); 2315 2346 goto unregister_ttys; 2316 2347 } 2317 - serial->ports[num_ttys]->device = loop_dev; 2318 - serial->ports[num_ttys]->loopback = true; 2348 + serial->ports[j]->device = loop_dev; 2349 + serial->ports[j]->loopback = true; 2319 2350 } 2320 2351 2321 2352 list_add_rcu(&serial->list, &fwserial_list); ··· 2331 2362 2332 2363 /* fall-through to error processing */ 2333 2364 list_del_rcu(&serial->list); 2365 + if (create_loop_dev) 2366 + tty_unregister_device(fwloop_driver, loop_idx(serial->ports[j])); 2334 2367 unregister_ttys: 2335 2368 for (--j; j >= 0; --j) 2336 2369 tty_unregister_device(fwtty_driver, serial->ports[j]->index); ··· 2421 2450 /* unlink from the fwserial_list here */ 2422 2451 list_del_rcu(&serial->list); 2423 2452 2424 - for (i = 0; i < num_ports; ++i) 2425 - fwserial_close_port(serial->ports[i]); 2453 + for (i = 0; i < num_ttys; ++i) 2454 + fwserial_close_port(fwtty_driver, serial->ports[i]); 2455 + if (create_loop_dev) 2456 + fwserial_close_port(fwloop_driver, serial->ports[i]); 2426 2457 kref_put(&serial->kref, fwserial_destroy); 2427 2458 } 2428 2459 mutex_unlock(&fwserial_list_mutex); ··· 2845 2872 goto put_tty; 2846 2873 } 2847 2874 2875 + if (create_loop_dev) { 2876 + fwloop_driver = alloc_tty_driver(MAX_TOTAL_PORTS / num_ports); 2877 + if (!fwloop_driver) { 2878 + err = -ENOMEM; 2879 + goto unregister_driver; 2880 + } 2881 + 2882 + fwloop_driver->driver_name = KBUILD_MODNAME "_loop"; 2883 + fwloop_driver->name = loop_dev_name; 2884 + fwloop_driver->major = 0; 2885 + fwloop_driver->minor_start = 0; 2886 + fwloop_driver->type = TTY_DRIVER_TYPE_SERIAL; 2887 + fwloop_driver->subtype = SERIAL_TYPE_NORMAL; 2888 + fwloop_driver->flags = TTY_DRIVER_REAL_RAW | 2889 + TTY_DRIVER_DYNAMIC_DEV; 2890 + 2891 + fwloop_driver->init_termios = tty_std_termios; 2892 + fwloop_driver->init_termios.c_cflag |= CLOCAL; 2893 + tty_set_operations(fwloop_driver, &fwloop_ops); 2894 + 2895 + err = tty_register_driver(fwloop_driver); 2896 + if (err) { 2897 + driver_err("register loop driver failed (%d)", err); 2898 + goto put_loop; 2899 + } 2900 + } 2901 + 2848 2902 fwtty_txn_cache = kmem_cache_create("fwtty_txn_cache", 2849 2903 sizeof(struct fwtty_transaction), 2850 2904 0, 0, fwtty_txn_constructor); 2851 2905 if (!fwtty_txn_cache) { 2852 2906 err = -ENOMEM; 2853 - goto unregister_driver; 2907 + goto unregister_loop; 2854 2908 } 2855 2909 2856 2910 /* ··· 2919 2919 fw_core_remove_address_handler(&fwserial_mgmt_addr_handler); 2920 2920 destroy_cache: 2921 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 2928 unregister_driver: 2923 2929 tty_unregister_driver(fwtty_driver); 2924 2930 put_tty: ··· 2938 2932 fw_core_remove_descriptor(&fwserial_unit_directory); 2939 2933 fw_core_remove_address_handler(&fwserial_mgmt_addr_handler); 2940 2934 kmem_cache_destroy(fwtty_txn_cache); 2935 + if (create_loop_dev) { 2936 + tty_unregister_driver(fwloop_driver); 2937 + put_tty_driver(fwloop_driver); 2938 + } 2941 2939 tty_unregister_driver(fwtty_driver); 2942 2940 put_tty_driver(fwtty_driver); 2943 2941 }