Deleted Added
full compact
usb_serial.c (213872) usb_serial.c (214761)
1/* $NetBSD: ucom.c,v 1.40 2001/11/13 06:24:54 lukem Exp $ */
2
3/*-
4 * Copyright (c) 2001-2003, 2005, 2008
5 * Shunsuke Akiyama <akiyama@jp.FreeBSD.org>.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without

--- 14 unchanged lines hidden (view full) ---

23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#include <sys/cdefs.h>
1/* $NetBSD: ucom.c,v 1.40 2001/11/13 06:24:54 lukem Exp $ */
2
3/*-
4 * Copyright (c) 2001-2003, 2005, 2008
5 * Shunsuke Akiyama <akiyama@jp.FreeBSD.org>.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without

--- 14 unchanged lines hidden (view full) ---

23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#include <sys/cdefs.h>
31__FBSDID("$FreeBSD: head/sys/dev/usb/serial/usb_serial.c 213872 2010-10-14 21:45:41Z hselasky $");
31__FBSDID("$FreeBSD: head/sys/dev/usb/serial/usb_serial.c 214761 2010-11-03 21:50:49Z n_hibma $");
32
33/*-
34 * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
35 * All rights reserved.
36 *
37 * This code is derived from software contributed to The NetBSD Foundation
38 * by Lennart Augustsson (lennart@augustsson.net) at
39 * Carlstedt Research & Technology.

--- 78 unchanged lines hidden (view full) ---

118
119static unsigned int ucom_cons_rx_low = 0;
120static unsigned int ucom_cons_rx_high = 0;
121
122static unsigned int ucom_cons_tx_low = 0;
123static unsigned int ucom_cons_tx_high = 0;
124
125static int ucom_cons_unit = -1;
32
33/*-
34 * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
35 * All rights reserved.
36 *
37 * This code is derived from software contributed to The NetBSD Foundation
38 * by Lennart Augustsson (lennart@augustsson.net) at
39 * Carlstedt Research & Technology.

--- 78 unchanged lines hidden (view full) ---

118
119static unsigned int ucom_cons_rx_low = 0;
120static unsigned int ucom_cons_rx_high = 0;
121
122static unsigned int ucom_cons_tx_low = 0;
123static unsigned int ucom_cons_tx_high = 0;
124
125static int ucom_cons_unit = -1;
126static int ucom_cons_subunit = 0;
126static int ucom_cons_baud = 9600;
127static struct ucom_softc *ucom_cons_softc = NULL;
128
129TUNABLE_INT("hw.usb.ucom.cons_unit", &ucom_cons_unit);
130SYSCTL_INT(_hw_usb_ucom, OID_AUTO, cons_unit, CTLFLAG_RW,
131 &ucom_cons_unit, 0, "console unit number");
127static int ucom_cons_baud = 9600;
128static struct ucom_softc *ucom_cons_softc = NULL;
129
130TUNABLE_INT("hw.usb.ucom.cons_unit", &ucom_cons_unit);
131SYSCTL_INT(_hw_usb_ucom, OID_AUTO, cons_unit, CTLFLAG_RW,
132 &ucom_cons_unit, 0, "console unit number");
132
133TUNABLE_INT("hw.usb.ucom.cons_subunit", &ucom_cons_subunit);
134SYSCTL_INT(_hw_usb_ucom, OID_AUTO, cons_subunit, CTLFLAG_RW,
135 &ucom_cons_subunit, 0, "console subunit number");
133TUNABLE_INT("hw.usb.ucom.cons_baud", &ucom_cons_baud);
134SYSCTL_INT(_hw_usb_ucom, OID_AUTO, cons_baud, CTLFLAG_RW,
135 &ucom_cons_baud, 0, "console baud rate");
136
137static usb_proc_callback_t ucom_cfg_start_transfers;
138static usb_proc_callback_t ucom_cfg_open;
139static usb_proc_callback_t ucom_cfg_close;
140static usb_proc_callback_t ucom_cfg_line_state;
141static usb_proc_callback_t ucom_cfg_status_change;
142static usb_proc_callback_t ucom_cfg_param;
143
136TUNABLE_INT("hw.usb.ucom.cons_baud", &ucom_cons_baud);
137SYSCTL_INT(_hw_usb_ucom, OID_AUTO, cons_baud, CTLFLAG_RW,
138 &ucom_cons_baud, 0, "console baud rate");
139
140static usb_proc_callback_t ucom_cfg_start_transfers;
141static usb_proc_callback_t ucom_cfg_open;
142static usb_proc_callback_t ucom_cfg_close;
143static usb_proc_callback_t ucom_cfg_line_state;
144static usb_proc_callback_t ucom_cfg_status_change;
145static usb_proc_callback_t ucom_cfg_param;
146
144static uint8_t ucom_units_alloc(uint32_t, uint32_t *);
145static void ucom_units_free(uint32_t, uint32_t);
146static int ucom_attach_tty(struct ucom_softc *, uint32_t);
147static int ucom_unit_alloc(void);
148static void ucom_unit_free(int);
149static int ucom_attach_tty(struct ucom_super_softc *, struct ucom_softc *);
147static void ucom_detach_tty(struct ucom_softc *);
148static void ucom_queue_command(struct ucom_softc *,
149 usb_proc_callback_t *, struct termios *pt,
150 struct usb_proc_msg *t0, struct usb_proc_msg *t1);
151static void ucom_shutdown(struct ucom_softc *);
152static void ucom_ring(struct ucom_softc *, uint8_t);
153static void ucom_break(struct ucom_softc *, uint8_t);
154static void ucom_dtr(struct ucom_softc *, uint8_t);

--- 16 unchanged lines hidden (view full) ---

171 .tsw_param = ucom_param,
172 .tsw_modem = ucom_modem,
173 .tsw_free = ucom_free,
174};
175
176MODULE_DEPEND(ucom, usb, 1, 1, 1);
177MODULE_VERSION(ucom, 1);
178
150static void ucom_detach_tty(struct ucom_softc *);
151static void ucom_queue_command(struct ucom_softc *,
152 usb_proc_callback_t *, struct termios *pt,
153 struct usb_proc_msg *t0, struct usb_proc_msg *t1);
154static void ucom_shutdown(struct ucom_softc *);
155static void ucom_ring(struct ucom_softc *, uint8_t);
156static void ucom_break(struct ucom_softc *, uint8_t);
157static void ucom_dtr(struct ucom_softc *, uint8_t);

--- 16 unchanged lines hidden (view full) ---

174 .tsw_param = ucom_param,
175 .tsw_modem = ucom_modem,
176 .tsw_free = ucom_free,
177};
178
179MODULE_DEPEND(ucom, usb, 1, 1, 1);
180MODULE_VERSION(ucom, 1);
181
179#define UCOM_UNIT_MAX 0x200 /* exclusive */
180#define UCOM_SUB_UNIT_MAX 0x100 /* exclusive */
182#define UCOM_UNIT_MAX 128 /* limits size of ucom_bitmap */
181
182static uint8_t ucom_bitmap[(UCOM_UNIT_MAX + 7) / 8];
183static struct mtx ucom_bitmap_mtx;
184MTX_SYSINIT(ucom_bitmap_mtx, &ucom_bitmap_mtx, "ucom bitmap", MTX_DEF);
185
183
184static uint8_t ucom_bitmap[(UCOM_UNIT_MAX + 7) / 8];
185static struct mtx ucom_bitmap_mtx;
186MTX_SYSINIT(ucom_bitmap_mtx, &ucom_bitmap_mtx, "ucom bitmap", MTX_DEF);
187
186static uint8_t
187ucom_units_alloc(uint32_t sub_units, uint32_t *p_root_unit)
188/*
189 * Mark a unit number (the X in cuaUX) as in use.
190 *
191 * Note that devices using a different naming scheme (see ucom_tty_name()
192 * callback) still use this unit allocation.
193 */
194static int
195ucom_unit_alloc(void)
188{
196{
189 uint32_t n;
190 uint32_t o;
191 uint32_t x;
192 uint32_t max = UCOM_UNIT_MAX - (UCOM_UNIT_MAX % sub_units);
193 uint8_t error = 1;
197 int unit;
194
195 mtx_lock(&ucom_bitmap_mtx);
196
198
199 mtx_lock(&ucom_bitmap_mtx);
200
197 for (n = 0; n < max; n += sub_units) {
201 for (unit = 0; unit < UCOM_UNIT_MAX; unit++)
202 if ((ucom_bitmap[unit / 8] & (1 << (unit % 8))) == 0)
203 break;
198
204
199 /* check for free consecutive bits */
200
201 for (o = 0; o < sub_units; o++) {
202
203 x = n + o;
204
205 if (ucom_bitmap[x / 8] & (1 << (x % 8))) {
206 goto skip;
207 }
208 }
209
210 /* allocate */
211
212 for (o = 0; o < sub_units; o++) {
213
214 x = n + o;
215
216 ucom_bitmap[x / 8] |= (1 << (x % 8));
217 }
218
219 error = 0;
220
221 break;
222
223skip: ;
224 }
225
226 mtx_unlock(&ucom_bitmap_mtx);
227
205 mtx_unlock(&ucom_bitmap_mtx);
206
228 /*
229 * Always set the variable pointed to by "p_root_unit" so that
230 * the compiler does not think that it is used uninitialised:
231 */
232 *p_root_unit = n;
233
234 return (error);
207 if (unit == UCOM_UNIT_MAX)
208 return -1;
209 else
210 return unit;
235}
236
211}
212
213/*
214 * Mark the unit number as not in use.
215 */
237static void
216static void
238ucom_units_free(uint32_t root_unit, uint32_t sub_units)
217ucom_unit_free(int unit)
239{
218{
240 uint32_t x;
241
242 mtx_lock(&ucom_bitmap_mtx);
243
219 mtx_lock(&ucom_bitmap_mtx);
220
244 while (sub_units--) {
245 x = root_unit + sub_units;
246 ucom_bitmap[x / 8] &= ~(1 << (x % 8));
247 }
221 ucom_bitmap[unit / 8] &= ~(1 << (unit % 8));
248
249 mtx_unlock(&ucom_bitmap_mtx);
250}
251
252/*
222
223 mtx_unlock(&ucom_bitmap_mtx);
224}
225
226/*
253 * "N" sub_units are setup at a time. All sub-units will
254 * be given sequential unit numbers. The number of
255 * sub-units can be used to differentiate among
256 * different types of devices.
227 * Setup a group of one or more serial ports.
257 *
258 * The mutex pointed to by "mtx" is applied before all
259 * callbacks are called back. Also "mtx" must be applied
260 * before calling into the ucom-layer!
261 */
262int
263ucom_attach(struct ucom_super_softc *ssc, struct ucom_softc *sc,
228 *
229 * The mutex pointed to by "mtx" is applied before all
230 * callbacks are called back. Also "mtx" must be applied
231 * before calling into the ucom-layer!
232 */
233int
234ucom_attach(struct ucom_super_softc *ssc, struct ucom_softc *sc,
264 uint32_t sub_units, void *parent,
235 uint32_t subunits, void *parent,
265 const struct ucom_callback *callback, struct mtx *mtx)
266{
236 const struct ucom_callback *callback, struct mtx *mtx)
237{
267 uint32_t n;
268 uint32_t root_unit;
238 uint32_t subunit;
269 int error = 0;
270
271 if ((sc == NULL) ||
239 int error = 0;
240
241 if ((sc == NULL) ||
272 (sub_units == 0) ||
273 (sub_units > UCOM_SUB_UNIT_MAX) ||
242 (subunits == 0) ||
274 (callback == NULL)) {
275 return (EINVAL);
276 }
277
243 (callback == NULL)) {
244 return (EINVAL);
245 }
246
278 /* XXX unit management does not really belong here */
279 if (ucom_units_alloc(sub_units, &root_unit)) {
247 ssc->sc_unit = ucom_unit_alloc();
248 if (ssc->sc_unit == -1)
280 return (ENOMEM);
249 return (ENOMEM);
281 }
282
283 error = usb_proc_create(&ssc->sc_tq, mtx, "ucom", USB_PRI_MED);
284 if (error) {
250
251 error = usb_proc_create(&ssc->sc_tq, mtx, "ucom", USB_PRI_MED);
252 if (error) {
285 ucom_units_free(root_unit, sub_units);
253 ucom_unit_free(ssc->sc_unit);
286 return (error);
287 }
254 return (error);
255 }
256 ssc->sc_subunits = subunits;
288
257
289 for (n = 0; n != sub_units; n++, sc++) {
290 sc->sc_unit = root_unit + n;
291 sc->sc_local_unit = n;
292 sc->sc_super = ssc;
293 sc->sc_mtx = mtx;
294 sc->sc_parent = parent;
295 sc->sc_callback = callback;
258 for (subunit = 0; subunit != ssc->sc_subunits; subunit++) {
259 sc[subunit].sc_subunit = subunit;
260 sc[subunit].sc_super = ssc;
261 sc[subunit].sc_mtx = mtx;
262 sc[subunit].sc_parent = parent;
263 sc[subunit].sc_callback = callback;
296
264
297 error = ucom_attach_tty(sc, sub_units);
265 error = ucom_attach_tty(ssc, &sc[subunit]);
298 if (error) {
266 if (error) {
299 ucom_detach(ssc, sc - n, n);
300 ucom_units_free(root_unit + n, sub_units - n);
267 ucom_detach(ssc, &sc[0]);
301 return (error);
302 }
268 return (error);
269 }
303 sc->sc_flag |= UCOM_FLAG_ATTACHED;
270 sc[subunit].sc_flag |= UCOM_FLAG_ATTACHED;
304 }
271 }
272
273 DPRINTF("tp = %p, unit = %d, subunits = %d, device name subunit 0 = %s\n",
274 sc->sc_tty, ssc->sc_unit, ssc->sc_subunits, sc[0].sc_devname);
275
305 return (0);
306}
307
308/*
309 * NOTE: the following function will do nothing if
310 * the structure pointed to by "ssc" and "sc" is zero.
311 */
312void
276 return (0);
277}
278
279/*
280 * NOTE: the following function will do nothing if
281 * the structure pointed to by "ssc" and "sc" is zero.
282 */
283void
313ucom_detach(struct ucom_super_softc *ssc, struct ucom_softc *sc,
314 uint32_t sub_units)
284ucom_detach(struct ucom_super_softc *ssc, struct ucom_softc *sc)
315{
285{
316 uint32_t n;
286 uint32_t subunit;
317
318 usb_proc_drain(&ssc->sc_tq);
319
287
288 usb_proc_drain(&ssc->sc_tq);
289
320 for (n = 0; n != sub_units; n++, sc++) {
321 if (sc->sc_flag & UCOM_FLAG_ATTACHED) {
290 for (subunit = 0; subunit <= ssc->sc_subunits; subunit++) {
291 if (sc[subunit].sc_flag & UCOM_FLAG_ATTACHED) {
322
292
323 ucom_detach_tty(sc);
293 ucom_detach_tty(&sc[subunit]);
324
294
325 ucom_units_free(sc->sc_unit, 1);
326
327 /* avoid duplicate detach: */
328 sc->sc_flag &= ~UCOM_FLAG_ATTACHED;
295 /* avoid duplicate detach */
296 sc[subunit].sc_flag &= ~UCOM_FLAG_ATTACHED;
329 }
330 }
297 }
298 }
299 ucom_unit_free(ssc->sc_unit);
331 usb_proc_free(&ssc->sc_tq);
332}
333
334static int
300 usb_proc_free(&ssc->sc_tq);
301}
302
303static int
335ucom_attach_tty(struct ucom_softc *sc, uint32_t sub_units)
304ucom_attach_tty(struct ucom_super_softc *ssc, struct ucom_softc *sc)
336{
337 struct tty *tp;
305{
306 struct tty *tp;
338 int error = 0;
339 char buf[32]; /* temporary TTY device name buffer */
307 char buf[10]; /* temporary TTY device name buffer */
340
341 tp = tty_alloc_mutex(&ucom_class, sc, sc->sc_mtx);
308
309 tp = tty_alloc_mutex(&ucom_class, sc, sc->sc_mtx);
342 if (tp == NULL) {
343 error = ENOMEM;
344 goto done;
345 }
346 DPRINTF("tp = %p, unit = %d\n", tp, sc->sc_unit);
310 if (tp == NULL)
311 return (ENOMEM);
347
312
348 buf[0] = 0; /* set some default value */
349
350 /* Check if the client has a custom TTY name */
313 /* Check if the client has a custom TTY name */
314 buf[0] = '\0';
351 if (sc->sc_callback->ucom_tty_name) {
352 sc->sc_callback->ucom_tty_name(sc, buf,
315 if (sc->sc_callback->ucom_tty_name) {
316 sc->sc_callback->ucom_tty_name(sc, buf,
353 sizeof(buf), sc->sc_local_unit);
317 sizeof(buf), ssc->sc_unit, sc->sc_subunit);
354 }
355 if (buf[0] == 0) {
356 /* Use default TTY name */
318 }
319 if (buf[0] == 0) {
320 /* Use default TTY name */
357 if (sub_units > 1) {
321 if (ssc->sc_subunits > 1) {
358 /* multiple modems in one */
322 /* multiple modems in one */
359 if (snprintf(buf, sizeof(buf), "U%u.%u",
360 sc->sc_unit - sc->sc_local_unit,
361 sc->sc_local_unit)) {
362 /* ignore */
363 }
323 snprintf(buf, sizeof(buf), "U%u.%u",
324 ssc->sc_unit, sc->sc_subunit);
364 } else {
365 /* single modem */
325 } else {
326 /* single modem */
366 if (snprintf(buf, sizeof(buf), "U%u", sc->sc_unit)) {
367 /* ignore */
368 }
327 snprintf(buf, sizeof(buf), "U%u", ssc->sc_unit);
369 }
370 }
371 tty_makedev(tp, NULL, "%s", buf);
372
373 sc->sc_tty = tp;
374
375 DPRINTF("ttycreate: %s\n", buf);
376 cv_init(&sc->sc_cv, "ucom");
377
378 /* Check if this device should be a console */
379 if ((ucom_cons_softc == NULL) &&
328 }
329 }
330 tty_makedev(tp, NULL, "%s", buf);
331
332 sc->sc_tty = tp;
333
334 DPRINTF("ttycreate: %s\n", buf);
335 cv_init(&sc->sc_cv, "ucom");
336
337 /* Check if this device should be a console */
338 if ((ucom_cons_softc == NULL) &&
380 (sc->sc_unit == ucom_cons_unit)) {
381
339 (ssc->sc_unit == ucom_cons_unit) &&
340 (sc->sc_subunit == ucom_cons_subunit)) {
382 struct termios t;
383
341 struct termios t;
342
343 DPRINTF("unit %d subunit %d is console", ssc->sc_unit, sc->sc_subunit);
344
384 ucom_cons_softc = sc;
385
386 memset(&t, 0, sizeof(t));
387 t.c_ispeed = ucom_cons_baud;
388 t.c_ospeed = t.c_ispeed;
389 t.c_cflag = CS8;
390
391 mtx_lock(ucom_cons_softc->sc_mtx);
392 ucom_cons_rx_low = 0;
393 ucom_cons_rx_high = 0;
394 ucom_cons_tx_low = 0;
395 ucom_cons_tx_high = 0;
396 sc->sc_flag |= UCOM_FLAG_CONSOLE;
397 ucom_open(ucom_cons_softc->sc_tty);
398 ucom_param(ucom_cons_softc->sc_tty, &t);
399 mtx_unlock(ucom_cons_softc->sc_mtx);
400 }
345 ucom_cons_softc = sc;
346
347 memset(&t, 0, sizeof(t));
348 t.c_ispeed = ucom_cons_baud;
349 t.c_ospeed = t.c_ispeed;
350 t.c_cflag = CS8;
351
352 mtx_lock(ucom_cons_softc->sc_mtx);
353 ucom_cons_rx_low = 0;
354 ucom_cons_rx_high = 0;
355 ucom_cons_tx_low = 0;
356 ucom_cons_tx_high = 0;
357 sc->sc_flag |= UCOM_FLAG_CONSOLE;
358 ucom_open(ucom_cons_softc->sc_tty);
359 ucom_param(ucom_cons_softc->sc_tty, &t);
360 mtx_unlock(ucom_cons_softc->sc_mtx);
361 }
401done:
402 return (error);
362
363 return (0);
403}
404
405static void
406ucom_detach_tty(struct ucom_softc *sc)
407{
408 struct tty *tp = sc->sc_tty;
409
410 DPRINTF("sc = %p, tp = %p\n", sc, sc->sc_tty);
411
412 if (sc->sc_flag & UCOM_FLAG_CONSOLE) {
413 mtx_lock(ucom_cons_softc->sc_mtx);
414 ucom_close(ucom_cons_softc->sc_tty);
364}
365
366static void
367ucom_detach_tty(struct ucom_softc *sc)
368{
369 struct tty *tp = sc->sc_tty;
370
371 DPRINTF("sc = %p, tp = %p\n", sc, sc->sc_tty);
372
373 if (sc->sc_flag & UCOM_FLAG_CONSOLE) {
374 mtx_lock(ucom_cons_softc->sc_mtx);
375 ucom_close(ucom_cons_softc->sc_tty);
376 sc->sc_flag &= ~UCOM_FLAG_CONSOLE;
415 mtx_unlock(ucom_cons_softc->sc_mtx);
416 ucom_cons_softc = NULL;
417 }
418
419 /* the config thread has been stopped when we get here */
420
421 mtx_lock(sc->sc_mtx);
422 sc->sc_flag |= UCOM_FLAG_GONE;

--- 1034 unchanged lines hidden ---
377 mtx_unlock(ucom_cons_softc->sc_mtx);
378 ucom_cons_softc = NULL;
379 }
380
381 /* the config thread has been stopped when we get here */
382
383 mtx_lock(sc->sc_mtx);
384 sc->sc_flag |= UCOM_FLAG_GONE;

--- 1034 unchanged lines hidden ---