Path: blob/master/drivers/isdn/gigaset/ser-gigaset.c
15109 views
/* This is the serial hardware link layer (HLL) for the Gigaset 307x isdn1* DECT base (aka Sinus 45 isdn) using the RS232 DECT data module M101,2* written as a line discipline.3*4* =====================================================================5* This program is free software; you can redistribute it and/or6* modify it under the terms of the GNU General Public License as7* published by the Free Software Foundation; either version 2 of8* the License, or (at your option) any later version.9* =====================================================================10*/1112#include "gigaset.h"13#include <linux/module.h>14#include <linux/moduleparam.h>15#include <linux/platform_device.h>16#include <linux/completion.h>1718/* Version Information */19#define DRIVER_AUTHOR "Tilman Schmidt"20#define DRIVER_DESC "Serial Driver for Gigaset 307x using Siemens M101"2122#define GIGASET_MINORS 123#define GIGASET_MINOR 024#define GIGASET_MODULENAME "ser_gigaset"25#define GIGASET_DEVNAME "ttyGS"2627/* length limit according to Siemens 3070usb-protokoll.doc ch. 2.1 */28#define IF_WRITEBUF 2642930MODULE_AUTHOR(DRIVER_AUTHOR);31MODULE_DESCRIPTION(DRIVER_DESC);32MODULE_LICENSE("GPL");33MODULE_ALIAS_LDISC(N_GIGASET_M101);3435static int startmode = SM_ISDN;36module_param(startmode, int, S_IRUGO);37MODULE_PARM_DESC(startmode, "initial operation mode");38static int cidmode = 1;39module_param(cidmode, int, S_IRUGO);40MODULE_PARM_DESC(cidmode, "stay in CID mode when idle");4142static struct gigaset_driver *driver;4344struct ser_cardstate {45struct platform_device dev;46struct tty_struct *tty;47atomic_t refcnt;48struct completion dead_cmp;49};5051static struct platform_driver device_driver = {52.driver = {53.name = GIGASET_MODULENAME,54},55};5657static void flush_send_queue(struct cardstate *);5859/* transmit data from current open skb60* result: number of bytes sent or error code < 061*/62static int write_modem(struct cardstate *cs)63{64struct tty_struct *tty = cs->hw.ser->tty;65struct bc_state *bcs = &cs->bcs[0]; /* only one channel */66struct sk_buff *skb = bcs->tx_skb;67int sent = -EOPNOTSUPP;6869if (!tty || !tty->driver || !skb)70return -EINVAL;7172if (!skb->len) {73dev_kfree_skb_any(skb);74bcs->tx_skb = NULL;75return -EINVAL;76}7778set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);79if (tty->ops->write)80sent = tty->ops->write(tty, skb->data, skb->len);81gig_dbg(DEBUG_OUTPUT, "write_modem: sent %d", sent);82if (sent < 0) {83/* error */84flush_send_queue(cs);85return sent;86}87skb_pull(skb, sent);88if (!skb->len) {89/* skb sent completely */90gigaset_skb_sent(bcs, skb);9192gig_dbg(DEBUG_INTR, "kfree skb (Adr: %lx)!",93(unsigned long) skb);94dev_kfree_skb_any(skb);95bcs->tx_skb = NULL;96}97return sent;98}99100/*101* transmit first queued command buffer102* result: number of bytes sent or error code < 0103*/104static int send_cb(struct cardstate *cs)105{106struct tty_struct *tty = cs->hw.ser->tty;107struct cmdbuf_t *cb, *tcb;108unsigned long flags;109int sent = 0;110111if (!tty || !tty->driver)112return -EFAULT;113114cb = cs->cmdbuf;115if (!cb)116return 0; /* nothing to do */117118if (cb->len) {119set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);120sent = tty->ops->write(tty, cb->buf + cb->offset, cb->len);121if (sent < 0) {122/* error */123gig_dbg(DEBUG_OUTPUT, "send_cb: write error %d", sent);124flush_send_queue(cs);125return sent;126}127cb->offset += sent;128cb->len -= sent;129gig_dbg(DEBUG_OUTPUT, "send_cb: sent %d, left %u, queued %u",130sent, cb->len, cs->cmdbytes);131}132133while (cb && !cb->len) {134spin_lock_irqsave(&cs->cmdlock, flags);135cs->cmdbytes -= cs->curlen;136tcb = cb;137cs->cmdbuf = cb = cb->next;138if (cb) {139cb->prev = NULL;140cs->curlen = cb->len;141} else {142cs->lastcmdbuf = NULL;143cs->curlen = 0;144}145spin_unlock_irqrestore(&cs->cmdlock, flags);146147if (tcb->wake_tasklet)148tasklet_schedule(tcb->wake_tasklet);149kfree(tcb);150}151return sent;152}153154/*155* send queue tasklet156* If there is already a skb opened, put data to the transfer buffer157* by calling "write_modem".158* Otherwise take a new skb out of the queue.159*/160static void gigaset_modem_fill(unsigned long data)161{162struct cardstate *cs = (struct cardstate *) data;163struct bc_state *bcs;164struct sk_buff *nextskb;165int sent = 0;166167if (!cs) {168gig_dbg(DEBUG_OUTPUT, "%s: no cardstate", __func__);169return;170}171bcs = cs->bcs;172if (!bcs) {173gig_dbg(DEBUG_OUTPUT, "%s: no cardstate", __func__);174return;175}176if (!bcs->tx_skb) {177/* no skb is being sent; send command if any */178sent = send_cb(cs);179gig_dbg(DEBUG_OUTPUT, "%s: send_cb -> %d", __func__, sent);180if (sent)181/* something sent or error */182return;183184/* no command to send; get skb */185nextskb = skb_dequeue(&bcs->squeue);186if (!nextskb)187/* no skb either, nothing to do */188return;189bcs->tx_skb = nextskb;190191gig_dbg(DEBUG_INTR, "Dequeued skb (Adr: %lx)",192(unsigned long) bcs->tx_skb);193}194195/* send skb */196gig_dbg(DEBUG_OUTPUT, "%s: tx_skb", __func__);197if (write_modem(cs) < 0)198gig_dbg(DEBUG_OUTPUT, "%s: write_modem failed", __func__);199}200201/*202* throw away all data queued for sending203*/204static void flush_send_queue(struct cardstate *cs)205{206struct sk_buff *skb;207struct cmdbuf_t *cb;208unsigned long flags;209210/* command queue */211spin_lock_irqsave(&cs->cmdlock, flags);212while ((cb = cs->cmdbuf) != NULL) {213cs->cmdbuf = cb->next;214if (cb->wake_tasklet)215tasklet_schedule(cb->wake_tasklet);216kfree(cb);217}218cs->cmdbuf = cs->lastcmdbuf = NULL;219cs->cmdbytes = cs->curlen = 0;220spin_unlock_irqrestore(&cs->cmdlock, flags);221222/* data queue */223if (cs->bcs->tx_skb)224dev_kfree_skb_any(cs->bcs->tx_skb);225while ((skb = skb_dequeue(&cs->bcs->squeue)) != NULL)226dev_kfree_skb_any(skb);227}228229230/* Gigaset Driver Interface */231/* ======================== */232233/*234* queue an AT command string for transmission to the Gigaset device235* parameters:236* cs controller state structure237* buf buffer containing the string to send238* len number of characters to send239* wake_tasklet tasklet to run when transmission is complete, or NULL240* return value:241* number of bytes queued, or error code < 0242*/243static int gigaset_write_cmd(struct cardstate *cs, struct cmdbuf_t *cb)244{245unsigned long flags;246247gigaset_dbg_buffer(cs->mstate != MS_LOCKED ?248DEBUG_TRANSCMD : DEBUG_LOCKCMD,249"CMD Transmit", cb->len, cb->buf);250251spin_lock_irqsave(&cs->cmdlock, flags);252cb->prev = cs->lastcmdbuf;253if (cs->lastcmdbuf)254cs->lastcmdbuf->next = cb;255else {256cs->cmdbuf = cb;257cs->curlen = cb->len;258}259cs->cmdbytes += cb->len;260cs->lastcmdbuf = cb;261spin_unlock_irqrestore(&cs->cmdlock, flags);262263spin_lock_irqsave(&cs->lock, flags);264if (cs->connected)265tasklet_schedule(&cs->write_tasklet);266spin_unlock_irqrestore(&cs->lock, flags);267return cb->len;268}269270/*271* tty_driver.write_room interface routine272* return number of characters the driver will accept to be written273* parameter:274* controller state structure275* return value:276* number of characters277*/278static int gigaset_write_room(struct cardstate *cs)279{280unsigned bytes;281282bytes = cs->cmdbytes;283return bytes < IF_WRITEBUF ? IF_WRITEBUF - bytes : 0;284}285286/*287* tty_driver.chars_in_buffer interface routine288* return number of characters waiting to be sent289* parameter:290* controller state structure291* return value:292* number of characters293*/294static int gigaset_chars_in_buffer(struct cardstate *cs)295{296return cs->cmdbytes;297}298299/*300* implementation of ioctl(GIGASET_BRKCHARS)301* parameter:302* controller state structure303* return value:304* -EINVAL (unimplemented function)305*/306static int gigaset_brkchars(struct cardstate *cs, const unsigned char buf[6])307{308/* not implemented */309return -EINVAL;310}311312/*313* Open B channel314* Called by "do_action" in ev-layer.c315*/316static int gigaset_init_bchannel(struct bc_state *bcs)317{318/* nothing to do for M10x */319gigaset_bchannel_up(bcs);320return 0;321}322323/*324* Close B channel325* Called by "do_action" in ev-layer.c326*/327static int gigaset_close_bchannel(struct bc_state *bcs)328{329/* nothing to do for M10x */330gigaset_bchannel_down(bcs);331return 0;332}333334/*335* Set up B channel structure336* This is called by "gigaset_initcs" in common.c337*/338static int gigaset_initbcshw(struct bc_state *bcs)339{340/* unused */341bcs->hw.ser = NULL;342return 1;343}344345/*346* Free B channel structure347* Called by "gigaset_freebcs" in common.c348*/349static int gigaset_freebcshw(struct bc_state *bcs)350{351/* unused */352return 1;353}354355/*356* Reinitialize B channel structure357* This is called by "bcs_reinit" in common.c358*/359static void gigaset_reinitbcshw(struct bc_state *bcs)360{361/* nothing to do for M10x */362}363364/*365* Free hardware specific device data366* This will be called by "gigaset_freecs" in common.c367*/368static void gigaset_freecshw(struct cardstate *cs)369{370tasklet_kill(&cs->write_tasklet);371if (!cs->hw.ser)372return;373dev_set_drvdata(&cs->hw.ser->dev.dev, NULL);374platform_device_unregister(&cs->hw.ser->dev);375kfree(cs->hw.ser);376cs->hw.ser = NULL;377}378379static void gigaset_device_release(struct device *dev)380{381struct platform_device *pdev = to_platform_device(dev);382383/* adapted from platform_device_release() in drivers/base/platform.c */384kfree(dev->platform_data);385kfree(pdev->resource);386}387388/*389* Set up hardware specific device data390* This is called by "gigaset_initcs" in common.c391*/392static int gigaset_initcshw(struct cardstate *cs)393{394int rc;395struct ser_cardstate *scs;396397scs = kzalloc(sizeof(struct ser_cardstate), GFP_KERNEL);398if (!scs) {399pr_err("out of memory\n");400return 0;401}402cs->hw.ser = scs;403404cs->hw.ser->dev.name = GIGASET_MODULENAME;405cs->hw.ser->dev.id = cs->minor_index;406cs->hw.ser->dev.dev.release = gigaset_device_release;407rc = platform_device_register(&cs->hw.ser->dev);408if (rc != 0) {409pr_err("error %d registering platform device\n", rc);410kfree(cs->hw.ser);411cs->hw.ser = NULL;412return 0;413}414dev_set_drvdata(&cs->hw.ser->dev.dev, cs);415416tasklet_init(&cs->write_tasklet,417gigaset_modem_fill, (unsigned long) cs);418return 1;419}420421/*422* set modem control lines423* Parameters:424* card state structure425* modem control line state ([TIOCM_DTR]|[TIOCM_RTS])426* Called by "gigaset_start" and "gigaset_enterconfigmode" in common.c427* and by "if_lock" and "if_termios" in interface.c428*/429static int gigaset_set_modem_ctrl(struct cardstate *cs, unsigned old_state,430unsigned new_state)431{432struct tty_struct *tty = cs->hw.ser->tty;433unsigned int set, clear;434435if (!tty || !tty->driver || !tty->ops->tiocmset)436return -EINVAL;437set = new_state & ~old_state;438clear = old_state & ~new_state;439if (!set && !clear)440return 0;441gig_dbg(DEBUG_IF, "tiocmset set %x clear %x", set, clear);442return tty->ops->tiocmset(tty, set, clear);443}444445static int gigaset_baud_rate(struct cardstate *cs, unsigned cflag)446{447return -EINVAL;448}449450static int gigaset_set_line_ctrl(struct cardstate *cs, unsigned cflag)451{452return -EINVAL;453}454455static const struct gigaset_ops ops = {456gigaset_write_cmd,457gigaset_write_room,458gigaset_chars_in_buffer,459gigaset_brkchars,460gigaset_init_bchannel,461gigaset_close_bchannel,462gigaset_initbcshw,463gigaset_freebcshw,464gigaset_reinitbcshw,465gigaset_initcshw,466gigaset_freecshw,467gigaset_set_modem_ctrl,468gigaset_baud_rate,469gigaset_set_line_ctrl,470gigaset_m10x_send_skb, /* asyncdata.c */471gigaset_m10x_input, /* asyncdata.c */472};473474475/* Line Discipline Interface */476/* ========================= */477478/* helper functions for cardstate refcounting */479static struct cardstate *cs_get(struct tty_struct *tty)480{481struct cardstate *cs = tty->disc_data;482483if (!cs || !cs->hw.ser) {484gig_dbg(DEBUG_ANY, "%s: no cardstate", __func__);485return NULL;486}487atomic_inc(&cs->hw.ser->refcnt);488return cs;489}490491static void cs_put(struct cardstate *cs)492{493if (atomic_dec_and_test(&cs->hw.ser->refcnt))494complete(&cs->hw.ser->dead_cmp);495}496497/*498* Called by the tty driver when the line discipline is pushed onto the tty.499* Called in process context.500*/501static int502gigaset_tty_open(struct tty_struct *tty)503{504struct cardstate *cs;505506gig_dbg(DEBUG_INIT, "Starting HLL for Gigaset M101");507508pr_info(DRIVER_DESC "\n");509510if (!driver) {511pr_err("%s: no driver structure\n", __func__);512return -ENODEV;513}514515/* allocate memory for our device state and initialize it */516cs = gigaset_initcs(driver, 1, 1, 0, cidmode, GIGASET_MODULENAME);517if (!cs)518goto error;519520cs->dev = &cs->hw.ser->dev.dev;521cs->hw.ser->tty = tty;522atomic_set(&cs->hw.ser->refcnt, 1);523init_completion(&cs->hw.ser->dead_cmp);524525tty->disc_data = cs;526527/* OK.. Initialization of the datastructures and the HW is done.. Now528* startup system and notify the LL that we are ready to run529*/530if (startmode == SM_LOCKED)531cs->mstate = MS_LOCKED;532if (!gigaset_start(cs)) {533tasklet_kill(&cs->write_tasklet);534goto error;535}536537gig_dbg(DEBUG_INIT, "Startup of HLL done");538return 0;539540error:541gig_dbg(DEBUG_INIT, "Startup of HLL failed");542tty->disc_data = NULL;543gigaset_freecs(cs);544return -ENODEV;545}546547/*548* Called by the tty driver when the line discipline is removed.549* Called from process context.550*/551static void552gigaset_tty_close(struct tty_struct *tty)553{554struct cardstate *cs = tty->disc_data;555556gig_dbg(DEBUG_INIT, "Stopping HLL for Gigaset M101");557558if (!cs) {559gig_dbg(DEBUG_INIT, "%s: no cardstate", __func__);560return;561}562563/* prevent other callers from entering ldisc methods */564tty->disc_data = NULL;565566if (!cs->hw.ser)567pr_err("%s: no hw cardstate\n", __func__);568else {569/* wait for running methods to finish */570if (!atomic_dec_and_test(&cs->hw.ser->refcnt))571wait_for_completion(&cs->hw.ser->dead_cmp);572}573574/* stop operations */575gigaset_stop(cs);576tasklet_kill(&cs->write_tasklet);577flush_send_queue(cs);578cs->dev = NULL;579gigaset_freecs(cs);580581gig_dbg(DEBUG_INIT, "Shutdown of HLL done");582}583584/*585* Called by the tty driver when the tty line is hung up.586* Wait for I/O to driver to complete and unregister ISDN device.587* This is already done by the close routine, so just call that.588* Called from process context.589*/590static int gigaset_tty_hangup(struct tty_struct *tty)591{592gigaset_tty_close(tty);593return 0;594}595596/*597* Read on the tty.598* Unused, received data goes only to the Gigaset driver.599*/600static ssize_t601gigaset_tty_read(struct tty_struct *tty, struct file *file,602unsigned char __user *buf, size_t count)603{604return -EAGAIN;605}606607/*608* Write on the tty.609* Unused, transmit data comes only from the Gigaset driver.610*/611static ssize_t612gigaset_tty_write(struct tty_struct *tty, struct file *file,613const unsigned char *buf, size_t count)614{615return -EAGAIN;616}617618/*619* Ioctl on the tty.620* Called in process context only.621* May be re-entered by multiple ioctl calling threads.622*/623static int624gigaset_tty_ioctl(struct tty_struct *tty, struct file *file,625unsigned int cmd, unsigned long arg)626{627struct cardstate *cs = cs_get(tty);628int rc, val;629int __user *p = (int __user *)arg;630631if (!cs)632return -ENXIO;633634switch (cmd) {635636case FIONREAD:637/* unused, always return zero */638val = 0;639rc = put_user(val, p);640break;641642case TCFLSH:643/* flush our buffers and the serial port's buffer */644switch (arg) {645case TCIFLUSH:646/* no own input buffer to flush */647break;648case TCIOFLUSH:649case TCOFLUSH:650flush_send_queue(cs);651break;652}653/* Pass through */654655default:656/* pass through to underlying serial device */657rc = n_tty_ioctl_helper(tty, file, cmd, arg);658break;659}660cs_put(cs);661return rc;662}663664/*665* Called by the tty driver when a block of data has been received.666* Will not be re-entered while running but other ldisc functions667* may be called in parallel.668* Can be called from hard interrupt level as well as soft interrupt669* level or mainline.670* Parameters:671* tty tty structure672* buf buffer containing received characters673* cflags buffer containing error flags for received characters (ignored)674* count number of received characters675*/676static void677gigaset_tty_receive(struct tty_struct *tty, const unsigned char *buf,678char *cflags, int count)679{680struct cardstate *cs = cs_get(tty);681unsigned tail, head, n;682struct inbuf_t *inbuf;683684if (!cs)685return;686inbuf = cs->inbuf;687if (!inbuf) {688dev_err(cs->dev, "%s: no inbuf\n", __func__);689cs_put(cs);690return;691}692693tail = inbuf->tail;694head = inbuf->head;695gig_dbg(DEBUG_INTR, "buffer state: %u -> %u, receive %u bytes",696head, tail, count);697698if (head <= tail) {699/* possible buffer wraparound */700n = min_t(unsigned, count, RBUFSIZE - tail);701memcpy(inbuf->data + tail, buf, n);702tail = (tail + n) % RBUFSIZE;703buf += n;704count -= n;705}706707if (count > 0) {708/* tail < head and some data left */709n = head - tail - 1;710if (count > n) {711dev_err(cs->dev,712"inbuf overflow, discarding %d bytes\n",713count - n);714count = n;715}716memcpy(inbuf->data + tail, buf, count);717tail += count;718}719720gig_dbg(DEBUG_INTR, "setting tail to %u", tail);721inbuf->tail = tail;722723/* Everything was received .. Push data into handler */724gig_dbg(DEBUG_INTR, "%s-->BH", __func__);725gigaset_schedule_event(cs);726cs_put(cs);727}728729/*730* Called by the tty driver when there's room for more data to send.731*/732static void733gigaset_tty_wakeup(struct tty_struct *tty)734{735struct cardstate *cs = cs_get(tty);736737clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);738if (!cs)739return;740tasklet_schedule(&cs->write_tasklet);741cs_put(cs);742}743744static struct tty_ldisc_ops gigaset_ldisc = {745.owner = THIS_MODULE,746.magic = TTY_LDISC_MAGIC,747.name = "ser_gigaset",748.open = gigaset_tty_open,749.close = gigaset_tty_close,750.hangup = gigaset_tty_hangup,751.read = gigaset_tty_read,752.write = gigaset_tty_write,753.ioctl = gigaset_tty_ioctl,754.receive_buf = gigaset_tty_receive,755.write_wakeup = gigaset_tty_wakeup,756};757758759/* Initialization / Shutdown */760/* ========================= */761762static int __init ser_gigaset_init(void)763{764int rc;765766gig_dbg(DEBUG_INIT, "%s", __func__);767rc = platform_driver_register(&device_driver);768if (rc != 0) {769pr_err("error %d registering platform driver\n", rc);770return rc;771}772773/* allocate memory for our driver state and initialize it */774driver = gigaset_initdriver(GIGASET_MINOR, GIGASET_MINORS,775GIGASET_MODULENAME, GIGASET_DEVNAME,776&ops, THIS_MODULE);777if (!driver)778goto error;779780rc = tty_register_ldisc(N_GIGASET_M101, &gigaset_ldisc);781if (rc != 0) {782pr_err("error %d registering line discipline\n", rc);783goto error;784}785786return 0;787788error:789if (driver) {790gigaset_freedriver(driver);791driver = NULL;792}793platform_driver_unregister(&device_driver);794return rc;795}796797static void __exit ser_gigaset_exit(void)798{799int rc;800801gig_dbg(DEBUG_INIT, "%s", __func__);802803if (driver) {804gigaset_freedriver(driver);805driver = NULL;806}807808rc = tty_unregister_ldisc(N_GIGASET_M101);809if (rc != 0)810pr_err("error %d unregistering line discipline\n", rc);811812platform_driver_unregister(&device_driver);813}814815module_init(ser_gigaset_init);816module_exit(ser_gigaset_exit);817818819