Use a taskqueue to handle port status changes.

Calling ucom layer directly from interrupt context make a panic.

MFC after:	1 week
This commit is contained in:
Shunsuke Akiyama 2005-01-31 13:58:10 +00:00
parent 1f0ce611b3
commit 4b6cd0347a
3 changed files with 54 additions and 2 deletions

View File

@ -94,6 +94,7 @@ __FBSDID("$FreeBSD$");
#include <sys/bus.h>
#include <sys/poll.h>
#include <sys/uio.h>
#include <sys/taskqueue.h>
#include <dev/usb/usb.h>
#include <dev/usb/usbcdc.h>
@ -165,6 +166,8 @@ struct umodem_softc {
usb_cdc_notification_t sc_notify_buf; /* Notification structure */
u_char sc_lsr; /* Local status register */
u_char sc_msr; /* Modem status register */
struct task sc_task;
};
Static void *umodem_get_desc(usbd_device_handle dev, int type, int subtype);
@ -186,6 +189,7 @@ Static int umodem_ioctl(void *, int, u_long, caddr_t, int, usb_proc_ptr );
Static int umodem_open(void *, int portno);
Static void umodem_close(void *, int portno);
Static void umodem_intr(usbd_xfer_handle, usbd_private_handle, usbd_status);
Static void umodem_notify(void *, int);
Static struct ucom_callback umodem_callback = {
umodem_get_status,
@ -415,6 +419,7 @@ USB_ATTACH(umodem)
ucom->sc_opkthdrlen = 0;
ucom->sc_callback = &umodem_callback;
TASK_INIT(&sc->sc_task, 0, umodem_notify, sc);
ucom_attach(&sc->sc_ucom);
free(devinfo, M_USBDEV);
@ -521,7 +526,8 @@ umodem_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
sc->sc_msr |= SER_DSR;
if (ISSET(mstatus, UCDC_N_SERIAL_DCD))
sc->sc_msr |= SER_DCD;
ucom_status_change(&sc->sc_ucom);
/* Deferred notifying to the ucom layer */
taskqueue_enqueue(taskqueue_swi_giant, &sc->sc_task);
break;
default:
DPRINTF(("%s: unknown notify message: %02x\n",
@ -531,6 +537,17 @@ umodem_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
}
}
Static void
umodem_notify(void *arg, int count)
{
struct umodem_softc *sc;
sc = (struct umodem_softc *)arg;
if (sc->sc_ucom.sc_dying)
return;
ucom_status_change(&sc->sc_ucom);
}
void
umodem_get_caps(usbd_device_handle dev, int *cm, int *acm)
{

View File

@ -107,6 +107,7 @@ __FBSDID("$FreeBSD$");
#include <sys/poll.h>
#include <sys/sysctl.h>
#include <sys/uio.h>
#include <sys/taskqueue.h>
#include <machine/bus.h>
@ -176,6 +177,8 @@ struct uplcom_softc {
u_char sc_msr; /* uplcom status register */
int sc_chiptype; /* Type of chip */
struct task sc_task;
};
/*
@ -203,6 +206,7 @@ Static int uplcom_ioctl(void *, int, u_long, caddr_t, int, usb_proc_ptr);
Static int uplcom_param(void *, int, struct termios *);
Static int uplcom_open(void *, int);
Static void uplcom_close(void *, int);
Static void uplcom_notify(void *, int);
struct ucom_callback uplcom_callback = {
uplcom_get_status,
@ -530,6 +534,7 @@ USB_ATTACH(uplcom)
DPRINTF(("uplcom: in = 0x%x, out = 0x%x, intr = 0x%x\n",
ucom->sc_bulkin_no, ucom->sc_bulkout_no, sc->sc_intr_number));
TASK_INIT(&sc->sc_task, 0, uplcom_notify, sc);
ucom_attach(&sc->sc_ucom);
free(devinfo, M_USBDEV);
@ -950,6 +955,19 @@ uplcom_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
sc->sc_msr |= SER_DCD;
else
sc->sc_msr &= ~SER_DCD;
/* Deferred notifying to the ucom layer */
taskqueue_enqueue(taskqueue_swi_giant, &sc->sc_task);
}
Static void
uplcom_notify(void *arg, int count)
{
struct uplcom_softc *sc;
sc = (struct uplcom_softc *)arg;
if (sc->sc_ucom.sc_dying)
return;
ucom_status_change(&sc->sc_ucom);
}

View File

@ -1,6 +1,6 @@
/* $NetBSD: usb/uvscom.c,v 1.1 2002/03/19 15:08:42 augustss Exp $ */
/*-
* Copyright (c) 2001-2002, Shunsuke Akiyama <akiyama@jp.FreeBSD.org>.
* Copyright (c) 2001-2003, 2005 Shunsuke Akiyama <akiyama@jp.FreeBSD.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -63,6 +63,7 @@ __FBSDID("$FreeBSD$");
#include <sys/proc.h>
#include <sys/poll.h>
#include <sys/sysctl.h>
#include <sys/taskqueue.h>
#include <dev/usb/usb.h>
#include <dev/usb/usbcdc.h>
@ -174,6 +175,8 @@ struct uvscom_softc {
uint16_t sc_lcr; /* Line control */
u_char sc_usr; /* unit status */
struct task sc_task;
};
/*
@ -206,6 +209,7 @@ Static int uvscom_ioctl(void *, int, u_long, caddr_t, int, usb_proc_ptr);
Static int uvscom_param(void *, int, struct termios *);
Static int uvscom_open(void *, int);
Static void uvscom_close(void *, int);
Static void uvscom_notify(void *, int);
struct ucom_callback uvscom_callback = {
uvscom_get_status,
@ -437,6 +441,7 @@ USB_ATTACH(uvscom)
DPRINTF(("uvscom: in = 0x%x out = 0x%x intr = 0x%x\n",
ucom->sc_bulkin_no, ucom->sc_bulkout_no, sc->sc_intr_number));
TASK_INIT(&sc->sc_task, 0, uvscom_notify, sc);
ucom_attach(&sc->sc_ucom);
free(devinfo, M_USBDEV);
@ -904,6 +909,18 @@ uvscom_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
if (ISSET(pstatus, UVSCOM_DCD))
SET(sc->sc_msr, SER_DCD);
/* Deferred notifying to the ucom layer */
taskqueue_enqueue(taskqueue_swi_giant, &sc->sc_task);
}
Static void
uvscom_notify(void *arg, int count)
{
struct uvscom_softc *sc;
sc = (struct uvscom_softc *)arg;
if (sc->sc_ucom.sc_dying)
return;
ucom_status_change(&sc->sc_ucom);
}