aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Hurley <peter@hurleysoftware.com>2013-01-28 22:34:38 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-01-29 23:28:45 -0500
commitfa1da242c3d24801ae946f4664406f679865388f (patch)
tree7d5e014ce72e7320a64345c09b00c90bc139f43a
parenta3d9ad474ef391166a48128bea753f455e9a7d69 (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/TODO13
-rw-r--r--drivers/staging/fwserial/fwserial.c176
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
121. This driver uses the same unregistered vendor id that the firewire core does 121. 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);
72static bool port_table_corrupt; 72static 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 */
76static int num_ports; 79static int num_ports;
77 80
@@ -79,6 +82,7 @@ static int num_ports;
79static struct kmem_cache *fwtty_txn_cache; 82static struct kmem_cache *fwtty_txn_cache;
80 83
81struct tty_driver *fwtty_driver; 84struct tty_driver *fwtty_driver;
85static struct tty_driver *fwloop_driver;
82 86
83struct fwtty_transaction; 87struct fwtty_transaction;
84typedef void (*fwtty_transaction_cb)(struct fw_card *card, int rcode, 88typedef 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
1172static 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
1168static int fwtty_write(struct tty_struct *tty, const unsigned char *buf, int c) 1185static 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
1621static 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
1604static inline int mgmt_pkt_expected_len(__be16 code) 1641static 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 */
1900static void fwserial_close_port(struct fwtty_port *port) 1937static 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 */
2188static void release_loop_device(struct device *dev)
2189{
2190 kfree(dev);
2191}
2192
2193static 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]));
2365unregister_ttys: 2336unregister_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);
2920destroy_cache: 2920destroy_cache:
2921 kmem_cache_destroy(fwtty_txn_cache); 2921 kmem_cache_destroy(fwtty_txn_cache);
2922unregister_loop:
2923 if (create_loop_dev)
2924 tty_unregister_driver(fwloop_driver);
2925put_loop:
2926 if (create_loop_dev)
2927 put_tty_driver(fwloop_driver);
2922unregister_driver: 2928unregister_driver:
2923 tty_unregister_driver(fwtty_driver); 2929 tty_unregister_driver(fwtty_driver);
2924put_tty: 2930put_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}