diff options
Diffstat (limited to 'drivers/isdn/gigaset/usb-gigaset.c')
| -rw-r--r-- | drivers/isdn/gigaset/usb-gigaset.c | 190 |
1 files changed, 78 insertions, 112 deletions
diff --git a/drivers/isdn/gigaset/usb-gigaset.c b/drivers/isdn/gigaset/usb-gigaset.c index fba61f67052..d0a41cb0cf6 100644 --- a/drivers/isdn/gigaset/usb-gigaset.c +++ b/drivers/isdn/gigaset/usb-gigaset.c @@ -16,10 +16,6 @@ */ #include "gigaset.h" - -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/slab.h> #include <linux/usb.h> #include <linux/module.h> #include <linux/moduleparam.h> @@ -43,14 +39,15 @@ MODULE_PARM_DESC(cidmode, "Call-ID mode"); #define GIGASET_MODULENAME "usb_gigaset" #define GIGASET_DEVNAME "ttyGU" -#define IF_WRITEBUF 2000 //FIXME // WAKEUP_CHARS: 256 +/* length limit according to Siemens 3070usb-protokoll.doc ch. 2.1 */ +#define IF_WRITEBUF 264 /* Values for the Gigaset M105 Data */ #define USB_M105_VENDOR_ID 0x0681 #define USB_M105_PRODUCT_ID 0x0009 /* table of devices that work with this driver */ -static const struct usb_device_id gigaset_table [] = { +static const struct usb_device_id gigaset_table[] = { { USB_DEVICE(USB_M105_VENDOR_ID, USB_M105_PRODUCT_ID) }, { } /* Terminating entry */ }; @@ -97,8 +94,8 @@ MODULE_DEVICE_TABLE(usb, gigaset_table); * 41 19 -- -- -- -- 06 00 00 00 00 xx 11 13 * Used after every "configuration sequence" (RQ 12, RQs 01/03/13). * xx is usually 0x00 but was 0x7e before starting data transfer - * in unimodem mode. So, this might be an array of characters that need - * special treatment ("commit all bufferd data"?), 11=^Q, 13=^S. + * in unimodem mode. So, this might be an array of characters that + * need special treatment ("commit all bufferd data"?), 11=^Q, 13=^S. * * Unimodem mode: use "modprobe ppp_async flag_time=0" as the device _needs_ two * flags per packet. @@ -114,7 +111,7 @@ static int gigaset_suspend(struct usb_interface *intf, pm_message_t message); static int gigaset_resume(struct usb_interface *intf); static int gigaset_pre_reset(struct usb_interface *intf); -static struct gigaset_driver *driver = NULL; +static struct gigaset_driver *driver; /* usb specific object needed to register this driver with the usb subsystem */ static struct usb_driver gigaset_usb_driver = { @@ -127,6 +124,7 @@ static struct usb_driver gigaset_usb_driver = { .reset_resume = gigaset_resume, .pre_reset = gigaset_pre_reset, .post_reset = gigaset_resume, + .disable_hub_initiated_lpm = 1, }; struct usb_cardstate { @@ -141,6 +139,7 @@ struct usb_cardstate { struct urb *bulk_out_urb; /* Input buffer */ + unsigned char *rcvbuf; int rcvbuf_size; struct urb *read_urb; __u8 int_in_endpointAddr; @@ -153,8 +152,6 @@ static inline unsigned tiocm_to_gigaset(unsigned state) return ((state & TIOCM_DTR) ? 1 : 0) | ((state & TIOCM_RTS) ? 2 : 0); } -#ifdef CONFIG_GIGASET_UNDOCREQ -/* WARNING: EXPERIMENTAL! */ static int gigaset_set_modem_ctrl(struct cardstate *cs, unsigned old_state, unsigned new_state) { @@ -166,16 +163,19 @@ static int gigaset_set_modem_ctrl(struct cardstate *cs, unsigned old_state, val = tiocm_to_gigaset(new_state); gig_dbg(DEBUG_USBREQ, "set flags 0x%02x with mask 0x%02x", val, mask); - // don't use this in an interrupt/BH r = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 7, 0x41, (val & 0xff) | ((mask & 0xff) << 8), 0, NULL, 0, 2000 /* timeout? */); if (r < 0) return r; - //.. return 0; } +/* + * Set M105 configuration value + * using undocumented device commands reverse engineered from USB traces + * of the Siemens Windows driver + */ static int set_value(struct cardstate *cs, u8 req, u16 val) { struct usb_device *udev = cs->hw.usb->udev; @@ -185,7 +185,7 @@ static int set_value(struct cardstate *cs, u8 req, u16 val) (unsigned)req, (unsigned)val); r = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x12, 0x41, 0xf /*?*/, 0, NULL, 0, 2000 /*?*/); - /* no idea what this does */ + /* no idea what this does */ if (r < 0) { dev_err(&udev->dev, "error %d on request 0x12\n", -r); return r; @@ -205,8 +205,10 @@ static int set_value(struct cardstate *cs, u8 req, u16 val) return r < 0 ? r : (r2 < 0 ? r2 : 0); } -/* WARNING: HIGHLY EXPERIMENTAL! */ -// don't use this in an interrupt/BH +/* + * set the baud rate on the internal serial adapter + * using the undocumented parameter setting command + */ static int gigaset_baud_rate(struct cardstate *cs, unsigned cflag) { u16 val; @@ -215,7 +217,6 @@ static int gigaset_baud_rate(struct cardstate *cs, unsigned cflag) cflag &= CBAUD; switch (cflag) { - //FIXME more values? case B300: rate = 300; break; case B600: rate = 600; break; case B1200: rate = 1200; break; @@ -237,8 +238,10 @@ static int gigaset_baud_rate(struct cardstate *cs, unsigned cflag) return set_value(cs, 1, val); } -/* WARNING: HIGHLY EXPERIMENTAL! */ -// don't use this in an interrupt/BH +/* + * set the line format on the internal serial adapter + * using the undocumented parameter setting command + */ static int gigaset_set_line_ctrl(struct cardstate *cs, unsigned cflag) { u16 val = 0; @@ -266,7 +269,7 @@ static int gigaset_set_line_ctrl(struct cardstate *cs, unsigned cflag) /* set the number of stop bits */ if (cflag & CSTOPB) { if ((cflag & CSIZE) == CS5) - val |= 1; /* 1.5 stop bits */ //FIXME is this okay? + val |= 1; /* 1.5 stop bits */ else val |= 2; /* 2 stop bits */ } @@ -274,26 +277,8 @@ static int gigaset_set_line_ctrl(struct cardstate *cs, unsigned cflag) return set_value(cs, 3, val); } -#else -static int gigaset_set_modem_ctrl(struct cardstate *cs, unsigned old_state, - unsigned new_state) -{ - return -EINVAL; -} - -static int gigaset_set_line_ctrl(struct cardstate *cs, unsigned cflag) -{ - return -EINVAL; -} - -static int gigaset_baud_rate(struct cardstate *cs, unsigned cflag) -{ - return -EINVAL; -} -#endif - - /*================================================================================================================*/ +/*============================================================================*/ static int gigaset_init_bchannel(struct bc_state *bcs) { /* nothing to do for M10x */ @@ -355,22 +340,19 @@ static void gigaset_modem_fill(unsigned long data) if (write_modem(cs) < 0) { gig_dbg(DEBUG_OUTPUT, "modem_fill: write_modem failed"); - // FIXME should we tell the LL? again = 1; /* no callback will be called! */ } } } while (again); } -/** - * gigaset_read_int_callback - * - * It is called if the data was received from the device. +/* + * Interrupt Input URB completion routine */ static void gigaset_read_int_callback(struct urb *urb) { - struct inbuf_t *inbuf = urb->context; - struct cardstate *cs = inbuf->cs; + struct cardstate *cs = urb->context; + struct inbuf_t *inbuf = cs->inbuf; int status = urb->status; int r; unsigned numbytes; @@ -381,10 +363,10 @@ static void gigaset_read_int_callback(struct urb *urb) numbytes = urb->actual_length; if (numbytes) { - src = inbuf->rcvbuf; + src = cs->hw.usb->rcvbuf; if (unlikely(*src)) dev_warn(cs->dev, - "%s: There was no leading 0, but 0x%02x!\n", + "%s: There was no leading 0, but 0x%02x!\n", __func__, (unsigned) *src); ++src; /* skip leading 0x00 */ --numbytes; @@ -453,7 +435,7 @@ static int send_cb(struct cardstate *cs, struct cmdbuf_t *cb) struct cmdbuf_t *tcb; unsigned long flags; int count; - int status = -ENOENT; // FIXME + int status = -ENOENT; struct usb_cardstate *ucs = cs->hw.usb; do { @@ -484,7 +466,7 @@ static int send_cb(struct cardstate *cs, struct cmdbuf_t *cb) usb_fill_bulk_urb(ucs->bulk_out_urb, ucs->udev, usb_sndbulkpipe(ucs->udev, - ucs->bulk_out_endpointAddr & 0x0f), + ucs->bulk_out_endpointAddr & 0x0f), cb->buf + cb->offset, count, gigaset_write_bulk_callback, cs); @@ -493,7 +475,9 @@ static int send_cb(struct cardstate *cs, struct cmdbuf_t *cb) ucs->busy = 1; spin_lock_irqsave(&cs->lock, flags); - status = cs->connected ? usb_submit_urb(ucs->bulk_out_urb, GFP_ATOMIC) : -ENODEV; + status = cs->connected ? + usb_submit_urb(ucs->bulk_out_urb, GFP_ATOMIC) : + -ENODEV; spin_unlock_irqrestore(&cs->lock, flags); if (status) { @@ -511,29 +495,13 @@ static int send_cb(struct cardstate *cs, struct cmdbuf_t *cb) } /* Send command to device. */ -static int gigaset_write_cmd(struct cardstate *cs, const unsigned char *buf, - int len, struct tasklet_struct *wake_tasklet) +static int gigaset_write_cmd(struct cardstate *cs, struct cmdbuf_t *cb) { - struct cmdbuf_t *cb; unsigned long flags; gigaset_dbg_buffer(cs->mstate != MS_LOCKED ? - DEBUG_TRANSCMD : DEBUG_LOCKCMD, - "CMD Transmit", len, buf); - - if (len <= 0) - return 0; - - if (!(cb = kmalloc(sizeof(struct cmdbuf_t) + len, GFP_ATOMIC))) { - dev_err(cs->dev, "%s: out of memory\n", __func__); - return -ENOMEM; - } - - memcpy(cb->buf, buf, len); - cb->len = len; - cb->offset = 0; - cb->next = NULL; - cb->wake_tasklet = wake_tasklet; + DEBUG_TRANSCMD : DEBUG_LOCKCMD, + "CMD Transmit", cb->len, cb->buf); spin_lock_irqsave(&cs->cmdlock, flags); cb->prev = cs->lastcmdbuf; @@ -541,9 +509,9 @@ static int gigaset_write_cmd(struct cardstate *cs, const unsigned char *buf, cs->lastcmdbuf->next = cb; else { cs->cmdbuf = cb; - cs->curlen = len; + cs->curlen = cb->len; } - cs->cmdbytes += len; + cs->cmdbytes += cb->len; cs->lastcmdbuf = cb; spin_unlock_irqrestore(&cs->cmdlock, flags); @@ -551,7 +519,7 @@ static int gigaset_write_cmd(struct cardstate *cs, const unsigned char *buf, if (cs->connected) tasklet_schedule(&cs->write_tasklet); spin_unlock_irqrestore(&cs->lock, flags); - return len; + return cb->len; } static int gigaset_write_room(struct cardstate *cs) @@ -567,24 +535,24 @@ static int gigaset_chars_in_buffer(struct cardstate *cs) return cs->cmdbytes; } +/* + * set the break characters on the internal serial adapter + * using undocumented device commands reverse engineered from USB traces + * of the Siemens Windows driver + */ static int gigaset_brkchars(struct cardstate *cs, const unsigned char buf[6]) { -#ifdef CONFIG_GIGASET_UNDOCREQ struct usb_device *udev = cs->hw.usb->udev; gigaset_dbg_buffer(DEBUG_USBREQ, "brkchars", 6, buf); memcpy(cs->hw.usb->bchars, buf, 6); return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x19, 0x41, 0, 0, &buf, 6, 2000); -#else - return -EINVAL; -#endif } -static int gigaset_freebcshw(struct bc_state *bcs) +static void gigaset_freebcshw(struct bc_state *bcs) { /* unused */ - return 1; } /* Initialize the b-channel structure */ @@ -592,7 +560,7 @@ static int gigaset_initbcshw(struct bc_state *bcs) { /* unused */ bcs->hw.usb = NULL; - return 1; + return 0; } static void gigaset_reinitbcshw(struct bc_state *bcs) @@ -614,7 +582,7 @@ static int gigaset_initcshw(struct cardstate *cs) kmalloc(sizeof(struct usb_cardstate), GFP_KERNEL); if (!ucs) { pr_err("out of memory\n"); - return 0; + return -ENOMEM; } ucs->bchars[0] = 0; @@ -625,12 +593,11 @@ static int gigaset_initcshw(struct cardstate *cs) ucs->bchars[5] = 0x13; ucs->bulk_out_buffer = NULL; ucs->bulk_out_urb = NULL; - //ucs->urb_cmd_out = NULL; ucs->read_urb = NULL; tasklet_init(&cs->write_tasklet, - &gigaset_modem_fill, (unsigned long) cs); + gigaset_modem_fill, (unsigned long) cs); - return 1; + return 0; } /* Send data from current skb to the device. */ @@ -642,7 +609,7 @@ static int write_modem(struct cardstate *cs) struct usb_cardstate *ucs = cs->hw.usb; unsigned long flags; - gig_dbg(DEBUG_WRITE, "len: %d...", bcs->tx_skb->len); + gig_dbg(DEBUG_OUTPUT, "len: %d...", bcs->tx_skb->len); if (!bcs->tx_skb->len) { dev_kfree_skb_any(bcs->tx_skb); @@ -650,9 +617,7 @@ static int write_modem(struct cardstate *cs) return -EINVAL; } - /* Copy data to bulk out buffer and // FIXME copying not necessary - * transmit data - */ + /* Copy data to bulk out buffer and transmit data */ count = min(bcs->tx_skb->len, (unsigned) ucs->bulk_out_size); skb_copy_from_linear_data(bcs->tx_skb, ucs->bulk_out_buffer, count); skb_pull(bcs->tx_skb, count); @@ -663,7 +628,8 @@ static int write_modem(struct cardstate *cs) if (cs->connected) { usb_fill_bulk_urb(ucs->bulk_out_urb, ucs->udev, usb_sndbulkpipe(ucs->udev, - ucs->bulk_out_endpointAddr & 0x0f), + ucs->bulk_out_endpointAddr & + 0x0f), ucs->bulk_out_buffer, count, gigaset_write_bulk_callback, cs); ret = usb_submit_urb(ucs->bulk_out_urb, GFP_ATOMIC); @@ -679,7 +645,7 @@ static int write_modem(struct cardstate *cs) if (!bcs->tx_skb->len) { /* skb sent completely */ - gigaset_skb_sent(bcs, bcs->tx_skb); //FIXME also, when ret<0? + gigaset_skb_sent(bcs, bcs->tx_skb); gig_dbg(DEBUG_INTR, "kfree skb (Adr: %lx)!", (unsigned long) bcs->tx_skb); @@ -729,7 +695,7 @@ static int gigaset_probe(struct usb_interface *interface, dev_info(&udev->dev, "%s: Device matched ... !\n", __func__); - /* allocate memory for our device state and intialize it */ + /* allocate memory for our device state and initialize it */ cs = gigaset_initcs(driver, 1, 1, 0, cidmode, GIGASET_MODULENAME); if (!cs) return -ENODEV; @@ -742,7 +708,7 @@ static int gigaset_probe(struct usb_interface *interface, cs->dev = &interface->dev; /* save address of controller structure */ - usb_set_intfdata(interface, cs); // dev_set_drvdata(&interface->dev, cs); + usb_set_intfdata(interface, cs); endpoint = &hostif->endpoint[0].desc; @@ -776,8 +742,8 @@ static int gigaset_probe(struct usb_interface *interface, buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); ucs->rcvbuf_size = buffer_size; ucs->int_in_endpointAddr = endpoint->bEndpointAddress; - cs->inbuf[0].rcvbuf = kmalloc(buffer_size, GFP_KERNEL); - if (!cs->inbuf[0].rcvbuf) { + ucs->rcvbuf = kmalloc(buffer_size, GFP_KERNEL); + if (!ucs->rcvbuf) { dev_err(cs->dev, "Couldn't allocate rcvbuf\n"); retval = -ENOMEM; goto error; @@ -786,9 +752,9 @@ static int gigaset_probe(struct usb_interface *interface, usb_fill_int_urb(ucs->read_urb, udev, usb_rcvintpipe(udev, endpoint->bEndpointAddress & 0x0f), - cs->inbuf[0].rcvbuf, buffer_size, + ucs->rcvbuf, buffer_size, gigaset_read_int_callback, - cs->inbuf + 0, endpoint->bInterval); + cs, endpoint->bInterval); retval = usb_submit_urb(ucs->read_urb, GFP_KERNEL); if (retval) { @@ -800,9 +766,9 @@ static int gigaset_probe(struct usb_interface *interface, if (startmode == SM_LOCKED) cs->mstate = MS_LOCKED; - if (!gigaset_start(cs)) { + retval = gigaset_start(cs); + if (retval < 0) { tasklet_kill(&cs->write_tasklet); - retval = -ENODEV; //FIXME goto error; } return 0; @@ -811,11 +777,11 @@ error: usb_kill_urb(ucs->read_urb); kfree(ucs->bulk_out_buffer); usb_free_urb(ucs->bulk_out_urb); - kfree(cs->inbuf[0].rcvbuf); + kfree(ucs->rcvbuf); usb_free_urb(ucs->read_urb); usb_set_intfdata(interface, NULL); ucs->read_urb = ucs->bulk_out_urb = NULL; - cs->inbuf[0].rcvbuf = ucs->bulk_out_buffer = NULL; + ucs->rcvbuf = ucs->bulk_out_buffer = NULL; usb_put_dev(ucs->udev); ucs->udev = NULL; ucs->interface = NULL; @@ -844,10 +810,10 @@ static void gigaset_disconnect(struct usb_interface *interface) kfree(ucs->bulk_out_buffer); usb_free_urb(ucs->bulk_out_urb); - kfree(cs->inbuf[0].rcvbuf); + kfree(ucs->rcvbuf); usb_free_urb(ucs->read_urb); ucs->read_urb = ucs->bulk_out_urb = NULL; - cs->inbuf[0].rcvbuf = ucs->bulk_out_buffer = NULL; + ucs->rcvbuf = ucs->bulk_out_buffer = NULL; usb_put_dev(ucs->udev); ucs->interface = NULL; @@ -921,19 +887,21 @@ static const struct gigaset_ops ops = { gigaset_m10x_input, }; -/** - * usb_gigaset_init +/* * This function is called while kernel-module is loaded */ static int __init usb_gigaset_init(void) { int result; - /* allocate memory for our driver state and intialize it */ - if ((driver = gigaset_initdriver(GIGASET_MINOR, GIGASET_MINORS, - GIGASET_MODULENAME, GIGASET_DEVNAME, - &ops, THIS_MODULE)) == NULL) + /* allocate memory for our driver state and initialize it */ + driver = gigaset_initdriver(GIGASET_MINOR, GIGASET_MINORS, + GIGASET_MODULENAME, GIGASET_DEVNAME, + &ops, THIS_MODULE); + if (driver == NULL) { + result = -ENOMEM; goto error; + } /* register this driver with the USB subsystem */ result = usb_register(&gigaset_usb_driver); @@ -949,12 +917,10 @@ error: if (driver) gigaset_freedriver(driver); driver = NULL; - return -1; + return result; } - -/** - * usb_gigaset_exit +/* * This function is called while unloading the kernel-module */ static void __exit usb_gigaset_exit(void) |
