Xi%Og\vm5
return; 1v|-+p42
} [-*&ZYp
*gH]R*Q[Rt
switch (data->state) { ]UUa/ep-
case BCM203X_LOAD_MINIDRV: u ,3B[
memcpy(data->buffer, "#", 1); iH4LZ
FA*$ dwp
usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(udev, BCM203X_OUT_EP), 60^j<O
data->buffer, 1, bcm203x_complete, data); DAb/B
z.8 nYL5^}
data->state = BCM203X_SELECT_MEMORY; NH|I>vyN
g8uqW1E^
/* use workqueue to have a small delay */ x3&gB`j-
schedule_work(&data->work); enJ;#aA
break; 5h/,*p6Nje
7ivo Q
case BCM203X_SELECT_MEMORY: x7/Vf,N
usb_fill_int_urb(urb, udev, usb_rcvintpipe(udev, BCM203X_IN_EP), ]Z5m_-I
data->buffer, 32, bcm203x_complete, data, 1); |\Jnr3)
IWu=z!mO
data->state = BCM203X_CHECK_MEMORY; A9b(P[!]T:
SM8N*WdiU
if (usb_submit_urb(data->urb, GFP_ATOMIC) < 0) K bLSK
BT_ERR("Can't submit URB"); #4mRMsW5"
break; ?)-6~p 4N
]S4"JcM
case BCM203X_CHECK_MEMORY: 3GF67]
if (data->buffer[0] != '#') { :ZY%-]u7
BT_ERR("Memory select failed"); $x'jf?zs!
data->state = BCM203X_ERROR; Y
M:9m)
break; neM.M)0
} u!|_bI3
%]}JWXof
data->state = BCM203X_LOAD_FIRMWARE; G/p\MzDko
< 8'
b
case BCM203X_LOAD_FIRMWARE: /al56n
if (data->fw_sent == data->fw_size) { l%2VA
usb_fill_int_urb(urb, udev, usb_rcvintpipe(udev, BCM203X_IN_EP), pF8$83S
data->buffer, 32, bcm203x_complete, data, 1); a6n@
5kw
K%
data->state = BCM203X_CHECK_FIRMWARE; `{!A1xKZ
} else { L@GICW~
len = min_t(uint, data->fw_size - data->fw_sent, 4096); ?YR;o4
n7bVL#Sq[
usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(udev, BCM203X_OUT_EP), ((A@VcX
data->fw_data + data->fw_sent, len, bcm203x_complete, data); x
t-s"A
`15}jTi
data->fw_sent += len; bK%F_v3'
} dh`s^D6Q>
aeUgr!
if (usb_submit_urb(data->urb, GFP_ATOMIC) < 0) tcj"rV{G
BT_ERR("Can't submit URB"); !6=s{V&r1
break; _MC',p&
8*u'D@0
case BCM203X_CHECK_FIRMWARE:
)1Bz0:
if (data->buffer[0] != '.') { $a~
BT_ERR("Firmware loading failed"); E>QS^)ih
data->state = BCM203X_ERROR; -lJ|x>PG'
break; hx0 t!k(3
} f?.VVlD
EM@|^47$
data->state = BCM203X_RESET; P
2_!(FZ<l
break; [8za=B/
} |_p7vl"
} !O"2)RU1
<lFHmi$qt{
static void bcm203x_work(struct work_struct *work) \2 DED
{ e">&B]#}
struct bcm203x_data *data = 0x~+=GUN
container_of(work, struct bcm203x_data, work); [!%5(Ro_
/E<Q_/'Z
if (atomic_read(&data->shutdown)) ThX3@o
return; VgXT4gO!
zqj|$YNC
if (usb_submit_urb(data->urb, GFP_KERNEL) < 0) P
s>Y]
BT_ERR("Can't submit URB"); [,Rc&7p~R
} ^Ak?2,xB#+
#9(+)~irz`
static int bcm203x_probe(struct usb_interface *intf, const struct usb_device_id *id) ]mtiIu[
{ IrYj#,xJ
const struct firmware *firmware; ]vf_4QW=
struct usb_device *udev = interface_to_usbdev(intf); %R4 \[e
struct bcm203x_data *data; !QVhP+l'H
int size; }R+#>P
8g8eY pG
BT_DBG("intf %p id %p", intf, id); ,K}"o~z
spP[S"gI
if (intf->cur_altsetting->desc.bInterfaceNumber != 0) ?cWwt~N9
return -ENODEV; mxCneX
^E/6vG
data = devm_kzalloc(&intf->dev, sizeof(*data), GFP_KERNEL); vUbgSI
if (!data) { G!VEV3zT
BT_ERR("Can't allocate memory for data structure"); '~
B2[
return -ENOMEM; W[I[Xg&
} r(wf>w3
[H\0
'
data->udev = udev; Yz2N(g[
data->state = BCM203X_LOAD_MINIDRV; ,1 H|{ <
r Yt|[Pk
data->urb = usb_alloc_urb(0, GFP_KERNEL); wclj9&k
if (!data->urb) { `%[m%Y9h
BT_ERR("Can't allocate URB"); #7 H0I8
return -ENOMEM; >.UEs8QV
} g
\S6>LG!
"a;$uW@.6
if (request_firmware(&firmware, "BCM2033-MD.hex", &udev->dev) < 0) { =),ZZD#J
BT_ERR("Mini driver request failed"); .7
j#F
usb_free_urb(data->urb); u `w w
return -EIO; i;~.kgtq4
} U= GJuixy
5I[:.o0
BT_DBG("minidrv data %p size %zu", firmware->data, firmware->size); b&E"r*i|
pFMJG<W9,
size = max_t(uint, firmware->size, 4096); gcwJ{&
;C =d(
pY
data->buffer = kmalloc(size, GFP_KERNEL); 8)iI=,T*
if (!data->buffer) { 93Gj#Mk
BT_ERR("Can't allocate memory for mini driver"); [H!do$[>
release_firmware(firmware); /Cwwz
usb_free_urb(data->urb); $27OrXQ|
return -ENOMEM; rg[#(
} fif'ptK
F&p42!"
memcpy(data->buffer, firmware->data, firmware->size); "MzBy)4Q
;XNC+mPK
usb_fill_bulk_urb(data->urb, udev, usb_sndbulkpipe(udev, BCM203X_OUT_EP), bRFZ:hu l
data->buffer, firmware->size, bcm203x_complete, data); gZ>&cju
'%e@7Cs
release_firmware(firmware); %! Sjbh
9:%')M&Q
if (request_firmware(&firmware, "BCM2033-FW.bin", &udev->dev) < 0) { jEx8G3EL
BT_ERR("Firmware request failed"); Z! /_H($
usb_free_urb(data->urb); WUYU\J&q3
kfree(data->buffer); AWFq5YMSI
return -EIO; 7a_u=\,
} +#>nOn(B
oEZhKVyc.y
BT_DBG("firmware data %p size %zu", firmware->data, firmware->size); :Id8N~g
zGd[sjL
data->fw_data = kmemdup(firmware->data, firmware->size, GFP_KERNEL); GRj [2I7:
if (!data->fw_data) { DV?c%z`YO
BT_ERR("Can't allocate memory for firmware image"); ;x_T*} CH
release_firmware(firmware); ~|~ 2B$JeV
usb_free_urb(data->urb); 0%rE*h9+
kfree(data->buffer); 6e,IjocsB
return -ENOMEM; YJz06E1 -9
} DcRoW
oKkDG|IE
data->fw_size = firmware->size; ~.e~YI80
data->fw_sent = 0; :Eg4^,QX
ooa"Th<
release_firmware(firmware); NU.4_cixb
B;iJ$gt]
INIT_WORK(&data->work, bcm203x_work); P"Q6 wdm
4%yeEc;z
usb_set_intfdata(intf, data); IWddJb~hu
R SWw4}
/* use workqueue to have a small delay */ 'g<FL`iP
schedule_work(&data->work); g("[wqgG
c.-dwz
return 0; z6qx9x|Ij
} ^8ilUu
P
2x.rukT|
static void bcm203x_disconnect(struct usb_interface *intf) #K-O<:s=y
{ Lrt~Q:z2u
struct bcm203x_data *data = usb_get_intfdata(intf); Ly`.~t(~l
2xy{g&G
BT_DBG("intf %p", intf); H%>cpwa[7
S}/ZHo
atomic_inc(&data->shutdown); N#Nc{WU'B
cancel_work_sync(&data->work); sx[mbKj<
7O=7lQ
usb_kill_urb(data->urb); hR[_1vuIu
"5sUE!)f
usb_set_intfdata(intf, NULL); N4yQ,tG>aa
|M?VmG/6
usb_free_urb(data->urb); h!Fh@%
kfree(data->fw_data); TuwSJS7
kfree(data->buffer); iqd7
} ,0,&
L
;,KT+!H$
static struct usb_driver bcm203x_driver = { #zn`)n
.name = "bcm203x", nl-tJ.MU"
.probe = bcm203x_probe, pug;1UZ
.disconnect = bcm203x_disconnect, ,I f9w$(z
.id_table = bcm203x_table, \S?;5LacZ